Compare commits

...

192 Commits

Author SHA1 Message Date
jf-cbd
37ed4b1294 Remove console.log 2025-12-23 18:36:06 +01:00
jf-cbd
35d3194e6c Proposition that allows to include modules from ar array. Works both on usual page + ajax page 2025-12-23 14:55:00 +01:00
Benjamin Dalsass
a627f8a471 form as custom element 2025-12-23 09:03:01 +01:00
Benjamin Dalsass
7713a113cc dashboard editor 2025-12-22 08:25:23 +01:00
Benjamin Dalsass
1a93b303e3 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-12-22 07:54:18 +01:00
Benjamin Dalsass
0dc32b3b13 dashboard editor 2025-12-22 07:53:09 +01:00
Eric Espie
048b1a94b1 N°8772 - Form compiler for collections 2025-12-19 10:56:27 +01:00
Eric Espie
d21b1eb151 N°8772 - Form compiler for collections 2025-12-19 10:23:42 +01:00
Eric Espie
d17c3aabbb Fix false positive in tests 2025-12-19 09:56:18 +01:00
Eric Espie
f010476923 🎨 Add automatic class return type to MetaModel::GetObject() and MetaModel::NewObject() 2025-12-18 17:24:20 +01:00
Eric Espie
49e58692e3 🎨 Add automatic class return type to MetaModel::GetObject() and MetaModel::NewObject() 2025-12-18 09:58:54 +01:00
Benjamin Dalsass
fb3cbcd779 form for dashboard 2025-12-17 16:36:05 +01:00
Eric Espie
c898df461f N°8772 - Added themes extensibility to controller 2025-12-17 15:51:24 +01:00
Eric Espie
e50109a898 N°8772 - Added DashletHeaderDynamic 2025-12-16 17:13:05 +01:00
Eric Espie
c6589b07f1 N°8772 - Form compiler for classes 2025-12-16 16:52:46 +01:00
Eric Espie
bd20818b66 N°8772 - cache now accept subdirectories 2025-12-16 15:41:55 +01:00
Eric Espie
b653236e86 N°8772 - cache fix 2025-12-16 11:14:39 +01:00
Eric Espie
75afd3ba46 N°8772 - compilation of choices from inputs 2025-12-16 11:03:52 +01:00
Eric Espie
2530d59e08 N°8772 - compilation of choices values 2025-12-15 17:15:07 +01:00
Eric Espie
a77e54c8cb N°8772 - PropertyTrees definition in DataModel 2025-12-15 16:19:22 +01:00
Eric Espie
eff59a93fd N°8772 - CI 2025-12-11 16:00:55 +01:00
Eric Espie
fdc958a734 N°8772 - Compiler: Expressions in input 2025-12-11 15:57:53 +01:00
Eric Espie
2b8de85af8 N°8772 - Compiler: Add errors check 2025-12-11 14:10:50 +01:00
Eric Espie
41d15f1b33 N°8772 - Compiler: Add errors check 2025-12-11 12:16:14 +01:00
Eric Espie
94fed54529 N°8772 - Compiler: add relevance conditions (with test fail) 2025-12-11 10:56:44 +01:00
Benjamin Dalsass
5352047ce4 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-12-11 08:12:27 +01:00
Benjamin Dalsass
2f36846d87 io array option 2025-12-11 08:09:47 +01:00
Eric Espie
49ff9378aa N°8772 - Compiler: add dynamic bindings 2025-12-10 18:07:39 +01:00
Eric Espie
4d7183e067 N°8772 - Compiler: add static inputs 2025-12-10 17:53:31 +01:00
Eric Espie
c40e7ab10e N°8772 - test driven compiler wip 2025-12-10 16:21:31 +01:00
Benjamin Dalsass
090925e28b collections 2025-12-10 08:53:34 +01:00
Benjamin Dalsass
9543624a0d collections 2025-12-08 10:03:34 +01:00
Eric Espie
0d3f7c5f07 N°8772 - test driven compiler wip 2025-12-05 16:53:02 +01:00
Eric Espie
8374d12869 N°8772 - removed use and set back full ns 2025-12-05 14:31:37 +01:00
Eric Espie
9c00ea2bbc N°8772 - fix tests 2025-12-05 13:58:10 +01:00
Eric Espie
be54bd5602 N°8772 - add &debug in request 2025-12-05 11:51:35 +01:00
Eric Espie
b315b97e9e N°8772 - "generic" form controller wip 2025-12-04 17:06:41 +01:00
Benjamin Dalsass
1fe6103d4f Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-12-04 15:28:04 +01:00
Benjamin Dalsass
3503805fe1 form input 2025-12-04 15:25:52 +01:00
Eric Espie
e092f87ae9 N°8772 - "generic" form controller 2025-12-04 14:57:28 +01:00
Eric Espie
af8fb733fb N°8772 - "generic" form controller 2025-12-04 14:56:12 +01:00
Eric Espie
b9591b05d8 N°8772 - "generic" form controller 2025-12-04 14:53:58 +01:00
Eric Espie
ee762b91c1 N°8772 - form controller 2025-12-04 14:23:45 +01:00
Eric Espie
ba1d62a147 N°8772 - form controller 2025-12-04 12:10:04 +01:00
Eric Espie
4349303a78 N°8772 - Fix broken cache 2025-12-04 10:49:20 +01:00
Eric Espie
4e6c12b903 N°8772 - XML description wip 2025-12-04 10:40:20 +01:00
Eric Espie
099b996c9a N°8772 - XML description wip 2025-12-04 10:01:09 +01:00
Eric Espie
5295dec868 N°8772 - XML description wip 2025-12-04 09:29:24 +01:00
Benjamin Dalsass
9c540b6227 form collection 2025-12-04 07:15:37 +01:00
Benjamin Dalsass
842bbcee9d form type correction 2025-12-04 06:52:37 +01:00
Benjamin Dalsass
4620710f5a collections 2025-12-03 17:47:22 +01:00
jf-cbd
b1129f19d7 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-12-02 16:50:14 +01:00
jf-cbd
d8c0cd7f21 With form in modal 2025-12-02 16:38:11 +01:00
Benjamin Dalsass
8f8a0e2672 validator component 2025-12-02 15:03:26 +01:00
Eric Espie
3d8e429c2b N°8772 - XML description traduction to PHP wip 2025-12-01 16:34:10 +01:00
Eric Espie
54aaf55a92 N°8772 - XML description traduction to PHP wip 2025-12-01 14:28:45 +01:00
Eric Espie
a88f33575d N°8772 - xml description wip 2025-12-01 08:54:49 +01:00
Benjamin Dalsass
e790929cbe validator component 2025-12-01 08:08:58 +01:00
Benjamin Dalsass
81f056a91c validator component 2025-12-01 07:58:28 +01:00
Benjamin Dalsass
06e5c80786 test and corrections 2025-11-27 16:51:46 +01:00
Benjamin Dalsass
e67fcbcfdc test and corrections 2025-11-27 16:50:47 +01:00
Eric Espie
8401aa1aec 🎨 PHP CS Fixer 2025-11-27 11:45:38 +01:00
Eric Espie
8f39e69002 autoload 2025-11-27 11:45:12 +01:00
Eric Espie
1e859ef890 🎨 PHP CS Fixer 2025-11-27 11:02:15 +01:00
Benjamin Dalsass
b8a093e625 test and corrections 2025-11-27 10:58:21 +01:00
Eric Espie
d0a2af44ac N°8772 - new LabelFormBlock and xml description wip 2025-11-27 10:23:51 +01:00
jf-cbd
827250357e Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-11-26 18:04:08 +01:00
jf-cbd
6aabed3063 Add default value for max_items_selected 2025-11-26 18:03:26 +01:00
Eric Espie
041ee2af95 N°8772 - exceptions 2025-11-26 12:33:17 +01:00
Eric Espie
72c5cbfedf N°8772 - FormBlock tests 2025-11-26 12:25:22 +01:00
jf-cbd
a0f28f725c OK for Tom Select 2025-11-26 12:04:08 +01:00
jf-cbd
02650f8cf7 WIP Tom Select options 2025-11-26 12:04:08 +01:00
Eric Espie
91958646d2 🎨 PHP CS Fixer 2025-11-26 10:57:52 +01:00
Benjamin Dalsass
87ca11b771 change turbo for form errors 2025-11-26 10:35:26 +01:00
Eric Espie
852238a110 N°8772 - OQL exceptions 2025-11-26 09:34:21 +01:00
Eric Espie
8e3d132714 🎨 PHP CS Fixer 2025-11-25 17:23:29 +01:00
Eric Espie
7a515d04dd N°8772 - exceptions 2025-11-25 17:08:41 +01:00
Benjamin Dalsass
7a67267c7d wip cleaning and other stuff 2025-11-25 10:59:27 +01:00
Benjamin Dalsass
10ac497a18 Update expression blocks 2025-11-25 08:58:14 +01:00
Benjamin Dalsass
283ecb6e67 Remove empty tests files 2025-11-25 08:52:40 +01:00
Benjamin Dalsass
33e8f9c3ae Remove string to bool converter 2025-11-25 08:49:03 +01:00
Eric Espie
039beb4c07 🎨 PHP CS Fixer 2025-11-24 17:36:57 +01:00
Eric Espie
f2a5559eea N°8772 - Removed RawFormat and OUTPUT_VALUE 2025-11-24 16:56:20 +01:00
Benjamin Dalsass
ce53487093 Quick and dirty patch TomSelect CSS style 2025-11-24 13:51:50 +01:00
Benjamin Dalsass
dd4eb9b9f0 OQLToCLassConverter class conversion 2025-11-24 13:50:51 +01:00
Eric Espie
a19472cfd1 🎨 N°8772 - CS Fixer 2025-11-20 10:55:10 +01:00
Eric Espie
7b29d562c8 N°8772 - wip 2025-11-20 10:31:18 +01:00
Eric Espie
3e471edefd 🎨 N°8772 - Moved DI under Service 2025-11-19 15:27:18 +01:00
Eric Espie
bd44f971e4 🎨 N°8772 - CS Fixer 2025-11-19 14:49:20 +01:00
Eric Espie
65bd6d9fd0 Add ModelReflection Service as dependency injection + tests 2025-11-19 14:42:32 +01:00
jf-cbd
6678689b77 Fix wrong path for turbo 2025-11-19 11:04:36 +01:00
jf-cbd
8f05c2bcba Fix CI error (cf. 2651) 2025-11-19 10:52:33 +01:00
jf-cbd
4169e10eec Fix wrong path for turbo 2025-11-19 10:49:01 +01:00
Eric Espie
e95ce21188 Add sAPPROOTURL to the data of the twig 2025-11-19 10:06:16 +01:00
Eric Espie
24d78df21d 🎨 N°8772 - CS Fixer 2025-11-19 09:21:34 +01:00
Eric Espie
546912ad77 N°8772 - 2025-11-18 18:08:50 +01:00
jf-cbd
f93926528f Add Tom-Select lib 2025-11-18 17:18:46 +01:00
Eric Espie
0cb7c7359f N°8772 - AbstractFormIO tests 2025-11-18 16:45:11 +01:00
Eric Espie
7c0f454936 Runtime Model Reflection & namespace 2025-11-18 15:36:22 +01:00
Eric Espie
11973d61ec 🎨 CS Fixer 2025-11-18 14:52:10 +01:00
Eric Espie
e08835c1a2 N°8772 - AbstractFormIO tests 2025-11-18 14:00:41 +01:00
Eric Espie
8ecb36b1fe N°8772 - FormBinding tests 2025-11-18 11:24:05 +01:00
Eric Espie
6a4ed98299 Merge remote-tracking branch 'origin/develop' into feature/8772_form_dependencies_manager 2025-11-18 09:54:29 +01:00
Eric Espie
2a8ed931e9 N°8772 - AbstractFormIO and FormBinding tests 2025-11-18 09:25:37 +01:00
Eric Espie
07a61d5f0d N°8772 - AbstractFormIO and FormBinding tests 2025-11-17 17:26:47 +01:00
Eric Espie
047c820466 N°8772 - AbstractFormIO and FormBinding tests 2025-11-17 17:26:12 +01:00
Benjamin Dalsass
753d0acce4 N°8772 - dynamic form 2025-11-17 14:51:11 +01:00
Eric Espie
51ebbc4274 N°8772 - Refactor 2025-11-14 16:42:42 +01:00
Eric Espie
3085023267 N°8772 - Error message 2025-11-14 16:24:18 +01:00
Eric Espie
e02fc9cb44 Merge dicos... 2025-11-14 16:14:34 +01:00
Eric Espie
ea95ae60a6 Merge remote-tracking branch 'origin/develop' into feature/8772_form_dependencies_manager 2025-11-14 16:08:37 +01:00
Eric Espie
b9d905ad1b N°8772 - refactor 2025-11-14 15:57:17 +01:00
Eric Espie
5b114285cc N°8772 - Error message 2025-11-14 15:39:16 +01:00
Eric Espie
b34566076e N°8772 - Form Expressions using iTop Expressions 2025-11-14 15:33:47 +01:00
Benjamin Dalsass
750b2b9cfa Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-11-14 14:32:56 +01:00
Benjamin Dalsass
bdde63a39c N°8772 - dynamic form 2025-11-14 14:30:50 +01:00
Eric Espie
891df6ab1c N°8772 - Expressions inputs are now :input instead of [[input]] (and quotes are added automatically) 2025-11-14 14:05:22 +01:00
Benjamin Dalsass
dc1ce2dc64 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager
# Conflicts:
#	lib/composer/autoload_classmap.php
#	lib/composer/autoload_static.php
#	sources/Forms/Block/Base/ChoiceFormBlock.php
#	sources/Forms/IO/Format/StringIOFormat.php
2025-11-14 10:53:42 +01:00
Benjamin Dalsass
e5058fb8f7 N°8772 - dynamic form 2025-11-14 10:50:57 +01:00
Eric Espie
f68082da96 N°8772 - Dashlet group by 2025-11-13 17:10:39 +01:00
jf-cbd
7733f13d14 Add Tom-Select lib 2025-11-13 16:43:49 +01:00
Eric Espie
cef8fbc859 N°8772 - Dashlet group by 2025-11-13 16:42:04 +01:00
Eric Espie
36d49d3550 N°8772 - wip 2025-11-13 15:02:09 +01:00
Eric Espie
c2ec3a9f02 N°8772 - remove unused class 2025-11-13 09:36:36 +01:00
Benjamin Dalsass
4d159ea3f1 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-11-12 17:11:29 +01:00
Benjamin Dalsass
5cacfcb754 N°8772 - dynamic form 2025-11-12 17:09:40 +01:00
Eric Espie
101b1b217e N°8772 - remove debug if not wanted like in config edition 2025-11-12 14:23:19 +01:00
Eric Espie
5af8adf7ce N°8772 - fix debug display 2025-11-12 13:07:37 +01:00
Benjamin Dalsass
3d2485a004 N°8772 - dynamic form 2025-11-12 09:33:29 +01:00
Benjamin Dalsass
cbb0e2ef7e N°8772 - dynamic form 2025-11-12 08:33:28 +01:00
Benjamin Dalsass
7095e5e959 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-11-12 08:24:04 +01:00
Benjamin Dalsass
7fd27913f4 N°8772 - dynamic form 2025-11-12 08:20:17 +01:00
Eric Espie
cfdf4121d3 N°8772 - Dynamic debug and error 2025-11-07 11:24:31 +01:00
Benjamin Dalsass
a448f668bc N°8772 - dynamic form 2025-11-07 11:00:15 +01:00
Eric Espie
b6ec29c6ec N°8772 - ExpressionFormBlock WIP 2025-11-06 17:12:25 +01:00
Eric Espie
03c37f2021 N°8772 - Fix IO tests 2025-11-05 16:54:18 +01:00
Benjamin Dalsass
5b7a1ee44f N°8772 - dynamic form 2025-11-05 15:52:23 +01:00
Eric Espie
9ea546ebf6 N°8772 - Turbo + Collections WIP 2025-11-05 11:19:03 +01:00
Eric Espie
8fdad7997e N°8772 - Turbo Ok 2025-11-05 10:15:58 +01:00
Eric Espie
b3ed7f4f5b N°8772 - UIBlocks 2025-11-04 17:36:44 +01:00
jf-cbd
4f4ba7167d WIP 2025-11-04 17:02:56 +01:00
Eric Espie
a092b65be7 N°8772 - WIP dependencies - Does not work yet 2025-11-04 15:22:14 +01:00
Eric Espie
5a1f6ffde9 N°8772 - WIP dependencies - Does not work yet 2025-11-04 09:05:29 +01:00
Benjamin Dalsass
0909ddfb3a N°8772 - dynamic form 2025-11-03 14:01:32 +01:00
Benjamin Dalsass
20da9664c2 N°8772 - dynamic form 2025-11-03 13:50:07 +01:00
Benjamin Dalsass
68d2038488 N°8772 - dynamic form 2025-11-03 13:47:07 +01:00
Eric Espie
4c9373d034 N°8772 - Fix error 2025-11-03 10:07:49 +01:00
Eric Espie
0d7ccd7d82 N°8772 - Moved debug forms 2025-10-31 16:48:06 +01:00
jf-cbd
077c48870f Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-10-31 16:44:03 +01:00
jf-cbd
5df44b8a18 Remove .compilation-symlinks 2025-10-31 16:42:30 +01:00
Eric Espie
d4415d6c3a N°8772 - some tests 2025-10-31 14:35:44 +01:00
Eric Espie
0196765eb6 N°8772 - automatic dependency in controller WIP 2025-10-31 08:58:50 +01:00
Eric Espie
45e4d9239c N°8772 - automatic dependency in controller WIP 2025-10-31 08:55:45 +01:00
Eric Espie
0df54413b3 N°8772 - cleanup code 2025-10-30 14:24:09 +01:00
Eric Espie
601cde0e2d N°8772 - Traditional parameters declaration 2025-10-30 14:16:36 +01:00
Eric Espie
4c10cfee60 N°8772 - Errors & turbo 2025-10-30 11:53:29 +01:00
Eric Espie
7a6f36b395 N°8772 - Debug & turbo 2025-10-30 10:00:12 +01:00
Eric Espie
06dbdcb5cd N°8772 - Turbo WIP 2025-10-29 16:52:19 +01:00
Benjamin Dalsass
c00bcbcd81 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-10-29 14:00:08 +01:00
Eric Espie
1394edc111 N°8772 - Turbo WIP
N°8772 - Twig factorization
2025-10-29 13:59:35 +01:00
Benjamin Dalsass
8582e89b8c Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager
# Conflicts:
#	sources/Forms/Block/AbstractFormBlock.php
#	sources/Forms/Block/DataModel/AttributeValueChoiceFormBlock.php
#	templates/application/forms/itop_console_layout.html.twig
2025-10-29 13:31:02 +01:00
Benjamin Dalsass
6952bfa978 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-29 13:14:15 +01:00
Eric Espie
98048219e7 N°8772 - Twig factorization 2025-10-29 09:31:40 +01:00
Eric Espie
8134d9a592 N°8772 - Form turbo stream WIP 2025-10-28 16:41:59 +01:00
Eric Espie
2a3de68652 N°8772 - Form turbo stream WIP 2025-10-28 15:34:19 +01:00
Benjamin Dalsass
5d335b39d2 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-28 15:22:29 +01:00
Eric Espie
c2fcf4144b N°8772 - Sub-forms WIP 2025-10-24 16:56:45 +02:00
Eric Espie
675db85131 N°8772 - log for exception 2025-10-24 15:44:41 +02:00
Benjamin Dalsass
212309e938 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 15:42:33 +02:00
Benjamin Dalsass
a4fbe90579 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 15:36:51 +02:00
Benjamin Dalsass
eb3c5e4eee N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 14:46:59 +02:00
Benjamin Dalsass
33c03f9493 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 09:29:53 +02:00
Benjamin Dalsass
243a525e15 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 08:56:04 +02:00
Benjamin Dalsass
a1025ac837 N°8771 - Add Symfony form component to iTop core
- IO
2025-10-24 08:35:10 +02:00
Benjamin Dalsass
7708f8e00e N°8771 - Add Symfony form component to iTop core
- IO
2025-10-24 07:54:51 +02:00
Benjamin Dalsass
a51272f107 N°8771 - Add Symfony form component to iTop core
- IO
2025-10-24 07:15:35 +02:00
Benjamin Dalsass
5582afe5ae N°8771 - Add Symfony form component to iTop core
- add licence info
2025-10-24 06:37:22 +02:00
Eric Espie
21b786e0fa N°8772 - Form dependencies manager implementation - WIP 2025-10-23 16:57:35 +02:00
Eric Espie
fd449d195d N°8772 - Form dependencies manager implementation - WIP 2025-10-23 15:11:14 +02:00
Eric Espie
98c0b11db7 N°8772 - Form dependencies manager implementation - WIP 2025-10-23 13:51:24 +02:00
Benjamin Dalsass
8c3543363e N°8771 - Add Symfony form component to iTop core
- WIP
2025-10-23 13:29:04 +02:00
Benjamin Dalsass
5dea3f5299 N°8771 - Add Symfony form component to iTop core
- WIP
2025-10-23 12:11:02 +02:00
Benjamin Dalsass
239814a38c N°8771 - Add Symfony form component to iTop core
- restore branch
2025-10-23 11:28:01 +02:00
Benjamin Dalsass
c4e2cc6c1c Merge remote-tracking branch 'origin/develop' into feature/8772_form_dependencies_manager
# Conflicts:
#	sources/Application/TwigBase/Controller/Controller.php
2025-10-23 11:14:24 +02:00
Benjamin Dalsass
ee745f8be9 N°8772 - Form dependencies manager implementation
- turbo implementation
2025-10-23 11:11:51 +02:00
Benjamin Dalsass
1a4a64cec1 N°8772 - Form dependencies manager implementation 2025-10-23 11:11:39 +02:00
Benjamin Dalsass
834d4d461b N°8771 - Add Symfony form component to iTop core
- restore $aAdditionalPaths missing parameter
2025-10-23 11:10:59 +02:00
Eric Espie
5df73f5820 N°8781 - Improve twig base controller render error report 2025-10-23 11:10:54 +02:00
odain
c83d998924 N°4058 - fix PHP Deprecated base64_decodestrlen : Passing nul 2025-10-23 11:10:17 +02:00
Stephen Abello
ccdfbbe0bf N°8701 - Fix class icon alt text displaying in portal tile when there's no icon defined 2025-10-23 11:10:17 +02:00
Benjamin Dalsass
0dae7346d1 N°8772 - Form dependencies manager implementation
- turbo implementation
2025-10-20 15:16:44 +02:00
Benjamin Dalsass
cdfded766f N°8772 - Form dependencies manager implementation 2025-10-17 09:03:45 +02:00
822 changed files with 115240 additions and 342 deletions

16
.phpstorm.meta.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace PHPSTORM_META
{
override(\MetaModel::NewObject(0), map([
'' => '@',
]));
override(\MetaModel::GetObject(0), map([
'' => '@',
]));
}

View File

@@ -849,5 +849,222 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
</methods>
</class>
</classes>
<property_trees _delta="define" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://www.combodo.com/itop-schema/3.3">
<property_tree id="DashletGroupBy" xsi:type="Combodo-PropertyTree">
<extends>Dashlet</extends>
<nodes>
<node id="title" xsi:type="Combodo-Property">
<label>UI:DashletGroupBy:Prop-Title</label>
<value-type xsi:type="Combodo-ValueType-Label"/><!-- LabelFormBlock -->
</node>
<node id="query" xsi:type="Combodo-Property">
<label>UI:DashletGroupBy:Prop-Query</label>
<data-transform>
<xml-node-empty-not-allowed/> <!-- mandatory quoi ! -->
</data-transform>
<value-type xsi:type="Combodo-ValueType-OQL"/><!-- OqlFormBlock -->
</node>
<node id="group_by" xsi:type="Combodo-Property">
<label>UI:DashletGroupBy:Prop-GroupBy</label>
<data-transform>
<xml-node-empty-not-allowed/>
</data-transform>
<value-type xsi:type="Combodo-ValueType-ClassAttributeGroupBy"> <!-- par défaut, il proposera le state attribute de la classe -->
<class>{{query.selected_class}}</class>
</value-type>
</node>
<node id="style" xsi:type="Combodo-Property"> <!-- possible de le cacher, etc.... celui-ci nous met dedans -->
<label>UI:DashletGroupBy:Prop-Style</label>
<data-transform>
<xml-node-empty-defaults-to>bars</xml-node-empty-defaults-to>
</data-transform>
<value-type xsi:type="Combodo-ValueType-Choice">
<values>
<value id="bars">
<label>UI:DashletGroupByBars:Label</label>
</value>
<value id="pie">
<label>UI:DashletGroupByPie:Label</label>
</value>
<value id="table">
<label>UI:DashletGroupByTable:Label</label>
</value>
</values>
</value-type>
</node>
<node id="aggregation_function" xsi:type="Combodo-Property">
<label>UI:DashletGroupBy:Prop-Function</label>
<data-transform>
<xml-node-empty-not-allowed/> <!-- mandatory quoi ! -->
</data-transform>
<value-type xsi:type="Combodo-ValueType-AggregateFunction"> <!-- par défaut : count -->
<class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables -->
</value-type>
</node>
<node id="aggregation_attribute" xsi:type="Combodo-Property">
<label>UI:DashletGroupBy:Prop-FunctionAttribute</label>
<relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition>
<data-transform>
<xml-node-empty-not-allowed/> <!-- mandatory quoi ! -->
</data-transform>
<value-type xsi:type="Combodo-ValueType-ClassAttribute">
<class>{{query.selected_class}}</class>
<category>numeric</category>
</value-type>
</node>
<node id="order_by" xsi:type="Combodo-Property">
<label>UI:DashletGroupBy:Prop-OrderField</label>
<value-type xsi:type="Combodo-ValueType-ChoiceFromInput">
<values>
<value id="attribute">
<label>{{aggregation_attribute.label}}</label>
</value>
<value id="function">
<label>{{aggregation_function.label}}</label>
</value>
</values>
</value-type>
</node>
<node id="limit" xsi:type="Combodo-Property">
<label>UI:DashletGroupBy:Prop-Limit</label>
<relevance-condition>{{order_by.value = 'function'}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-Integer"/>
</node>
<node id="order_direction" xsi:type="Combodo-Property">
<label>UI:DashletGroupBy:Prop-OrderDirection</label>
<data-transform>
<xml-node-empty-not-allowed/>
</data-transform>
<value-type xsi:type="Combodo-ValueType-Choice">
<values>
<value id="asc">
<label>UI:DashletGroupBy:Order:asc</label>
</value>
<value id="desc">
<label>UI:DashletGroupBy:Order:desc</label>
</value>
</values>
</value-type>
<display-default>desc</display-default>
</node>
</nodes>
</property_tree>
<property_tree id="DashletBadge" xsi:type="Combodo-PropertyTree">
<extends>Dashlet</extends>
<nodes>
<node id="class" xsi:type="Combodo-Property">
<label>UI:DashletBadge:Prop-Class</label>
<value-type xsi:type="Combodo-ValueType-Class">
<categories-csv>bizmodel</categories-csv>
</value-type>
</node>
</nodes>
</property_tree>
<property_tree id="DashletHeaderDynamic" xsi:type="Combodo-PropertyTree">
<extends>Dashlet</extends>
<nodes>
<node id="title" xsi:type="Combodo-Property">
<label>UI:DashletHeaderDynamic:Prop-Title</label>
<value-type xsi:type="Combodo-ValueType-Label">
<not-blank/>
</value-type>
</node>
<node id="icon" xsi:type="Combodo-Property">
<label>UI:DashletHeaderDynamic:Prop-Icon</label>
<value-type xsi:type="Combodo-ValueType-Choice">
<values>
<value id="todo">
<label>ToDo</label>
</value>
</values>
</value-type>
</node>
<node id="subtitle" xsi:type="Combodo-Property">
<label>UI:DashletHeaderDynamic:Prop-Subtitle</label>
<value-type xsi:type="Combodo-ValueType-Label"/>
</node>
<node id="query" xsi:type="Combodo-Property">
<label>UI:DashletHeaderDynamic:Prop-Query</label>
<data-transform>
<xml-node-empty-not-allowed/>
</data-transform>
<value-type xsi:type="Combodo-ValueType-OQL"/>
</node>
<node id="group_by" xsi:type="Combodo-Property">
<label>UI:DashletHeaderDynamic:Prop-GroupBy</label>
<data-transform>
<xml-node-empty-not-allowed/>
</data-transform>
<value-type xsi:type="Combodo-ValueType-ClassAttribute">
<class>{{query.selected_class}}</class>
<category>enum</category>
</value-type>
</node>
<node id="values" xsi:type="Combodo-CollectionOfValues">
<label>UI:DashletHeaderDynamic:Prop-Values</label>
<data-transform>
<xml-format xsi:type="xml-format-csv"/>
</data-transform>
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
<class>{{query.selected_class}}</class>
<attribute>{{group_by.value}}</attribute>
</value-type>
</node>
</nodes>
</property_tree>
<property_tree id="DashletHeaderStatic" xsi:type="Combodo-PropertyTree">
<extends>Dashlet</extends>
<nodes>
<node id="title" xsi:type="Combodo-Property">
<label>UI:DashletHeaderStatic:Prop-Title</label>
<value-type xsi:type="Combodo-ValueType-Label"/>
</node>
<node id="icon" xsi:type="Combodo-Property">
<label>UI:DashletHeaderStatic:Prop-Icon</label>
<value-type xsi:type="Combodo-ValueType-Icon"/>
</node>
</nodes>
</property_tree>
<property_tree id="DashletObjectList" xsi:type="Combodo-PropertyTree">
<extends>Dashlet</extends>
<nodes>
<node id="title" xsi:type="Combodo-Property">
<label>UI:DashletObjectList:Prop-Title</label>
<value-type xsi:type="Combodo-ValueType-Label">
</value-type>
</node>
<node id="query" xsi:type="Combodo-Property">
<label>UI:DashletObjectList:Prop-Query</label>
<value-type xsi:type="Combodo-ValueType-OQL"/>
</node>
<node id="menu" xsi:type="Combodo-Property">
<label>UI:DashletObjectList:Prop-Menu</label>
<value-type xsi:type="Combodo-ValueType-Boolean">
<on>
<!-- not so cute, but matches exactly 3.2 implementation of boolean fields -->
<label>UI:UserManagement:ActionAllowed:Yes</label>
<value>true</value>
</on>
<off>
<label>UI:UserManagement:ActionAllowed:No</label>
<value>false</value>
</off>
</value-type>
</node>
</nodes>
</property_tree>
<property_tree id="DashletPlainText" xsi:type="Combodo-PropertyTree">
<extends>Dashlet</extends>
<nodes>
<node id="text" xsi:type="Combodo-Property">
<label>UI:DashletPlainText:Prop-Text</label>
<constraints>
<not_blank/>
</constraints>
<value-type xsi:type="Combodo-ValueType-Text"/>
</node>
</nodes>
</property_tree>
</property_trees>
</meta>
</itop_design>

View File

@@ -1900,6 +1900,12 @@ SQL;
return $response;
}
public static function QuoteForPHP(string $sValue): string
{
$sEscaped = str_replace(['\\', "'"], ['\\\\', "\\'"], $sValue);
return "'$sEscaped'";
}
/**
* Get a standard list of character sets
*

View File

@@ -31,6 +31,7 @@
"symfony/mailer": "^6.4",
"symfony/security-csrf": "^6.4",
"symfony/twig-bundle": "~6.4.0",
"symfony/validator" : "^6.4",
"symfony/yaml": "~6.4.0",
"tecnickcom/tcpdf": "^6.6.0",
"thenetworg/oauth2-azure": "^2.0"

103
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "26fa7aa920057d080bcc0948bf052fda",
"content-hash" : "3e627286597661542dd598499c2bcc36",
"packages": [
{
"name": "apereo/phpcas",
@@ -4984,6 +4984,107 @@
"time": "2025-07-10T08:14:14+00:00"
},
{
"name" : "symfony/validator",
"version" : "v6.4.29",
"source" : {
"type" : "git",
"url" : "https://github.com/symfony/validator.git",
"reference" : "99df8a769e64e399f510166141ea74f450e8dd1d"
},
"dist" : {
"type" : "zip",
"url" : "https://api.github.com/repos/symfony/validator/zipball/99df8a769e64e399f510166141ea74f450e8dd1d",
"reference" : "99df8a769e64e399f510166141ea74f450e8dd1d",
"shasum" : ""
},
"require" : {
"php" : ">=8.1",
"symfony/deprecation-contracts" : "^2.5|^3",
"symfony/polyfill-ctype" : "~1.8",
"symfony/polyfill-mbstring" : "~1.0",
"symfony/polyfill-php83" : "^1.27",
"symfony/translation-contracts" : "^2.5|^3"
},
"conflict" : {
"doctrine/annotations" : "<1.13",
"doctrine/lexer" : "<1.1",
"symfony/dependency-injection" : "<5.4",
"symfony/expression-language" : "<5.4",
"symfony/http-kernel" : "<5.4",
"symfony/intl" : "<5.4",
"symfony/property-info" : "<5.4",
"symfony/translation" : "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3",
"symfony/yaml" : "<5.4"
},
"require-dev" : {
"doctrine/annotations" : "^1.13|^2",
"egulias/email-validator" : "^2.1.10|^3|^4",
"symfony/cache" : "^5.4|^6.0|^7.0",
"symfony/config" : "^5.4|^6.0|^7.0",
"symfony/console" : "^5.4|^6.0|^7.0",
"symfony/dependency-injection" : "^5.4|^6.0|^7.0",
"symfony/expression-language" : "^5.4|^6.0|^7.0",
"symfony/finder" : "^5.4|^6.0|^7.0",
"symfony/http-client" : "^5.4|^6.0|^7.0",
"symfony/http-foundation" : "^5.4|^6.0|^7.0",
"symfony/http-kernel" : "^5.4|^6.0|^7.0",
"symfony/intl" : "^5.4|^6.0|^7.0",
"symfony/mime" : "^5.4|^6.0|^7.0",
"symfony/property-access" : "^5.4|^6.0|^7.0",
"symfony/property-info" : "^5.4|^6.0|^7.0",
"symfony/translation" : "^5.4.35|~6.3.12|^6.4.3|^7.0.3",
"symfony/yaml" : "^5.4|^6.0|^7.0"
},
"type" : "library",
"autoload" : {
"psr-4" : {
"Symfony\\Component\\Validator\\" : ""
},
"exclude-from-classmap" : [
"/Tests/",
"/Resources/bin/"
]
},
"notification-url" : "https://packagist.org/downloads/",
"license" : [
"MIT"
],
"authors" : [
{
"name" : "Fabien Potencier",
"email" : "fabien@symfony.com"
},
{
"name" : "Symfony Community",
"homepage" : "https://symfony.com/contributors"
}
],
"description" : "Provides tools to validate values",
"homepage" : "https://symfony.com",
"support" : {
"source" : "https://github.com/symfony/validator/tree/v6.4.29"
},
"funding" : [
{
"url" : "https://symfony.com/sponsor",
"type" : "custom"
},
{
"url" : "https://github.com/fabpot",
"type" : "github"
},
{
"url" : "https://github.com/nicolas-grekas",
"type" : "github"
},
{
"url" : "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type" : "tidelift"
}
],
"time" : "2025-11-06T20:26:06+00:00"
},
{
"name": "symfony/var-dumper",
"version": "v6.4.26",
"source": {

View File

@@ -41,7 +41,7 @@ use utils;
/**
* Class \Combodo\iTop\DesignDocument
*
* A design document is the DOM tree that modelize behaviors. One of its
* A design document is the DOM tree that models behaviors. One of its
* characteristics is that it can be altered by the mean of the same kind of document.
*
*/

View File

@@ -691,6 +691,28 @@ abstract class LogAPI
static::$m_oMockMetaModelConfig = $oMetaModelConfig;
}
public static function Exception(string $sMessage, throwable $oException, string $sChannel = null, array $aContext = []): void
{
$aErrorLogs = [];
$aErrorLogs[] = static::PrepareErrorLog($sMessage, $oException, $aContext);
$oException = $oException->getPrevious();
while ($oException !== null) {
$aErrorLogs[] = static::PrepareErrorLog($oException->getMessage(), $oException, $aContext, true);
$oException = $oException->getPrevious();
}
$aErrorLogs = array_reverse($aErrorLogs);
foreach ($aErrorLogs as $aErrorLog) {
static::Error($aErrorLog['message'], $sChannel, $aErrorLog['context']);
}
}
private static function PrepareErrorLog(string $sMessage, throwable $oException, array $aContext, bool $isPrevious = false): array
{
$aContext['Error Message'] = $oException->getMessage();
$aContext['Stack Trace'] = $oException->getTraceAsString();
return ['message' => ($isPrevious ? "Previous " : '')."Exception: $sMessage", 'context' => $aContext];
}
public static function Error($sMessage, $sChannel = null, $aContext = [])
{
static::Log(self::LEVEL_ERROR, $sMessage, $sChannel, $aContext);

View File

@@ -55,6 +55,11 @@ abstract class ModelReflection
abstract public function GetFiltersList($sClass);
abstract public function IsValidFilterCode($sClass, $sFilterCode);
/**
* @since 3.3.0
*/
abstract public function IsAbstract($sClass): bool;
/**
* @param string $sOQL
*
@@ -148,7 +153,7 @@ class ModelReflectionRuntime extends ModelReflection
$sAttributeClass = get_class($oAttDef);
if ($aScope != null) {
foreach ($aScope as $sScopeClass) {
if (($sAttributeClass == $sScopeClass) || is_subclass_of($sAttributeClass, $sScopeClass)) {
if (is_a($sAttributeClass, $sScopeClass, true)) {
$aAttributes[$sAttCode] = $sAttributeClass;
break;
}
@@ -230,6 +235,11 @@ class ModelReflectionRuntime extends ModelReflection
return MetaModel::IsValidFilterCode($sClass, $sFilterCode);
}
public function IsAbstract($sClass): bool
{
return MetaModel::IsAbstract($sClass);
}
public function GetQuery($sOQL)
{
return new QueryReflectionRuntime($sOQL, $this);

View File

@@ -2103,12 +2103,18 @@ class VariableExpression extends UnaryExpression
/**
* Evaluate the value of the expression
*
* @param array $aArgs
* @throws \Exception if terms cannot be evaluated as scalars
*/
*
* @return mixed
* @throws \MissingQueryArgument
*/
public function Evaluate(array $aArgs)
{
throw new Exception('not implemented yet');
if (!isset($aArgs[$this->m_sName])) {
throw new MissingQueryArgument('Missing variable expression argument', array('expecting'=>$this->m_sName));
}
return $aArgs[$this->m_sName];
}
/**

View File

@@ -72,9 +72,15 @@ class OQLException extends CoreException
}
else
{
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
$sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput'";
if (count($this->m_aExpecting) < 30) {
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
$sMessage .= ', expecting '.json_encode($sExpectations);
}
$sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting);
$sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput', expecting $sExpectations, I would suggest to use '$sSuggest'";
if (strlen($sSuggest) > 0) {
$sMessage .= ", I would suggest to use ".json_encode($sSuggest);
}
}
// make sure everything is assigned properly
@@ -155,5 +161,3 @@ class OQLException extends CoreException
return $sRet;
}
}
?>

View File

@@ -57,15 +57,15 @@ class OqlName
{
return $this->m_iPos;
}
public function __toString()
{
return $this->m_sValue;
}
}
}
/**
*
*
* Store hexadecimal values as strings so that we can support 64-bit values
*
*/
@@ -77,12 +77,12 @@ class OqlHexValue
{
$this->m_sValue = $sValue;
}
public function __toString()
{
return $this->m_sValue;
}
}
class OqlJoinSpec
@@ -109,6 +109,7 @@ class OqlJoinSpec
{
return $this->m_oClass->GetValue();
}
public function GetClassAlias()
{
return $this->m_oClassAlias->GetValue();
@@ -118,6 +119,7 @@ class OqlJoinSpec
{
return $this->m_oClass;
}
public function GetClassAliasDetails()
{
return $this->m_oClassAlias;
@@ -127,10 +129,12 @@ class OqlJoinSpec
{
return $this->m_oLeftField;
}
public function GetRightField()
{
return $this->m_oRightField;
}
public function GetOperator()
{
return $this->m_sOperator;
@@ -146,8 +150,9 @@ interface CheckableExpression
* @param ModelReflection $oModelReflection MetaModel to consider
* @param array $aAliases Aliases to class names (for the current query)
* @param string $sSourceQuery For the reporting
*
* @throws OqlNormalizeException
*/
*/
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery);
}
@@ -168,13 +173,11 @@ class MatchOqlExpression extends MatchExpression implements CheckableExpression
$this->m_oRightExpr->Check($oModelReflection, $aAliases, $sSourceQuery);
// Only field MATCHES scalar is allowed
if (!$this->m_oLeftExpr instanceof FieldExpression)
{
if (!$this->m_oLeftExpr instanceof FieldExpression) {
throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oLeftExpr->RenderExpression(true), 0));
}
// Only field MATCHES scalar is allowed
if (!$this->m_oRightExpr instanceof ScalarExpression && !$this->m_oRightExpr instanceof VariableOqlExpression)
{
if (!$this->m_oRightExpr instanceof ScalarExpression && !$this->m_oRightExpr instanceof VariableOqlExpression) {
throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oRightExpr->RenderExpression(true), 0));
}
}
@@ -198,7 +201,7 @@ class NestedQueryOqlExpression extends NestedQueryExpression implements Checkabl
*
* @param OQLObjectQuery $oOQLObjectQuery
*/
public function __construct($oOQLObjectQuery )
public function __construct($oOQLObjectQuery)
{
parent::__construct($oOQLObjectQuery->ToDBSearch(""));
$this->m_oOQLObjectQuery = $oOQLObjectQuery;
@@ -232,8 +235,7 @@ class FieldOqlExpression extends FieldExpression implements CheckableExpression
public function __construct($oName, $oParent = null)
{
if (is_null($oParent))
{
if (is_null($oParent)) {
$oParent = new OqlName('', 0);
}
$this->m_oParent = $oParent;
@@ -256,37 +258,28 @@ class FieldOqlExpression extends FieldExpression implements CheckableExpression
{
$sClassAlias = $this->GetParent();
$sFltCode = $this->GetName();
if (empty($sClassAlias))
{
if (empty($sClassAlias)) {
// Try to find an alias
// Build an array of field => array of aliases
$aFieldClasses = array();
foreach($aAliases as $sAlias => $sReal)
{
foreach($oModelReflection->GetFiltersList($sReal) as $sAnFltCode)
{
foreach ($aAliases as $sAlias => $sReal) {
foreach ($oModelReflection->GetFiltersList($sReal) as $sAnFltCode) {
$aFieldClasses[$sAnFltCode][] = $sAlias;
}
}
if (!array_key_exists($sFltCode, $aFieldClasses))
{
if (!array_key_exists($sFltCode, $aFieldClasses)) {
throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), array_keys($aFieldClasses));
}
if (count($aFieldClasses[$sFltCode]) > 1)
{
if (count($aFieldClasses[$sFltCode]) > 1) {
throw new OqlNormalizeException('Ambiguous filter code', $sSourceQuery, $this->GetNameDetails());
}
$sClassAlias = $aFieldClasses[$sFltCode][0];
}
else
{
if (!array_key_exists($sClassAlias, $aAliases))
{
} else {
if (!array_key_exists($sClassAlias, $aAliases)) {
throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $this->GetParentDetails(), array_keys($aAliases));
}
$sClass = $aAliases[$sClassAlias];
if (!$oModelReflection->IsValidFilterCode($sClass, $sFltCode))
{
if (!$oModelReflection->IsValidFilterCode($sClass, $sFltCode)) {
throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), $oModelReflection->GetFiltersList($sClass));
}
}
@@ -305,8 +298,7 @@ class ListOqlExpression extends ListExpression implements CheckableExpression
{
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
{
foreach ($this->GetItems() as $oItemExpression)
{
foreach ($this->GetItems() as $oItemExpression) {
$oItemExpression->Check($oModelReflection, $aAliases, $sSourceQuery);
}
}
@@ -316,8 +308,7 @@ class FunctionOqlExpression extends FunctionExpression implements CheckableExpre
{
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
{
foreach ($this->GetArgs() as $oArgExpression)
{
foreach ($this->GetArgs() as $oArgExpression) {
$oArgExpression->Check($oModelReflection, $aAliases, $sSourceQuery);
}
}
@@ -350,6 +341,7 @@ abstract class OqlQuery
* Determine the class
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @return string
* @throws Exception
*/
@@ -392,6 +384,7 @@ class OqlObjectQuery extends OqlQuery
* Determine the class
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @return string
* @throws Exception
*/
@@ -415,6 +408,7 @@ class OqlObjectQuery extends OqlQuery
{
return $this->m_oClass;
}
public function GetClassAliasDetails()
{
return $this->m_oClassAlias;
@@ -424,6 +418,7 @@ class OqlObjectQuery extends OqlQuery
{
return $this->m_aJoins;
}
public function GetCondition()
{
return $this->m_oCondition;
@@ -432,44 +427,37 @@ class OqlObjectQuery extends OqlQuery
/**
* Recursively check the validity of the expression with regard to the data model
* and the query in which it is used
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @throws OqlNormalizeException
*/
*/
public function Check(ModelReflection $oModelReflection, $sSourceQuery, $aParentAliases = array())
{
$sClass = $this->GetClass($oModelReflection);
$sClassAlias = $this->GetClassAlias();
if (!$oModelReflection->IsValidClass($sClass))
{
if (!$oModelReflection->IsValidClass($sClass)) {
throw new UnknownClassOqlException($sSourceQuery, $this->GetClassDetails(), $oModelReflection->GetClasses());
}
$aAliases = array_merge(array($sClassAlias => $sClass),$aParentAliases);
$aAliases = array_merge(array($sClassAlias => $sClass), $aParentAliases);
$aJoinSpecs = $this->GetJoins();
if (is_array($aJoinSpecs))
{
foreach ($aJoinSpecs as $oJoinSpec)
{
if (is_array($aJoinSpecs)) {
foreach ($aJoinSpecs as $oJoinSpec) {
$sJoinClass = $oJoinSpec->GetClass();
$sJoinClassAlias = $oJoinSpec->GetClassAlias();
if (!$oModelReflection->IsValidClass($sJoinClass))
{
if (!$oModelReflection->IsValidClass($sJoinClass)) {
throw new UnknownClassOqlException($sSourceQuery, $oJoinSpec->GetClassDetails(), $oModelReflection->GetClasses());
}
if (array_key_exists($sJoinClassAlias, $aAliases))
{
if ($sJoinClassAlias != $sJoinClass)
{
if (array_key_exists($sJoinClassAlias, $aAliases)) {
if ($sJoinClassAlias != $sJoinClass) {
throw new OqlNormalizeException('Duplicate class alias', $sSourceQuery, $oJoinSpec->GetClassAliasDetails());
}
else
{
} else {
throw new OqlNormalizeException('Duplicate class name', $sSourceQuery, $oJoinSpec->GetClassDetails());
}
}
}
// Assumption: ext key on the left only !!!
// normalization should take care of this
@@ -480,85 +468,74 @@ class OqlObjectQuery extends OqlQuery
$oRightField = $oJoinSpec->GetRightField();
$sToClass = $oRightField->GetParent();
$sPKeyDescriptor = $oRightField->GetName();
if ($sPKeyDescriptor != 'id')
{
if ($sPKeyDescriptor != 'id') {
throw new OqlNormalizeException('Wrong format for Join clause (right hand), expecting an id', $sSourceQuery, $oRightField->GetNameDetails(), array('id'));
}
$aAliases[$sJoinClassAlias] = $sJoinClass;
if (!array_key_exists($sFromClass, $aAliases))
{
if (!array_key_exists($sFromClass, $aAliases)) {
throw new OqlNormalizeException('Unknown class in join condition (left expression)', $sSourceQuery, $oLeftField->GetParentDetails(), array_keys($aAliases));
}
if (!array_key_exists($sToClass, $aAliases))
{
if (!array_key_exists($sToClass, $aAliases)) {
throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sSourceQuery, $oRightField->GetParentDetails(), array_keys($aAliases));
}
$aExtKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], \Combodo\iTop\Core\AttributeDefinition\AttributeExternalKey::class);
$aObjKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], \Combodo\iTop\Core\AttributeDefinition\AttributeObjectKey::class);
$aAllKeys = array_merge($aExtKeys, $aObjKeys);
if (!array_key_exists($sExtKeyAttCode, $aAllKeys))
{
if (!array_key_exists($sExtKeyAttCode, $aAllKeys)) {
throw new OqlNormalizeException('Unknown key in join condition (left expression)', $sSourceQuery, $oLeftField->GetNameDetails(), array_keys($aAllKeys));
}
if ($sFromClass == $sJoinClassAlias)
{
if ($sFromClass == $sJoinClassAlias) {
if (array_key_exists($sExtKeyAttCode, $aExtKeys)) // Skip that check for object keys
{
$sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass');
if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass))
{
if (!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass)) {
throw new OqlNormalizeException("The joined class ($aAliases[$sFromClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails());
}
}
}
else
{
} else {
$sOperator = $oJoinSpec->GetOperator();
switch($sOperator)
{
switch ($sOperator) {
case '=':
$iOperatorCode = TREE_OPERATOR_EQUALS;
break;
$iOperatorCode = TREE_OPERATOR_EQUALS;
break;
case 'BELOW':
$iOperatorCode = TREE_OPERATOR_BELOW;
break;
$iOperatorCode = TREE_OPERATOR_BELOW;
break;
case 'BELOW_STRICT':
$iOperatorCode = TREE_OPERATOR_BELOW_STRICT;
break;
$iOperatorCode = TREE_OPERATOR_BELOW_STRICT;
break;
case 'NOT_BELOW':
$iOperatorCode = TREE_OPERATOR_NOT_BELOW;
break;
$iOperatorCode = TREE_OPERATOR_NOT_BELOW;
break;
case 'NOT_BELOW_STRICT':
$iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT;
break;
$iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT;
break;
case 'ABOVE':
$iOperatorCode = TREE_OPERATOR_ABOVE;
break;
$iOperatorCode = TREE_OPERATOR_ABOVE;
break;
case 'ABOVE_STRICT':
$iOperatorCode = TREE_OPERATOR_ABOVE_STRICT;
break;
$iOperatorCode = TREE_OPERATOR_ABOVE_STRICT;
break;
case 'NOT_ABOVE':
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE;
break;
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE;
break;
case 'NOT_ABOVE_STRICT':
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT;
break;
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT;
break;
}
if (array_key_exists($sExtKeyAttCode, $aExtKeys)) // Skip that check for object keys
{
$sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass');
if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass))
{
if (!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass)) {
throw new OqlNormalizeException("The joined class ($aAliases[$sToClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails());
}
}
$aAttList = $oModelReflection->ListAttributes($aAliases[$sFromClass]);
$sAttType = $aAttList[$sExtKeyAttCode];
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_subclass_of($sAttType, \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class) && ($sAttType != \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class))
{
if (($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_a($sAttType, \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class, true)) {
throw new OqlNormalizeException("The specified tree operator $sOperator is not applicable to the key", $sSourceQuery, $oLeftField->GetNameDetails());
}
}
@@ -567,26 +544,23 @@ class OqlObjectQuery extends OqlQuery
// Check the select information
//
foreach ($this->GetSelectedClasses() as $oClassDetails)
{
foreach ($this->GetSelectedClasses() as $oClassDetails) {
$sClassToSelect = $oClassDetails->GetValue();
if (!array_key_exists($sClassToSelect, $aAliases))
{
if (!array_key_exists($sClassToSelect, $aAliases)) {
throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $oClassDetails, array_keys($aAliases));
}
}
// Check the condition tree
//
if ($this->m_oCondition instanceof Expression)
{
if ($this->m_oCondition instanceof Expression) {
$this->m_oCondition->Check($oModelReflection, $aAliases, $sSourceQuery);
}
}
/**
* Make the relevant DBSearch instance (FromOQL)
*/
*/
public function ToDBSearch($sQuery)
{
$sClass = $this->GetClass(new ModelReflectionRuntime());
@@ -594,6 +568,7 @@ class OqlObjectQuery extends OqlQuery
$oSearch = new DBObjectSearch($sClass, $sClassAlias);
$oSearch->InitFromOqlQuery($this, $sQuery);
return $oSearch;
}
}
@@ -606,19 +581,15 @@ class OqlUnionQuery extends OqlQuery
{
parent::__construct();
$this->aQueries[] = $oLeftQuery;
if ($oRightQueryOrUnion instanceof OqlUnionQuery)
{
foreach ($oRightQueryOrUnion->GetQueries() as $oSingleQuery)
{
if ($oRightQueryOrUnion instanceof OqlUnionQuery) {
foreach ($oRightQueryOrUnion->GetQueries() as $oSingleQuery) {
$this->aQueries[] = $oSingleQuery;
}
}
else
{
} else {
$this->aQueries[] = $oRightQueryOrUnion;
}
}
public function GetQueries()
{
return $this->aQueries;
@@ -627,66 +598,54 @@ class OqlUnionQuery extends OqlQuery
/**
* Check the validity of the expression with regard to the data model
* and the query in which it is used
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @throws OqlNormalizeException
*/
*/
public function Check(ModelReflection $oModelReflection, $sSourceQuery)
{
$aColumnToClasses = array();
foreach ($this->aQueries as $iQuery => $oQuery)
{
foreach ($this->aQueries as $iQuery => $oQuery) {
$oQuery->Check($oModelReflection, $sSourceQuery);
$aAliasToClass = array($oQuery->GetClassAlias() => $oQuery->GetClass($oModelReflection));
$aJoinSpecs = $oQuery->GetJoins();
if (is_array($aJoinSpecs))
{
foreach ($aJoinSpecs as $oJoinSpec)
{
if (is_array($aJoinSpecs)) {
foreach ($aJoinSpecs as $oJoinSpec) {
$aAliasToClass[$oJoinSpec->GetClassAlias()] = $oJoinSpec->GetClass();
}
}
$aSelectedClasses = $oQuery->GetSelectedClasses();
if ($iQuery != 0)
{
if (count($aSelectedClasses) < count($aColumnToClasses))
{
if ($iQuery != 0) {
if (count($aSelectedClasses) < count($aColumnToClasses)) {
$oLastClass = end($aSelectedClasses);
throw new OqlNormalizeException('Too few selected classes in the subquery', $sSourceQuery, $oLastClass);
}
if (count($aSelectedClasses) > count($aColumnToClasses))
{
if (count($aSelectedClasses) > count($aColumnToClasses)) {
$oLastClass = end($aSelectedClasses);
throw new OqlNormalizeException('Too many selected classes in the subquery', $sSourceQuery, $oLastClass);
}
}
foreach ($aSelectedClasses as $iColumn => $oClassDetails)
{
foreach ($aSelectedClasses as $iColumn => $oClassDetails) {
$sAlias = $oClassDetails->GetValue();
$sClass = $aAliasToClass[$sAlias];
$aColumnToClasses[$iColumn][] = array(
'alias' => $sAlias,
'class' => $sClass,
'alias' => $sAlias,
'class' => $sClass,
'class_name' => $oClassDetails,
);
}
}
foreach ($aColumnToClasses as $iColumn => $aClasses)
{
foreach ($aColumnToClasses as $iColumn => $aClasses) {
$sRootClass = null;
foreach ($aClasses as $iQuery => $aData)
{
if ($iQuery == 0)
{
foreach ($aClasses as $iQuery => $aData) {
if ($iQuery == 0) {
// Establish the reference
$sRootClass = $oModelReflection->GetRootClass($aData['class']);
}
else
{
if ($oModelReflection->GetRootClass($aData['class']) != $sRootClass)
{
} else {
if ($oModelReflection->GetRootClass($aData['class']) != $sRootClass) {
$aSubclasses = $oModelReflection->EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL);
throw new OqlNormalizeException('Incompatible classes: could not find a common ancestor', $sSourceQuery, $aData['class_name'], $aSubclasses);
}
@@ -699,21 +658,21 @@ class OqlUnionQuery extends OqlQuery
* Determine the class
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @return string
* @throws Exception
*/
public function GetClass(ModelReflection $oModelReflection)
{
$aFirstColClasses = array();
foreach ($this->aQueries as $iQuery => $oQuery)
{
foreach ($this->aQueries as $iQuery => $oQuery) {
$aFirstColClasses[] = $oQuery->GetClass($oModelReflection);
}
$sClass = self::GetLowestCommonAncestor($oModelReflection, $aFirstColClasses);
if (is_null($sClass))
{
if (is_null($sClass)) {
throw new Exception('Could not determine the class of the union query. This issue should have been detected earlier by calling OqlQuery::Check()');
}
return $sClass;
}
@@ -726,6 +685,7 @@ class OqlUnionQuery extends OqlQuery
public function GetClassAlias()
{
$sAlias = $this->aQueries[0]->GetClassAlias();
return $sAlias;
}
@@ -735,29 +695,25 @@ class OqlUnionQuery extends OqlQuery
*
* @param ModelReflection $oModelReflection MetaModel to consider
* @param array $aClasses Flat list of classes
*
* @return string the lowest common ancestor amongst classes, null if none has been found
* @throws Exception
*/
public static function GetLowestCommonAncestor(ModelReflection $oModelReflection, $aClasses)
{
$sAncestor = null;
foreach($aClasses as $sClass)
{
if (is_null($sAncestor))
{
foreach ($aClasses as $sClass) {
if (is_null($sAncestor)) {
// first loop
$sAncestor = $sClass;
}
elseif ($oModelReflection->GetRootClass($sClass) != $oModelReflection->GetRootClass($sAncestor))
{
} elseif ($oModelReflection->GetRootClass($sClass) != $oModelReflection->GetRootClass($sAncestor)) {
$sAncestor = null;
break;
}
else
{
} else {
$sAncestor = self::LowestCommonAncestor($oModelReflection, $sAncestor, $sClass);
}
}
return $sAncestor;
}
@@ -766,37 +722,32 @@ class OqlUnionQuery extends OqlQuery
*/
protected static function LowestCommonAncestor(ModelReflection $oModelReflection, $sClassA, $sClassB)
{
if ($sClassA == $sClassB)
{
if ($sClassA == $sClassB) {
$sRet = $sClassA;
}
elseif (in_array($sClassA, $oModelReflection->EnumChildClasses($sClassB)))
{
} elseif (in_array($sClassA, $oModelReflection->EnumChildClasses($sClassB))) {
$sRet = $sClassB;
}
elseif (in_array($sClassB, $oModelReflection->EnumChildClasses($sClassA)))
{
} elseif (in_array($sClassB, $oModelReflection->EnumChildClasses($sClassA))) {
$sRet = $sClassA;
}
else
{
} else {
// Recurse
$sRet = self::LowestCommonAncestor($oModelReflection, $sClassA, $oModelReflection->GetParentClass($sClassB));
}
return $sRet;
}
/**
* Make the relevant DBSearch instance (FromOQL)
*/
*/
public function ToDBSearch($sQuery)
{
$aSearches = array();
foreach ($this->aQueries as $oQuery)
{
foreach ($this->aQueries as $oQuery) {
$aSearches[] = $oQuery->ToDBSearch($sQuery);
}
$oSearch = new DBUnionSearch($aSearches);
return $oSearch;
}
}

View File

@@ -6,4 +6,59 @@
.ibo-prop-header {
@extend %ibo-font-size-150;
padding-bottom: 14px;
}
.help-text{
padding: 1px 5px;
background-color: #d7e3f8;
border: 1px solid #c6e7f5;
border-radius: 5px;
margin: 5px 0;
font-size: 0.9em;
}
.form-error ul{
padding: 1px 5px;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 5px;
margin: 5px 0;
font-size: 0.9em;
}
.subform{
background-color: #efefef;
border-radius: 5px;
padding: 10px;
}
.form-buttons{
margin: 20px 0;
}
.form select{
padding: 0;
overflow-y: auto;
}
.form select option{
height: 30px;
display: flex;
align-items: center;
}
.turbo-refreshing{
opacity: .5;
}
.ibo-field legend{
margin-top: 24px;
}
collection-entry-element {
margin-top: 8px;
display: block;
padding: 10px 10px;
background-color: #f5f5f5;
border-radius: 5px;
}

View File

@@ -0,0 +1,3 @@
@import "../../../node_modules/tom-select/dist/scss/tom-select.scss";
$select-color-item-active-border: $ibo-input--focus--border-color;

View File

View File

@@ -30,7 +30,7 @@ SetupWebPage::AddModule(
// Identification
//
'label' => 'Database maintenance tools',
'category' => 'business',
'category' => 'Application management',
// Setup
//

View File

@@ -28,6 +28,7 @@ class ConfigEditorController extends Controller
public function __construct()
{
parent::__construct(MODULESROOT.static::MODULE_NAME.'/templates', static::MODULE_NAME);
$this->SetDebugAllowed(false);
}
public function OperationEdit(): void

View File

@@ -30,7 +30,7 @@ SetupWebPage::AddModule(
// Identification
//
'label' => 'iTop Core Update',
'category' => 'business',
'category' => 'Application management',
// Setup
//

View File

@@ -1333,6 +1333,7 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:DashletGroupBy:Prop-GroupBy:DayOfMonth' => 'Day of month for %1$s',
'UI:DashletGroupBy:Prop-GroupBy:Select-Hour' => '%1$s (hour)',
'UI:DashletGroupBy:Prop-GroupBy:Select-Month' => '%1$s (month)',
'UI:DashletGroupBy:Prop-GroupBy:Select-Year' => '%1$s (year)',
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfWeek' => '%1$s (day of week)',
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfMonth' => '%1$s (day of month)',
'UI:DashletGroupBy:MissingGroupBy' => 'Please select the field on which the objects will be grouped together',

View File

@@ -1279,6 +1279,7 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
'UI:DashletGroupBy:Prop-GroupBy:DayOfMonth' => 'Jour du mois pour %1$s',
'UI:DashletGroupBy:Prop-GroupBy:Select-Hour' => '%1$s (heure)',
'UI:DashletGroupBy:Prop-GroupBy:Select-Month' => '%1$s (mois)',
'UI:DashletGroupBy:Prop-GroupBy:Select-Year' => '%1$s (année)',
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfWeek' => '%1$s (jour de la semaine)',
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfMonth' => '%1$s (jour du mois)',
'UI:DashletGroupBy:MissingGroupBy' => 'Veuillez sélectionner le champ sur lequel les objets seront groupés',

View File

@@ -19,8 +19,15 @@
*/
// Input
Dict::Add('EN US', 'English', 'English', [
'UI:Component:Input:ChangeNotAllowed' => 'This change is not allowed',
'UI:Component:Input:Password:DoesNotMatch' => 'Passwords do not match',
'UI:Component:Input:Set:MinimumItems' => 'Minimum %1$s item(s) required',
]);
Dict::Add(
'EN US',
'English',
'English',
[
'UI:Component:Input:ChangeNotAllowed' => 'This change is not allowed',
'UI:Component:Input:Password:DoesNotMatch' => 'Passwords do not match',
'UI:Component:Input:Set:MinimumItems' => 'Minimum %1$s item(s) required',
'UI:Component:Input:Select:Select_item' => 'Select an item...',
]
);

View File

@@ -10,8 +10,15 @@
/**
*
*/
Dict::Add('FR FR', 'French', 'Français', [
'UI:Component:Input:ChangeNotAllowed' => 'Cette modification n\'est pas autorisée',
'UI:Component:Input:Password:DoesNotMatch' => 'Les mots de passe ne correspondent pas',
'UI:Component:Input:Set:MinimumItems' => 'Minimum %1$s élément(s) requis',
]);
Dict::Add(
'FR FR',
'French',
'Français',
[
'UI:Component:Input:ChangeNotAllowed' => 'Cette modification n\'est pas autorisée',
'UI:Component:Input:Password:DoesNotMatch' => 'Les mots de passe ne correspondent pas',
'UI:Component:Input:Set:MinimumItems' => 'Minimum %1$s élément(s) requis',
'UI:Component:Input:Select:Select_item' => 'Sélectionnez un élément...',
]
);

View File

@@ -0,0 +1,45 @@
class ChoicesElement extends HTMLSelectElement {
// register the custom element
static {
customElements.define('choices-element', ChoicesElement, {extends: 'select'});
}
plugins = [];
connectedCallback() {
if (this.tomselect) {
return;
}
if (this.getAttribute('multiple')) {
this.plugins.push('remove_button');
}
const options = {
plugins: this.plugins,
wrapperClass: 'ts-wrapper ibo-input-wrapper ibo-input-select-wrapper--with-buttons ibo-input-select-autocomplete-wrapper',
controlClass: 'ts-control ibo-input ibo-input-select ibo-input-select-autocomplete',
dropdownParent: 'body',
render: {
dropdown: function (data, escape) {
return `<div class="selectize-dropdown"></div>`;
}
}
};
if (this.getAttribute('data-tom-select-disable-auto-complete')) {
// options.controlInput = null;
}
if (this.getAttribute('data-tom-select-max-items-selected') && this.getAttribute('data-tom-select-max-items-selected') !== '') {
options.maxItems = parseInt(this.getAttribute('data-tom-select-max-items-selected'));
}
if (this.getAttribute('data-tom-select-placehelder')) {
options.placeholder = this.getAttribute('data-tom-select-placehelder');
}
new TomSelect(this, options);
}
}

View File

@@ -0,0 +1,39 @@
class CollectionElement extends HTMLElement {
#eBtnAdd;
// register the custom element
static {
customElements.define('collection-element', CollectionElement);
}
addFormToCollection(e) {
const collectionHolder = document.querySelector('.'+e.currentTarget.dataset.collectionHolderClass);
const item = document.createElement('div');
const collectionHolderList = collectionHolder.querySelector('[role="list"]');
item.innerHTML = collectionHolder
.dataset
.prototype
.replace(
/__name__/g,
collectionHolder.dataset.index
);
collectionHolderList.appendChild(item.firstChild);
collectionHolder.dataset.index++;
this.querySelectorAll('collection-entry-element').forEach((entry) => {
console.log('test');
entry.updateButtonStates();
});
}
/** connectedCallback **/
connectedCallback() {
this.#eBtnAdd = this.querySelector('.add_item_link');
this.#eBtnAdd.addEventListener('click', this.addFormToCollection.bind(this));
}
}

View File

@@ -0,0 +1,112 @@
class CollectionEntryElement extends HTMLElement {
// Button elements
#eBtnDelete;
#eBtnMoveUp;
#eBtnMoveDown;
// register the custom element
static {
customElements.define('collection-entry-element', CollectionEntryElement);
}
/** connectedCallback **/
connectedCallback() {
if ((this.dataset.new || this.dataset.allowDelete) && this.#eBtnDelete === undefined) {
this.#eBtnDelete = this.#createButton('Remove', 'ibo-button ibo-is-regular ibo-is-danger');
this.#eBtnDelete.addEventListener('click', this.#removeCollectionItem.bind(this));
this.appendChild(this.#eBtnDelete);
}
if (this.dataset.allowOrdering) {
if (this.#eBtnMoveUp === undefined) {
this.#eBtnMoveUp = this.#createButton('Move Up', 'ibo-button ibo-is-regular');
this.#eBtnMoveUp.addEventListener('click', this.#moveUp.bind(this));
this.appendChild(this.#eBtnMoveUp);
}
if (this.#eBtnMoveDown === undefined) {
this.#eBtnMoveDown = this.#createButton('Move Down', 'ibo-button ibo-is-regular');
this.#eBtnMoveDown.addEventListener('click', this.#moveDown.bind(this));
this.appendChild(this.#eBtnMoveDown);
}
}
this.updateButtonStates();
}
/**
* Update the state of the buttons (enabled/disabled).
*
*/
updateButtonStates() {
if (this.dataset.allowOrdering) {
if (this.previousElementSibling === null) {
this.#eBtnMoveUp.setAttribute('disabled', 'disabled');
} else {
this.#eBtnMoveUp.removeAttribute('disabled');
}
if (this.nextElementSibling === null) {
this.#eBtnMoveDown.setAttribute('disabled', 'disabled');
} else {
this.#eBtnMoveDown.removeAttribute('disabled');
}
}
}
/**
* Create a button element.
*
* @param label
* @param className
* @returns {HTMLButtonElement}
*/
#createButton(label, className) {
const btnElement = document.createElement('button');
btnElement.type = 'button';
btnElement.className = className;
btnElement.textContent = label;
return btnElement;
}
/**
* Move this collection item up.
*
*/
#moveUp() {
const prev = this.previousElementSibling;
if (prev) {
this.parentNode.insertBefore(this, prev);
this.updateButtonStates();
prev.updateButtonStates();
}
}
/**
* Move this collection item down.
*
*/
#moveDown() {
const next = this.nextElementSibling;
if (next) {
this.parentNode.insertBefore(next, this);
this.updateButtonStates();
next.updateButtonStates();
}
}
/**
* Remove this collection item.
*
*/
#removeCollectionItem() {
this.remove();
}
}

View File

@@ -0,0 +1,90 @@
class FormElement extends HTMLFormElement
{
static #TURBO_REFRESHING_CLASS = 'turbo-refreshing';
static #TURBO_TRIGGER_FIELD = '_turbo_trigger';
#aFormBlockDataTransmittedData = {};
// register the custom element
static {
customElements.define('itop-form-element', FormElement, {extends: 'form'});
}
TriggerTurbo(oElement) {
// Get the name and id of the element triggering turbo
const sName = oElement.getAttribute('name');
const sId = oElement.getAttribute('id');
if(FormElement.IsCheckbox(oElement) || this.#aFormBlockDataTransmittedData[sName] !== oElement.value) {
// Refresh UI
this.#StartRefreshingUI(sId);
// Pre Submit
this.#PreSubmitTurboForm(sName);
// Submit
oElement.form.requestSubmit();
// Post Submit
this.#PostSubmitTurboForm(sName)
this.#aFormBlockDataTransmittedData[sName] = oElement.value;
}
}
/**
* Start refreshing UI.
*
* @param sId
* @constructor
*/
#StartRefreshingUI(sId)
{
Array.from(this.querySelectorAll(`.ibo-content-block[data-impacted-by*="${sId}"]`)).forEach(block => {
block.classList.add(FormElement.#TURBO_REFRESHING_CLASS);
});
}
/**
* Pre submit the form.
* Set the turbo trigger field in the form and disable validation
*
* @param sName
* @constructor
*/
#PreSubmitTurboForm(sName)
{
this.querySelector(`[name="${this.getAttribute("name")}[${FormElement.#TURBO_TRIGGER_FIELD}]"]`).value = sName;
this.setAttribute('novalidate', true);
}
/**
* Post submit the form.
* Reset the turbo trigger field and restore form validation.
*
* @param sName
* @constructor
*/
#PostSubmitTurboForm(sName)
{
this.querySelector(`[name="${this.getAttribute("name")}[${FormElement.#TURBO_TRIGGER_FIELD}]"]`).value = null;
this.removeAttribute('novalidate');
}
/**
*
* @param oElement
* @returns {boolean}
*/
static IsCheckbox (oElement)
{
return oElement instanceof HTMLInputElement
&& oElement.getAttribute('type') === 'checkbox'
}
}

View File

@@ -0,0 +1,70 @@
class OqlElement extends HTMLTextAreaElement {
// register the custom element
static{
customElements.define('oql-element', OqlElement, {extends: 'textarea'});
}
// variables
#url = '../pages/ajax.render.php?route=oql.validate_query';
#iconValid = 'fa-check-double';
#iconNotValid = 'fa-exclamation-triangle';
#debounceTimer = null;
#debounce = 300;
/** connectedCallback **/
connectedCallback() {
this.addEventListener('input', this.#onInput.bind(this));
this.#callValidateQuery();
}
/**
* Call oql verification with debounce when input event is fired.
*/
#onInput() {
if (this.#debounceTimer) clearTimeout(this.#debounceTimer);
this.#debounceTimer = setTimeout(() => {
this.#callValidateQuery(true);
}, this.#debounce);
}
/**
* Call the ajax to validate the query.
*
* @param fireChange flag to handle change event
*/
#callValidateQuery(fireChange = false) {
fetch(this.#url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Combodo-Ajax': true
},
body: JSON.stringify({
query: this.value
})
})
.then(response => response.json())
.then(response => {
// fire change event only if the query is valid
if (fireChange && response.is_valid){
this.#fireChangeEvent();
}
// update the icon color
const fieldEl = this.closest('.ibo-field');
const marqueeEl = fieldEl.querySelector('[role="marquee"]');
marqueeEl.style.color = response.is_valid ? 'green' : 'orange';
marqueeEl.classList.toggle(this.#iconNotValid, !response.is_valid);
marqueeEl.classList.toggle(this.#iconValid, response.is_valid);
});
}
/**
* Fire a change event.
*/
#fireChangeEvent() {
const changeEvent = new Event('change', { bubbles: true, cancelable: true });
this.dispatchEvent(changeEvent);
}
}

View File

@@ -0,0 +1,26 @@
class TurboStreamEvent extends HTMLElement {
// register the custom element
static {
customElements.define('turbo-stream-event', TurboStreamEvent);
}
constructor() {
super();
this.style.display = 'none';
const event = new CustomEvent("itop:TurboStreamEvent", {
detail: {
id: this.getAttribute('id'),
form_id: this.dataset.formId,
block_class: this.dataset.formBlockClass,
view_data: this.dataset.viewData,
valid: this.dataset.valid,
},
});
document.dispatchEvent(event);
}
}

View File

@@ -244,6 +244,10 @@ return array(
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarSpacer\\ToolbarSpacer' => $baseDir . '/sources/Application/UI/Base/Component/Toolbar/ToolbarSpacer/ToolbarSpacer.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarSpacer\\ToolbarSpacerUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Toolbar/ToolbarSpacer/ToolbarSpacerUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Toolbar/ToolbarUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboForm\\TurboForm' => $baseDir . '/sources/Application/UI/Base/Component/TurboForm/TurboForm.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboForm\\TurboFormUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/TurboForm/TurboFormUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboUpdate\\TurboStream' => $baseDir . '/sources/Application/UI/Base/Component/TurboStream/TurboStream.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboUpdate\\TurboStreamUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/TurboStream/TurboStreamUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntry' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/ActivityEntry.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntryFactory' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/ActivityEntryFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\CMDBChangeOp\\CMDBChangeOpAttachmentAddedFactory' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/CMDBChangeOp/CMDBChangeOpAttachmentAddedFactory.php',
@@ -341,6 +345,7 @@ return array(
'Combodo\\iTop\\Controller\\AjaxRenderController' => $baseDir . '/sources/Controller/AjaxRenderController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => $baseDir . '/sources/Controller/Base/Layout/ActivityPanelController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => $baseDir . '/sources/Controller/Base/Layout/ObjectController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\OqlController' => $baseDir . '/sources/Controller/Base/Layout/OqlController.php',
'Combodo\\iTop\\Controller\\Links\\LinkSetController' => $baseDir . '/sources/Controller/Links/LinkSetController.php',
'Combodo\\iTop\\Controller\\Newsroom\\iTopNewsroomController' => $baseDir . '/sources/Controller/Newsroom/iTopNewsroomController.php',
'Combodo\\iTop\\Controller\\Notifications\\ActionController' => $baseDir . '/sources/Controller/Notifications/ActionController.php',
@@ -473,8 +478,106 @@ return array(
'Combodo\\iTop\\Form\\Validator\\MultipleChoicesValidator' => $baseDir . '/sources/Form/Validator/MultipleChoicesValidator.php',
'Combodo\\iTop\\Form\\Validator\\NotEmptyExtKeyValidator' => $baseDir . '/sources/Form/Validator/NotEmptyExtKeyValidator.php',
'Combodo\\iTop\\Form\\Validator\\SelectObjectValidator' => $baseDir . '/sources/Form/Validator/SelectObjectValidator.php',
'Combodo\\iTop\\Forms\\Block\\AbstractFormBlock' => $baseDir . '/sources/Forms/Block/AbstractFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\AbstractTypeFormBlock' => $baseDir . '/sources/Forms/Block/AbstractTypeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\CheckboxFormBlock' => $baseDir . '/sources/Forms/Block/Base/CheckboxFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFromInputsBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceFromInputsBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\CollectionBlock' => $baseDir . '/sources/Forms/Block/Base/CollectionBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateFormBlock' => $baseDir . '/sources/Forms/Block/Base/DateFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateTimeFormBlock' => $baseDir . '/sources/Forms/Block/Base/DateTimeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\FormBlock' => $baseDir . '/sources/Forms/Block/Base/FormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\HiddenFormBlock' => $baseDir . '/sources/Forms/Block/Base/HiddenFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\IntegerFormBlock' => $baseDir . '/sources/Forms/Block/Base/IntegerFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\NumberFormBlock' => $baseDir . '/sources/Forms/Block/Base/NumberFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextAreaFormBlock' => $baseDir . '/sources/Forms/Block/Base/TextAreaFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextFormBlock' => $baseDir . '/sources/Forms/Block/Base/TextFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeTypeChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeTypeChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeValueChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeValueChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\Dashlet\\AggregateFunctionFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/Dashlet/AggregateFunctionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\Dashlet\\ClassAttributeGroupByFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/Dashlet/ClassAttributeGroupByFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\LabelFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/LabelFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\OqlFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/OqlFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\AbstractExpressionFormBlock' => $baseDir . '/sources/Forms/Block/Expression/AbstractExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\BooleanExpressionFormBlock' => $baseDir . '/sources/Forms/Block/Expression/BooleanExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\NumberExpressionFormBlock' => $baseDir . '/sources/Forms/Block/Expression/NumberExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\StringExpressionFormBlock' => $baseDir . '/sources/Forms/Block/Expression/StringExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockException' => $baseDir . '/sources/Forms/Block/FormBlockException.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockHelper' => $baseDir . '/sources/Forms/Block/FormBlockHelper.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockService' => $baseDir . '/sources/Forms/Block/FormBlockService.php',
'Combodo\\iTop\\Forms\\Block\\IFormBlock' => $baseDir . '/sources/Forms/Block/IFormBlock.php',
'Combodo\\iTop\\Forms\\Compiler\\FormsCompiler' => $baseDir . '/sources/Forms/Compiler/FormsCompiler.php',
'Combodo\\iTop\\Forms\\Compiler\\FormsCompilerException' => $baseDir . '/sources/Forms/Compiler/FormsCompilerException.php',
'Combodo\\iTop\\Forms\\Controller\\FormsController' => $baseDir . '/sources/Forms/Controller/FormsController.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyHandler' => $baseDir . '/sources/Forms/FormBuilder/DependencyHandler.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => $baseDir . '/sources/Forms/FormBuilder/DependencyMap.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormBuilder' => $baseDir . '/sources/Forms/FormBuilder/FormBuilder.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormBuilderException' => $baseDir . '/sources/Forms/FormBuilder/FormBuilderException.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormHelper' => $baseDir . '/sources/Forms/FormBuilder/FormHelper.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormTypeExtension' => $baseDir . '/sources/Forms/FormBuilder/FormTypeExtension.php',
'Combodo\\iTop\\Forms\\FormBuilder\\ResolvedFormType' => $baseDir . '/sources/Forms/FormBuilder/ResolvedFormType.php',
'Combodo\\iTop\\Forms\\FormBuilder\\ResolvedFormTypeFactory' => $baseDir . '/sources/Forms/FormBuilder/ResolvedFormTypeFactory.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\ChoiceFormType' => $baseDir . '/sources/Forms/FormType/Base/ChoiceFormType.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\CollectionFormType' => $baseDir . '/sources/Forms/FormType/Base/CollectionFormType.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\FormType' => $baseDir . '/sources/Forms/FormType/Base/FormType.php',
'Combodo\\iTop\\Forms\\FormType\\DataModel\\OqlFormType' => $baseDir . '/sources/Forms/FormType/DataModel/OqlFormType.php',
'Combodo\\iTop\\Forms\\FormType\\FormTypeHelper' => $baseDir . '/sources/Forms/FormType/FormTypeHelper.php',
'Combodo\\iTop\\Forms\\Forms' => $baseDir . '/sources/Forms/Forms.php',
'Combodo\\iTop\\Forms\\FormsException' => $baseDir . '/sources/Forms/FormsException.php',
'Combodo\\iTop\\Forms\\IO\\AbstractFormIO' => $baseDir . '/sources/Forms/IO/AbstractFormIO.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\AbstractConverter' => $baseDir . '/sources/Forms/IO/Converter/AbstractConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\ChoiceValueToLabelConverter' => $baseDir . '/sources/Forms/IO/Converter/ChoiceValueToLabelConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\OqlToClassConverter' => $baseDir . '/sources/Forms/IO/Converter/OqlToClassConverter.php',
'Combodo\\iTop\\Forms\\IO\\FormBinding' => $baseDir . '/sources/Forms/IO/FormBinding.php',
'Combodo\\iTop\\Forms\\IO\\FormBlockIOException' => $baseDir . '/sources/Forms/IO/FormBlockIOException.php',
'Combodo\\iTop\\Forms\\IO\\FormInput' => $baseDir . '/sources/Forms/IO/FormInput.php',
'Combodo\\iTop\\Forms\\IO\\FormOutput' => $baseDir . '/sources/Forms/IO/FormOutput.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AbstractIOFormat' => $baseDir . '/sources/Forms/IO/Format/AbstractIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeIOFormat' => $baseDir . '/sources/Forms/IO/Format/AttributeIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeTypeArrayIOFormat' => $baseDir . '/sources/Forms/IO/Format/AttributeTypeArrayIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeTypeIOFormat' => $baseDir . '/sources/Forms/IO/Format/AttributeTypeIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\BooleanIOFormat' => $baseDir . '/sources/Forms/IO/Format/BooleanIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\ClassIOFormat' => $baseDir . '/sources/Forms/IO/Format/ClassIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\IntegerIOFormat' => $baseDir . '/sources/Forms/IO/Format/IntegerIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\NumberIOFormat' => $baseDir . '/sources/Forms/IO/Format/NumberIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\StringIOFormat' => $baseDir . '/sources/Forms/IO/Format/StringIOFormat.php',
'Combodo\\iTop\\Forms\\Register\\IORegister' => $baseDir . '/sources/Forms/Register/IORegister.php',
'Combodo\\iTop\\Forms\\Register\\Option' => $baseDir . '/sources/Forms/Register/Option.php',
'Combodo\\iTop\\Forms\\Register\\OptionsRegister' => $baseDir . '/sources/Forms/Register/OptionsRegister.php',
'Combodo\\iTop\\Forms\\Register\\RegisterException' => $baseDir . '/sources/Forms/Register/RegisterException.php',
'Combodo\\iTop\\Forms\\Twig\\Extension\\FormCompatibilityExtension' => $baseDir . '/sources/Forms/Twig/Extension/FormCompatibilityExtension.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExist' => $baseDir . '/sources/Forms/Validator/AttributeExist.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExistValidator' => $baseDir . '/sources/Forms/Validator/AttributeExistValidator.php',
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
'Combodo\\iTop\\PropertyTree\\AbstractProperty' => $baseDir . '/sources/PropertyTree/AbstractProperty.php',
'Combodo\\iTop\\PropertyTree\\CollectionOfTrees' => $baseDir . '/sources/PropertyTree/CollectionOfTrees.php',
'Combodo\\iTop\\PropertyTree\\CollectionOfValues' => $baseDir . '/sources/PropertyTree/CollectionOfValues.php',
'Combodo\\iTop\\PropertyTree\\CollectionType\\AbstractCollectionType' => $baseDir . '/sources/PropertyTree/CollectionType/AbstractCollectionType.php',
'Combodo\\iTop\\PropertyTree\\CollectionType\\CollectionTypeCollection' => $baseDir . '/sources/PropertyTree/CollectionType/CollectionTypeCollection.php',
'Combodo\\iTop\\PropertyTree\\CollectionType\\CollectionTypeFactory' => $baseDir . '/sources/PropertyTree/CollectionType/CollectionTypeFactory.php',
'Combodo\\iTop\\PropertyTree\\Property' => $baseDir . '/sources/PropertyTree/Property.php',
'Combodo\\iTop\\PropertyTree\\PropertyTree' => $baseDir . '/sources/PropertyTree/PropertyTree.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeDesign' => $baseDir . '/sources/PropertyTree/PropertyTreeDesign.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeException' => $baseDir . '/sources/PropertyTree/PropertyTreeException.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeFactory' => $baseDir . '/sources/PropertyTree/PropertyTreeFactory.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\AbstractValueType' => $baseDir . '/sources/PropertyTree/ValueType/AbstractValueType.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeAggregateFunction' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeAggregateFunction.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeBoolean' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeBoolean.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeChoice' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeChoice.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeChoiceFromInput' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeChoiceFromInput.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClass' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeClass.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttribute' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeClassAttribute.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttributeGroupBy' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeClassAttributeGroupBy.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttributeValue' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeClassAttributeValue.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeFactory' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeFactory.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeIcon' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeIcon.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeInteger' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeInteger.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeLabel' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeLabel.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeOQL' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeOQL.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeProfileName' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeProfileName.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeString' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeString.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeText' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeText.php',
'Combodo\\iTop\\Renderer\\BlockRenderer' => $baseDir . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => $baseDir . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => $baseDir . '/sources/Renderer/Bootstrap/BsFormRenderer.php',
@@ -497,6 +600,8 @@ return array(
'Combodo\\iTop\\Service\\Base\\ObjectRepository' => $baseDir . '/sources/Service/Base/ObjectRepository.php',
'Combodo\\iTop\\Service\\Base\\iDataPostProcessor' => $baseDir . '/sources/Service/Base/iDataPostProcessor.php',
'Combodo\\iTop\\Service\\Cache\\DataModelDependantCache' => $baseDir . '/sources/Service/Cache/DataModelDependantCache.php',
'Combodo\\iTop\\Service\\DependencyInjection\\DIException' => $baseDir . '/sources/Service/DependencyInjection/DIException.php',
'Combodo\\iTop\\Service\\DependencyInjection\\DIService' => $baseDir . '/sources/Service/DependencyInjection/DIService.php',
'Combodo\\iTop\\Service\\Events\\Description\\EventDataDescription' => $baseDir . '/sources/Service/Events/Description/EventDataDescription.php',
'Combodo\\iTop\\Service\\Events\\Description\\EventDescription' => $baseDir . '/sources/Service/Events/Description/EventDescription.php',
'Combodo\\iTop\\Service\\Events\\EventData' => $baseDir . '/sources/Service/Events/EventData.php',
@@ -3071,6 +3176,227 @@ return array(
'Symfony\\Component\\String\\Slugger\\AsciiSlugger' => $vendorDir . '/symfony/string/Slugger/AsciiSlugger.php',
'Symfony\\Component\\String\\Slugger\\SluggerInterface' => $vendorDir . '/symfony/string/Slugger/SluggerInterface.php',
'Symfony\\Component\\String\\UnicodeString' => $vendorDir . '/symfony/string/UnicodeString.php',
'Symfony\\Component\\Validator\\Attribute\\HasNamedArguments' => $vendorDir . '/symfony/validator/Attribute/HasNamedArguments.php',
'Symfony\\Component\\Validator\\Command\\DebugCommand' => $vendorDir . '/symfony/validator/Command/DebugCommand.php',
'Symfony\\Component\\Validator\\Constraint' => $vendorDir . '/symfony/validator/Constraint.php',
'Symfony\\Component\\Validator\\ConstraintValidator' => $vendorDir . '/symfony/validator/ConstraintValidator.php',
'Symfony\\Component\\Validator\\ConstraintValidatorFactory' => $vendorDir . '/symfony/validator/ConstraintValidatorFactory.php',
'Symfony\\Component\\Validator\\ConstraintValidatorFactoryInterface' => $vendorDir . '/symfony/validator/ConstraintValidatorFactoryInterface.php',
'Symfony\\Component\\Validator\\ConstraintValidatorInterface' => $vendorDir . '/symfony/validator/ConstraintValidatorInterface.php',
'Symfony\\Component\\Validator\\ConstraintViolation' => $vendorDir . '/symfony/validator/ConstraintViolation.php',
'Symfony\\Component\\Validator\\ConstraintViolationInterface' => $vendorDir . '/symfony/validator/ConstraintViolationInterface.php',
'Symfony\\Component\\Validator\\ConstraintViolationList' => $vendorDir . '/symfony/validator/ConstraintViolationList.php',
'Symfony\\Component\\Validator\\ConstraintViolationListInterface' => $vendorDir . '/symfony/validator/ConstraintViolationListInterface.php',
'Symfony\\Component\\Validator\\Constraints\\AbstractComparison' => $vendorDir . '/symfony/validator/Constraints/AbstractComparison.php',
'Symfony\\Component\\Validator\\Constraints\\AbstractComparisonValidator' => $vendorDir . '/symfony/validator/Constraints/AbstractComparisonValidator.php',
'Symfony\\Component\\Validator\\Constraints\\All' => $vendorDir . '/symfony/validator/Constraints/All.php',
'Symfony\\Component\\Validator\\Constraints\\AllValidator' => $vendorDir . '/symfony/validator/Constraints/AllValidator.php',
'Symfony\\Component\\Validator\\Constraints\\AtLeastOneOf' => $vendorDir . '/symfony/validator/Constraints/AtLeastOneOf.php',
'Symfony\\Component\\Validator\\Constraints\\AtLeastOneOfValidator' => $vendorDir . '/symfony/validator/Constraints/AtLeastOneOfValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Bic' => $vendorDir . '/symfony/validator/Constraints/Bic.php',
'Symfony\\Component\\Validator\\Constraints\\BicValidator' => $vendorDir . '/symfony/validator/Constraints/BicValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Blank' => $vendorDir . '/symfony/validator/Constraints/Blank.php',
'Symfony\\Component\\Validator\\Constraints\\BlankValidator' => $vendorDir . '/symfony/validator/Constraints/BlankValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Callback' => $vendorDir . '/symfony/validator/Constraints/Callback.php',
'Symfony\\Component\\Validator\\Constraints\\CallbackValidator' => $vendorDir . '/symfony/validator/Constraints/CallbackValidator.php',
'Symfony\\Component\\Validator\\Constraints\\CardScheme' => $vendorDir . '/symfony/validator/Constraints/CardScheme.php',
'Symfony\\Component\\Validator\\Constraints\\CardSchemeValidator' => $vendorDir . '/symfony/validator/Constraints/CardSchemeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Cascade' => $vendorDir . '/symfony/validator/Constraints/Cascade.php',
'Symfony\\Component\\Validator\\Constraints\\Choice' => $vendorDir . '/symfony/validator/Constraints/Choice.php',
'Symfony\\Component\\Validator\\Constraints\\ChoiceValidator' => $vendorDir . '/symfony/validator/Constraints/ChoiceValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Cidr' => $vendorDir . '/symfony/validator/Constraints/Cidr.php',
'Symfony\\Component\\Validator\\Constraints\\CidrValidator' => $vendorDir . '/symfony/validator/Constraints/CidrValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Collection' => $vendorDir . '/symfony/validator/Constraints/Collection.php',
'Symfony\\Component\\Validator\\Constraints\\CollectionValidator' => $vendorDir . '/symfony/validator/Constraints/CollectionValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Composite' => $vendorDir . '/symfony/validator/Constraints/Composite.php',
'Symfony\\Component\\Validator\\Constraints\\Compound' => $vendorDir . '/symfony/validator/Constraints/Compound.php',
'Symfony\\Component\\Validator\\Constraints\\CompoundValidator' => $vendorDir . '/symfony/validator/Constraints/CompoundValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Count' => $vendorDir . '/symfony/validator/Constraints/Count.php',
'Symfony\\Component\\Validator\\Constraints\\CountValidator' => $vendorDir . '/symfony/validator/Constraints/CountValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Country' => $vendorDir . '/symfony/validator/Constraints/Country.php',
'Symfony\\Component\\Validator\\Constraints\\CountryValidator' => $vendorDir . '/symfony/validator/Constraints/CountryValidator.php',
'Symfony\\Component\\Validator\\Constraints\\CssColor' => $vendorDir . '/symfony/validator/Constraints/CssColor.php',
'Symfony\\Component\\Validator\\Constraints\\CssColorValidator' => $vendorDir . '/symfony/validator/Constraints/CssColorValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Currency' => $vendorDir . '/symfony/validator/Constraints/Currency.php',
'Symfony\\Component\\Validator\\Constraints\\CurrencyValidator' => $vendorDir . '/symfony/validator/Constraints/CurrencyValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Date' => $vendorDir . '/symfony/validator/Constraints/Date.php',
'Symfony\\Component\\Validator\\Constraints\\DateTime' => $vendorDir . '/symfony/validator/Constraints/DateTime.php',
'Symfony\\Component\\Validator\\Constraints\\DateTimeValidator' => $vendorDir . '/symfony/validator/Constraints/DateTimeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\DateValidator' => $vendorDir . '/symfony/validator/Constraints/DateValidator.php',
'Symfony\\Component\\Validator\\Constraints\\DisableAutoMapping' => $vendorDir . '/symfony/validator/Constraints/DisableAutoMapping.php',
'Symfony\\Component\\Validator\\Constraints\\DivisibleBy' => $vendorDir . '/symfony/validator/Constraints/DivisibleBy.php',
'Symfony\\Component\\Validator\\Constraints\\DivisibleByValidator' => $vendorDir . '/symfony/validator/Constraints/DivisibleByValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Email' => $vendorDir . '/symfony/validator/Constraints/Email.php',
'Symfony\\Component\\Validator\\Constraints\\EmailValidator' => $vendorDir . '/symfony/validator/Constraints/EmailValidator.php',
'Symfony\\Component\\Validator\\Constraints\\EnableAutoMapping' => $vendorDir . '/symfony/validator/Constraints/EnableAutoMapping.php',
'Symfony\\Component\\Validator\\Constraints\\EqualTo' => $vendorDir . '/symfony/validator/Constraints/EqualTo.php',
'Symfony\\Component\\Validator\\Constraints\\EqualToValidator' => $vendorDir . '/symfony/validator/Constraints/EqualToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Existence' => $vendorDir . '/symfony/validator/Constraints/Existence.php',
'Symfony\\Component\\Validator\\Constraints\\Expression' => $vendorDir . '/symfony/validator/Constraints/Expression.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageProvider' => $vendorDir . '/symfony/validator/Constraints/ExpressionLanguageProvider.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntax' => $vendorDir . '/symfony/validator/Constraints/ExpressionLanguageSyntax.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntaxValidator' => $vendorDir . '/symfony/validator/Constraints/ExpressionLanguageSyntaxValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionSyntax' => $vendorDir . '/symfony/validator/Constraints/ExpressionSyntax.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionSyntaxValidator' => $vendorDir . '/symfony/validator/Constraints/ExpressionSyntaxValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionValidator' => $vendorDir . '/symfony/validator/Constraints/ExpressionValidator.php',
'Symfony\\Component\\Validator\\Constraints\\File' => $vendorDir . '/symfony/validator/Constraints/File.php',
'Symfony\\Component\\Validator\\Constraints\\FileValidator' => $vendorDir . '/symfony/validator/Constraints/FileValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThan' => $vendorDir . '/symfony/validator/Constraints/GreaterThan.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqual' => $vendorDir . '/symfony/validator/Constraints/GreaterThanOrEqual.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqualValidator' => $vendorDir . '/symfony/validator/Constraints/GreaterThanOrEqualValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanValidator' => $vendorDir . '/symfony/validator/Constraints/GreaterThanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GroupSequence' => $vendorDir . '/symfony/validator/Constraints/GroupSequence.php',
'Symfony\\Component\\Validator\\Constraints\\GroupSequenceProvider' => $vendorDir . '/symfony/validator/Constraints/GroupSequenceProvider.php',
'Symfony\\Component\\Validator\\Constraints\\Hostname' => $vendorDir . '/symfony/validator/Constraints/Hostname.php',
'Symfony\\Component\\Validator\\Constraints\\HostnameValidator' => $vendorDir . '/symfony/validator/Constraints/HostnameValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Iban' => $vendorDir . '/symfony/validator/Constraints/Iban.php',
'Symfony\\Component\\Validator\\Constraints\\IbanValidator' => $vendorDir . '/symfony/validator/Constraints/IbanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IdenticalTo' => $vendorDir . '/symfony/validator/Constraints/IdenticalTo.php',
'Symfony\\Component\\Validator\\Constraints\\IdenticalToValidator' => $vendorDir . '/symfony/validator/Constraints/IdenticalToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Image' => $vendorDir . '/symfony/validator/Constraints/Image.php',
'Symfony\\Component\\Validator\\Constraints\\ImageValidator' => $vendorDir . '/symfony/validator/Constraints/ImageValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Ip' => $vendorDir . '/symfony/validator/Constraints/Ip.php',
'Symfony\\Component\\Validator\\Constraints\\IpValidator' => $vendorDir . '/symfony/validator/Constraints/IpValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsFalse' => $vendorDir . '/symfony/validator/Constraints/IsFalse.php',
'Symfony\\Component\\Validator\\Constraints\\IsFalseValidator' => $vendorDir . '/symfony/validator/Constraints/IsFalseValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsNull' => $vendorDir . '/symfony/validator/Constraints/IsNull.php',
'Symfony\\Component\\Validator\\Constraints\\IsNullValidator' => $vendorDir . '/symfony/validator/Constraints/IsNullValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsTrue' => $vendorDir . '/symfony/validator/Constraints/IsTrue.php',
'Symfony\\Component\\Validator\\Constraints\\IsTrueValidator' => $vendorDir . '/symfony/validator/Constraints/IsTrueValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Isbn' => $vendorDir . '/symfony/validator/Constraints/Isbn.php',
'Symfony\\Component\\Validator\\Constraints\\IsbnValidator' => $vendorDir . '/symfony/validator/Constraints/IsbnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Isin' => $vendorDir . '/symfony/validator/Constraints/Isin.php',
'Symfony\\Component\\Validator\\Constraints\\IsinValidator' => $vendorDir . '/symfony/validator/Constraints/IsinValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Issn' => $vendorDir . '/symfony/validator/Constraints/Issn.php',
'Symfony\\Component\\Validator\\Constraints\\IssnValidator' => $vendorDir . '/symfony/validator/Constraints/IssnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Json' => $vendorDir . '/symfony/validator/Constraints/Json.php',
'Symfony\\Component\\Validator\\Constraints\\JsonValidator' => $vendorDir . '/symfony/validator/Constraints/JsonValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Language' => $vendorDir . '/symfony/validator/Constraints/Language.php',
'Symfony\\Component\\Validator\\Constraints\\LanguageValidator' => $vendorDir . '/symfony/validator/Constraints/LanguageValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Length' => $vendorDir . '/symfony/validator/Constraints/Length.php',
'Symfony\\Component\\Validator\\Constraints\\LengthValidator' => $vendorDir . '/symfony/validator/Constraints/LengthValidator.php',
'Symfony\\Component\\Validator\\Constraints\\LessThan' => $vendorDir . '/symfony/validator/Constraints/LessThan.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanOrEqual' => $vendorDir . '/symfony/validator/Constraints/LessThanOrEqual.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanOrEqualValidator' => $vendorDir . '/symfony/validator/Constraints/LessThanOrEqualValidator.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanValidator' => $vendorDir . '/symfony/validator/Constraints/LessThanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Locale' => $vendorDir . '/symfony/validator/Constraints/Locale.php',
'Symfony\\Component\\Validator\\Constraints\\LocaleValidator' => $vendorDir . '/symfony/validator/Constraints/LocaleValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Luhn' => $vendorDir . '/symfony/validator/Constraints/Luhn.php',
'Symfony\\Component\\Validator\\Constraints\\LuhnValidator' => $vendorDir . '/symfony/validator/Constraints/LuhnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Negative' => $vendorDir . '/symfony/validator/Constraints/Negative.php',
'Symfony\\Component\\Validator\\Constraints\\NegativeOrZero' => $vendorDir . '/symfony/validator/Constraints/NegativeOrZero.php',
'Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharacters' => $vendorDir . '/symfony/validator/Constraints/NoSuspiciousCharacters.php',
'Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharactersValidator' => $vendorDir . '/symfony/validator/Constraints/NoSuspiciousCharactersValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotBlank' => $vendorDir . '/symfony/validator/Constraints/NotBlank.php',
'Symfony\\Component\\Validator\\Constraints\\NotBlankValidator' => $vendorDir . '/symfony/validator/Constraints/NotBlankValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotCompromisedPassword' => $vendorDir . '/symfony/validator/Constraints/NotCompromisedPassword.php',
'Symfony\\Component\\Validator\\Constraints\\NotCompromisedPasswordValidator' => $vendorDir . '/symfony/validator/Constraints/NotCompromisedPasswordValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotEqualTo' => $vendorDir . '/symfony/validator/Constraints/NotEqualTo.php',
'Symfony\\Component\\Validator\\Constraints\\NotEqualToValidator' => $vendorDir . '/symfony/validator/Constraints/NotEqualToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotIdenticalTo' => $vendorDir . '/symfony/validator/Constraints/NotIdenticalTo.php',
'Symfony\\Component\\Validator\\Constraints\\NotIdenticalToValidator' => $vendorDir . '/symfony/validator/Constraints/NotIdenticalToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotNull' => $vendorDir . '/symfony/validator/Constraints/NotNull.php',
'Symfony\\Component\\Validator\\Constraints\\NotNullValidator' => $vendorDir . '/symfony/validator/Constraints/NotNullValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Optional' => $vendorDir . '/symfony/validator/Constraints/Optional.php',
'Symfony\\Component\\Validator\\Constraints\\PasswordStrength' => $vendorDir . '/symfony/validator/Constraints/PasswordStrength.php',
'Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator' => $vendorDir . '/symfony/validator/Constraints/PasswordStrengthValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Positive' => $vendorDir . '/symfony/validator/Constraints/Positive.php',
'Symfony\\Component\\Validator\\Constraints\\PositiveOrZero' => $vendorDir . '/symfony/validator/Constraints/PositiveOrZero.php',
'Symfony\\Component\\Validator\\Constraints\\Range' => $vendorDir . '/symfony/validator/Constraints/Range.php',
'Symfony\\Component\\Validator\\Constraints\\RangeValidator' => $vendorDir . '/symfony/validator/Constraints/RangeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Regex' => $vendorDir . '/symfony/validator/Constraints/Regex.php',
'Symfony\\Component\\Validator\\Constraints\\RegexValidator' => $vendorDir . '/symfony/validator/Constraints/RegexValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Required' => $vendorDir . '/symfony/validator/Constraints/Required.php',
'Symfony\\Component\\Validator\\Constraints\\Sequentially' => $vendorDir . '/symfony/validator/Constraints/Sequentially.php',
'Symfony\\Component\\Validator\\Constraints\\SequentiallyValidator' => $vendorDir . '/symfony/validator/Constraints/SequentiallyValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Time' => $vendorDir . '/symfony/validator/Constraints/Time.php',
'Symfony\\Component\\Validator\\Constraints\\TimeValidator' => $vendorDir . '/symfony/validator/Constraints/TimeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Timezone' => $vendorDir . '/symfony/validator/Constraints/Timezone.php',
'Symfony\\Component\\Validator\\Constraints\\TimezoneValidator' => $vendorDir . '/symfony/validator/Constraints/TimezoneValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Traverse' => $vendorDir . '/symfony/validator/Constraints/Traverse.php',
'Symfony\\Component\\Validator\\Constraints\\Type' => $vendorDir . '/symfony/validator/Constraints/Type.php',
'Symfony\\Component\\Validator\\Constraints\\TypeValidator' => $vendorDir . '/symfony/validator/Constraints/TypeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Ulid' => $vendorDir . '/symfony/validator/Constraints/Ulid.php',
'Symfony\\Component\\Validator\\Constraints\\UlidValidator' => $vendorDir . '/symfony/validator/Constraints/UlidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Unique' => $vendorDir . '/symfony/validator/Constraints/Unique.php',
'Symfony\\Component\\Validator\\Constraints\\UniqueValidator' => $vendorDir . '/symfony/validator/Constraints/UniqueValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Url' => $vendorDir . '/symfony/validator/Constraints/Url.php',
'Symfony\\Component\\Validator\\Constraints\\UrlValidator' => $vendorDir . '/symfony/validator/Constraints/UrlValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Uuid' => $vendorDir . '/symfony/validator/Constraints/Uuid.php',
'Symfony\\Component\\Validator\\Constraints\\UuidValidator' => $vendorDir . '/symfony/validator/Constraints/UuidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Valid' => $vendorDir . '/symfony/validator/Constraints/Valid.php',
'Symfony\\Component\\Validator\\Constraints\\ValidValidator' => $vendorDir . '/symfony/validator/Constraints/ValidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\When' => $vendorDir . '/symfony/validator/Constraints/When.php',
'Symfony\\Component\\Validator\\Constraints\\WhenValidator' => $vendorDir . '/symfony/validator/Constraints/WhenValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ZeroComparisonConstraintTrait' => $vendorDir . '/symfony/validator/Constraints/ZeroComparisonConstraintTrait.php',
'Symfony\\Component\\Validator\\ContainerConstraintValidatorFactory' => $vendorDir . '/symfony/validator/ContainerConstraintValidatorFactory.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContext' => $vendorDir . '/symfony/validator/Context/ExecutionContext.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextFactory' => $vendorDir . '/symfony/validator/Context/ExecutionContextFactory.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextFactoryInterface' => $vendorDir . '/symfony/validator/Context/ExecutionContextFactoryInterface.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextInterface' => $vendorDir . '/symfony/validator/Context/ExecutionContextInterface.php',
'Symfony\\Component\\Validator\\DataCollector\\ValidatorDataCollector' => $vendorDir . '/symfony/validator/DataCollector/ValidatorDataCollector.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddAutoMappingConfigurationPass' => $vendorDir . '/symfony/validator/DependencyInjection/AddAutoMappingConfigurationPass.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddConstraintValidatorsPass' => $vendorDir . '/symfony/validator/DependencyInjection/AddConstraintValidatorsPass.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddValidatorInitializersPass' => $vendorDir . '/symfony/validator/DependencyInjection/AddValidatorInitializersPass.php',
'Symfony\\Component\\Validator\\Exception\\BadMethodCallException' => $vendorDir . '/symfony/validator/Exception/BadMethodCallException.php',
'Symfony\\Component\\Validator\\Exception\\ConstraintDefinitionException' => $vendorDir . '/symfony/validator/Exception/ConstraintDefinitionException.php',
'Symfony\\Component\\Validator\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/validator/Exception/ExceptionInterface.php',
'Symfony\\Component\\Validator\\Exception\\GroupDefinitionException' => $vendorDir . '/symfony/validator/Exception/GroupDefinitionException.php',
'Symfony\\Component\\Validator\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/validator/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Validator\\Exception\\InvalidOptionsException' => $vendorDir . '/symfony/validator/Exception/InvalidOptionsException.php',
'Symfony\\Component\\Validator\\Exception\\LogicException' => $vendorDir . '/symfony/validator/Exception/LogicException.php',
'Symfony\\Component\\Validator\\Exception\\MappingException' => $vendorDir . '/symfony/validator/Exception/MappingException.php',
'Symfony\\Component\\Validator\\Exception\\MissingOptionsException' => $vendorDir . '/symfony/validator/Exception/MissingOptionsException.php',
'Symfony\\Component\\Validator\\Exception\\NoSuchMetadataException' => $vendorDir . '/symfony/validator/Exception/NoSuchMetadataException.php',
'Symfony\\Component\\Validator\\Exception\\OutOfBoundsException' => $vendorDir . '/symfony/validator/Exception/OutOfBoundsException.php',
'Symfony\\Component\\Validator\\Exception\\RuntimeException' => $vendorDir . '/symfony/validator/Exception/RuntimeException.php',
'Symfony\\Component\\Validator\\Exception\\UnexpectedTypeException' => $vendorDir . '/symfony/validator/Exception/UnexpectedTypeException.php',
'Symfony\\Component\\Validator\\Exception\\UnexpectedValueException' => $vendorDir . '/symfony/validator/Exception/UnexpectedValueException.php',
'Symfony\\Component\\Validator\\Exception\\UnsupportedMetadataException' => $vendorDir . '/symfony/validator/Exception/UnsupportedMetadataException.php',
'Symfony\\Component\\Validator\\Exception\\ValidationFailedException' => $vendorDir . '/symfony/validator/Exception/ValidationFailedException.php',
'Symfony\\Component\\Validator\\Exception\\ValidatorException' => $vendorDir . '/symfony/validator/Exception/ValidatorException.php',
'Symfony\\Component\\Validator\\GroupProviderInterface' => $vendorDir . '/symfony/validator/GroupProviderInterface.php',
'Symfony\\Component\\Validator\\GroupSequenceProviderInterface' => $vendorDir . '/symfony/validator/GroupSequenceProviderInterface.php',
'Symfony\\Component\\Validator\\Mapping\\AutoMappingStrategy' => $vendorDir . '/symfony/validator/Mapping/AutoMappingStrategy.php',
'Symfony\\Component\\Validator\\Mapping\\CascadingStrategy' => $vendorDir . '/symfony/validator/Mapping/CascadingStrategy.php',
'Symfony\\Component\\Validator\\Mapping\\ClassMetadata' => $vendorDir . '/symfony/validator/Mapping/ClassMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\ClassMetadataInterface' => $vendorDir . '/symfony/validator/Mapping/ClassMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\BlackHoleMetadataFactory' => $vendorDir . '/symfony/validator/Mapping/Factory/BlackHoleMetadataFactory.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\LazyLoadingMetadataFactory' => $vendorDir . '/symfony/validator/Mapping/Factory/LazyLoadingMetadataFactory.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\MetadataFactoryInterface' => $vendorDir . '/symfony/validator/Mapping/Factory/MetadataFactoryInterface.php',
'Symfony\\Component\\Validator\\Mapping\\GenericMetadata' => $vendorDir . '/symfony/validator/Mapping/GenericMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\GetterMetadata' => $vendorDir . '/symfony/validator/Mapping/GetterMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AbstractLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/AbstractLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AnnotationLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/AnnotationLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AttributeLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/AttributeLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AutoMappingTrait' => $vendorDir . '/symfony/validator/Mapping/Loader/AutoMappingTrait.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\FileLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/FileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\FilesLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/FilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\LoaderChain' => $vendorDir . '/symfony/validator/Mapping/Loader/LoaderChain.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\LoaderInterface' => $vendorDir . '/symfony/validator/Mapping/Loader/LoaderInterface.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\PropertyInfoLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/PropertyInfoLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\StaticMethodLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/StaticMethodLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\XmlFileLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/XmlFileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\XmlFilesLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/XmlFilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\YamlFileLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/YamlFileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\YamlFilesLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/YamlFilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\MemberMetadata' => $vendorDir . '/symfony/validator/Mapping/MemberMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\MetadataInterface' => $vendorDir . '/symfony/validator/Mapping/MetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadata' => $vendorDir . '/symfony/validator/Mapping/PropertyMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface' => $vendorDir . '/symfony/validator/Mapping/PropertyMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\TraversalStrategy' => $vendorDir . '/symfony/validator/Mapping/TraversalStrategy.php',
'Symfony\\Component\\Validator\\ObjectInitializerInterface' => $vendorDir . '/symfony/validator/ObjectInitializerInterface.php',
'Symfony\\Component\\Validator\\Util\\PropertyPath' => $vendorDir . '/symfony/validator/Util/PropertyPath.php',
'Symfony\\Component\\Validator\\Validation' => $vendorDir . '/symfony/validator/Validation.php',
'Symfony\\Component\\Validator\\ValidatorBuilder' => $vendorDir . '/symfony/validator/ValidatorBuilder.php',
'Symfony\\Component\\Validator\\Validator\\ContextualValidatorInterface' => $vendorDir . '/symfony/validator/Validator/ContextualValidatorInterface.php',
'Symfony\\Component\\Validator\\Validator\\LazyProperty' => $vendorDir . '/symfony/validator/Validator/LazyProperty.php',
'Symfony\\Component\\Validator\\Validator\\RecursiveContextualValidator' => $vendorDir . '/symfony/validator/Validator/RecursiveContextualValidator.php',
'Symfony\\Component\\Validator\\Validator\\RecursiveValidator' => $vendorDir . '/symfony/validator/Validator/RecursiveValidator.php',
'Symfony\\Component\\Validator\\Validator\\TraceableValidator' => $vendorDir . '/symfony/validator/Validator/TraceableValidator.php',
'Symfony\\Component\\Validator\\Validator\\ValidatorInterface' => $vendorDir . '/symfony/validator/Validator/ValidatorInterface.php',
'Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilder' => $vendorDir . '/symfony/validator/Violation/ConstraintViolationBuilder.php',
'Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilderInterface' => $vendorDir . '/symfony/validator/Violation/ConstraintViolationBuilderInterface.php',
'Symfony\\Component\\VarDumper\\Caster\\AmqpCaster' => $vendorDir . '/symfony/var-dumper/Caster/AmqpCaster.php',
'Symfony\\Component\\VarDumper\\Caster\\ArgsStub' => $vendorDir . '/symfony/var-dumper/Caster/ArgsStub.php',
'Symfony\\Component\\VarDumper\\Caster\\Caster' => $vendorDir . '/symfony/var-dumper/Caster/Caster.php',

View File

@@ -22,6 +22,7 @@ return array(
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'),
'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
'Symfony\\Component\\Validator\\' => array($vendorDir . '/symfony/validator'),
'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'),
'Symfony\\Component\\Stopwatch\\' => array($vendorDir . '/symfony/stopwatch'),
'Symfony\\Component\\Security\\Csrf\\' => array($vendorDir . '/symfony/security-csrf'),

View File

@@ -49,6 +49,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Symfony\\Component\\Yaml\\' => 23,
'Symfony\\Component\\VarExporter\\' => 30,
'Symfony\\Component\\VarDumper\\' => 28,
'Symfony\\Component\\Validator\\' => 28,
'Symfony\\Component\\String\\' => 25,
'Symfony\\Component\\Stopwatch\\' => 28,
'Symfony\\Component\\Security\\Csrf\\' => 32,
@@ -181,6 +182,10 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
array (
0 => __DIR__ . '/..' . '/symfony/var-dumper',
),
'Symfony\\Component\\Validator\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/validator',
),
'Symfony\\Component\\String\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/string',
@@ -625,6 +630,10 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarSpacer\\ToolbarSpacer' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Toolbar/ToolbarSpacer/ToolbarSpacer.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarSpacer\\ToolbarSpacerUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Toolbar/ToolbarSpacer/ToolbarSpacerUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Toolbar/ToolbarUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboForm\\TurboForm' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/TurboForm/TurboForm.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboForm\\TurboFormUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/TurboForm/TurboFormUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboUpdate\\TurboStream' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/TurboStream/TurboStream.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboUpdate\\TurboStreamUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/TurboStream/TurboStreamUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntry' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/ActivityEntry.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntryFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/ActivityEntryFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\CMDBChangeOp\\CMDBChangeOpAttachmentAddedFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/CMDBChangeOp/CMDBChangeOpAttachmentAddedFactory.php',
@@ -722,6 +731,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Controller\\AjaxRenderController' => __DIR__ . '/../..' . '/sources/Controller/AjaxRenderController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ActivityPanelController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ObjectController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\OqlController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/OqlController.php',
'Combodo\\iTop\\Controller\\Links\\LinkSetController' => __DIR__ . '/../..' . '/sources/Controller/Links/LinkSetController.php',
'Combodo\\iTop\\Controller\\Newsroom\\iTopNewsroomController' => __DIR__ . '/../..' . '/sources/Controller/Newsroom/iTopNewsroomController.php',
'Combodo\\iTop\\Controller\\Notifications\\ActionController' => __DIR__ . '/../..' . '/sources/Controller/Notifications/ActionController.php',
@@ -854,8 +864,106 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Form\\Validator\\MultipleChoicesValidator' => __DIR__ . '/../..' . '/sources/Form/Validator/MultipleChoicesValidator.php',
'Combodo\\iTop\\Form\\Validator\\NotEmptyExtKeyValidator' => __DIR__ . '/../..' . '/sources/Form/Validator/NotEmptyExtKeyValidator.php',
'Combodo\\iTop\\Form\\Validator\\SelectObjectValidator' => __DIR__ . '/../..' . '/sources/Form/Validator/SelectObjectValidator.php',
'Combodo\\iTop\\Forms\\Block\\AbstractFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/AbstractFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\AbstractTypeFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/AbstractTypeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\CheckboxFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/CheckboxFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFromInputsBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceFromInputsBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\CollectionBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/CollectionBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/DateFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateTimeFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/DateTimeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\FormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/FormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\HiddenFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/HiddenFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\IntegerFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/IntegerFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\NumberFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/NumberFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextAreaFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/TextAreaFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/TextFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeTypeChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeTypeChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeValueChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeValueChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\Dashlet\\AggregateFunctionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/Dashlet/AggregateFunctionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\Dashlet\\ClassAttributeGroupByFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/Dashlet/ClassAttributeGroupByFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\LabelFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/LabelFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\OqlFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/OqlFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\AbstractExpressionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Expression/AbstractExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\BooleanExpressionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Expression/BooleanExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\NumberExpressionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Expression/NumberExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\StringExpressionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Expression/StringExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockException' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlockException.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockHelper' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlockHelper.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockService' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlockService.php',
'Combodo\\iTop\\Forms\\Block\\IFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/IFormBlock.php',
'Combodo\\iTop\\Forms\\Compiler\\FormsCompiler' => __DIR__ . '/../..' . '/sources/Forms/Compiler/FormsCompiler.php',
'Combodo\\iTop\\Forms\\Compiler\\FormsCompilerException' => __DIR__ . '/../..' . '/sources/Forms/Compiler/FormsCompilerException.php',
'Combodo\\iTop\\Forms\\Controller\\FormsController' => __DIR__ . '/../..' . '/sources/Forms/Controller/FormsController.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyHandler' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/DependencyHandler.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/DependencyMap.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormBuilder' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/FormBuilder.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormBuilderException' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/FormBuilderException.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormHelper' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/FormHelper.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormTypeExtension' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/FormTypeExtension.php',
'Combodo\\iTop\\Forms\\FormBuilder\\ResolvedFormType' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/ResolvedFormType.php',
'Combodo\\iTop\\Forms\\FormBuilder\\ResolvedFormTypeFactory' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/ResolvedFormTypeFactory.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\ChoiceFormType' => __DIR__ . '/../..' . '/sources/Forms/FormType/Base/ChoiceFormType.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\CollectionFormType' => __DIR__ . '/../..' . '/sources/Forms/FormType/Base/CollectionFormType.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\FormType' => __DIR__ . '/../..' . '/sources/Forms/FormType/Base/FormType.php',
'Combodo\\iTop\\Forms\\FormType\\DataModel\\OqlFormType' => __DIR__ . '/../..' . '/sources/Forms/FormType/DataModel/OqlFormType.php',
'Combodo\\iTop\\Forms\\FormType\\FormTypeHelper' => __DIR__ . '/../..' . '/sources/Forms/FormType/FormTypeHelper.php',
'Combodo\\iTop\\Forms\\Forms' => __DIR__ . '/../..' . '/sources/Forms/Forms.php',
'Combodo\\iTop\\Forms\\FormsException' => __DIR__ . '/../..' . '/sources/Forms/FormsException.php',
'Combodo\\iTop\\Forms\\IO\\AbstractFormIO' => __DIR__ . '/../..' . '/sources/Forms/IO/AbstractFormIO.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\AbstractConverter' => __DIR__ . '/../..' . '/sources/Forms/IO/Converter/AbstractConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\ChoiceValueToLabelConverter' => __DIR__ . '/../..' . '/sources/Forms/IO/Converter/ChoiceValueToLabelConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\OqlToClassConverter' => __DIR__ . '/../..' . '/sources/Forms/IO/Converter/OqlToClassConverter.php',
'Combodo\\iTop\\Forms\\IO\\FormBinding' => __DIR__ . '/../..' . '/sources/Forms/IO/FormBinding.php',
'Combodo\\iTop\\Forms\\IO\\FormBlockIOException' => __DIR__ . '/../..' . '/sources/Forms/IO/FormBlockIOException.php',
'Combodo\\iTop\\Forms\\IO\\FormInput' => __DIR__ . '/../..' . '/sources/Forms/IO/FormInput.php',
'Combodo\\iTop\\Forms\\IO\\FormOutput' => __DIR__ . '/../..' . '/sources/Forms/IO/FormOutput.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AbstractIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/AbstractIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/AttributeIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeTypeArrayIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/AttributeTypeArrayIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeTypeIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/AttributeTypeIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\BooleanIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/BooleanIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\ClassIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/ClassIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\IntegerIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/IntegerIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\NumberIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/NumberIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\StringIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/StringIOFormat.php',
'Combodo\\iTop\\Forms\\Register\\IORegister' => __DIR__ . '/../..' . '/sources/Forms/Register/IORegister.php',
'Combodo\\iTop\\Forms\\Register\\Option' => __DIR__ . '/../..' . '/sources/Forms/Register/Option.php',
'Combodo\\iTop\\Forms\\Register\\OptionsRegister' => __DIR__ . '/../..' . '/sources/Forms/Register/OptionsRegister.php',
'Combodo\\iTop\\Forms\\Register\\RegisterException' => __DIR__ . '/../..' . '/sources/Forms/Register/RegisterException.php',
'Combodo\\iTop\\Forms\\Twig\\Extension\\FormCompatibilityExtension' => __DIR__ . '/../..' . '/sources/Forms/Twig/Extension/FormCompatibilityExtension.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExist' => __DIR__ . '/../..' . '/sources/Forms/Validator/AttributeExist.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExistValidator' => __DIR__ . '/../..' . '/sources/Forms/Validator/AttributeExistValidator.php',
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
'Combodo\\iTop\\PropertyTree\\AbstractProperty' => __DIR__ . '/../..' . '/sources/PropertyTree/AbstractProperty.php',
'Combodo\\iTop\\PropertyTree\\CollectionOfTrees' => __DIR__ . '/../..' . '/sources/PropertyTree/CollectionOfTrees.php',
'Combodo\\iTop\\PropertyTree\\CollectionOfValues' => __DIR__ . '/../..' . '/sources/PropertyTree/CollectionOfValues.php',
'Combodo\\iTop\\PropertyTree\\CollectionType\\AbstractCollectionType' => __DIR__ . '/../..' . '/sources/PropertyTree/CollectionType/AbstractCollectionType.php',
'Combodo\\iTop\\PropertyTree\\CollectionType\\CollectionTypeCollection' => __DIR__ . '/../..' . '/sources/PropertyTree/CollectionType/CollectionTypeCollection.php',
'Combodo\\iTop\\PropertyTree\\CollectionType\\CollectionTypeFactory' => __DIR__ . '/../..' . '/sources/PropertyTree/CollectionType/CollectionTypeFactory.php',
'Combodo\\iTop\\PropertyTree\\Property' => __DIR__ . '/../..' . '/sources/PropertyTree/Property.php',
'Combodo\\iTop\\PropertyTree\\PropertyTree' => __DIR__ . '/../..' . '/sources/PropertyTree/PropertyTree.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeDesign' => __DIR__ . '/../..' . '/sources/PropertyTree/PropertyTreeDesign.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeException' => __DIR__ . '/../..' . '/sources/PropertyTree/PropertyTreeException.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeFactory' => __DIR__ . '/../..' . '/sources/PropertyTree/PropertyTreeFactory.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\AbstractValueType' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/AbstractValueType.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeAggregateFunction' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeAggregateFunction.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeBoolean' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeBoolean.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeChoice' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeChoice.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeChoiceFromInput' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeChoiceFromInput.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClass' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeClass.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttribute' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeClassAttribute.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttributeGroupBy' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeClassAttributeGroupBy.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttributeValue' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeClassAttributeValue.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeFactory' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeFactory.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeIcon' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeIcon.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeInteger' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeInteger.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeLabel' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeLabel.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeOQL' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeOQL.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeProfileName' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeProfileName.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeString' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeString.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeText' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeText.php',
'Combodo\\iTop\\Renderer\\BlockRenderer' => __DIR__ . '/../..' . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFormRenderer.php',
@@ -878,6 +986,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Service\\Base\\ObjectRepository' => __DIR__ . '/../..' . '/sources/Service/Base/ObjectRepository.php',
'Combodo\\iTop\\Service\\Base\\iDataPostProcessor' => __DIR__ . '/../..' . '/sources/Service/Base/iDataPostProcessor.php',
'Combodo\\iTop\\Service\\Cache\\DataModelDependantCache' => __DIR__ . '/../..' . '/sources/Service/Cache/DataModelDependantCache.php',
'Combodo\\iTop\\Service\\DependencyInjection\\DIException' => __DIR__ . '/../..' . '/sources/Service/DependencyInjection/DIException.php',
'Combodo\\iTop\\Service\\DependencyInjection\\DIService' => __DIR__ . '/../..' . '/sources/Service/DependencyInjection/DIService.php',
'Combodo\\iTop\\Service\\Events\\Description\\EventDataDescription' => __DIR__ . '/../..' . '/sources/Service/Events/Description/EventDataDescription.php',
'Combodo\\iTop\\Service\\Events\\Description\\EventDescription' => __DIR__ . '/../..' . '/sources/Service/Events/Description/EventDescription.php',
'Combodo\\iTop\\Service\\Events\\EventData' => __DIR__ . '/../..' . '/sources/Service/Events/EventData.php',
@@ -3452,6 +3562,227 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Symfony\\Component\\String\\Slugger\\AsciiSlugger' => __DIR__ . '/..' . '/symfony/string/Slugger/AsciiSlugger.php',
'Symfony\\Component\\String\\Slugger\\SluggerInterface' => __DIR__ . '/..' . '/symfony/string/Slugger/SluggerInterface.php',
'Symfony\\Component\\String\\UnicodeString' => __DIR__ . '/..' . '/symfony/string/UnicodeString.php',
'Symfony\\Component\\Validator\\Attribute\\HasNamedArguments' => __DIR__ . '/..' . '/symfony/validator/Attribute/HasNamedArguments.php',
'Symfony\\Component\\Validator\\Command\\DebugCommand' => __DIR__ . '/..' . '/symfony/validator/Command/DebugCommand.php',
'Symfony\\Component\\Validator\\Constraint' => __DIR__ . '/..' . '/symfony/validator/Constraint.php',
'Symfony\\Component\\Validator\\ConstraintValidator' => __DIR__ . '/..' . '/symfony/validator/ConstraintValidator.php',
'Symfony\\Component\\Validator\\ConstraintValidatorFactory' => __DIR__ . '/..' . '/symfony/validator/ConstraintValidatorFactory.php',
'Symfony\\Component\\Validator\\ConstraintValidatorFactoryInterface' => __DIR__ . '/..' . '/symfony/validator/ConstraintValidatorFactoryInterface.php',
'Symfony\\Component\\Validator\\ConstraintValidatorInterface' => __DIR__ . '/..' . '/symfony/validator/ConstraintValidatorInterface.php',
'Symfony\\Component\\Validator\\ConstraintViolation' => __DIR__ . '/..' . '/symfony/validator/ConstraintViolation.php',
'Symfony\\Component\\Validator\\ConstraintViolationInterface' => __DIR__ . '/..' . '/symfony/validator/ConstraintViolationInterface.php',
'Symfony\\Component\\Validator\\ConstraintViolationList' => __DIR__ . '/..' . '/symfony/validator/ConstraintViolationList.php',
'Symfony\\Component\\Validator\\ConstraintViolationListInterface' => __DIR__ . '/..' . '/symfony/validator/ConstraintViolationListInterface.php',
'Symfony\\Component\\Validator\\Constraints\\AbstractComparison' => __DIR__ . '/..' . '/symfony/validator/Constraints/AbstractComparison.php',
'Symfony\\Component\\Validator\\Constraints\\AbstractComparisonValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/AbstractComparisonValidator.php',
'Symfony\\Component\\Validator\\Constraints\\All' => __DIR__ . '/..' . '/symfony/validator/Constraints/All.php',
'Symfony\\Component\\Validator\\Constraints\\AllValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/AllValidator.php',
'Symfony\\Component\\Validator\\Constraints\\AtLeastOneOf' => __DIR__ . '/..' . '/symfony/validator/Constraints/AtLeastOneOf.php',
'Symfony\\Component\\Validator\\Constraints\\AtLeastOneOfValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/AtLeastOneOfValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Bic' => __DIR__ . '/..' . '/symfony/validator/Constraints/Bic.php',
'Symfony\\Component\\Validator\\Constraints\\BicValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/BicValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Blank' => __DIR__ . '/..' . '/symfony/validator/Constraints/Blank.php',
'Symfony\\Component\\Validator\\Constraints\\BlankValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/BlankValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Callback' => __DIR__ . '/..' . '/symfony/validator/Constraints/Callback.php',
'Symfony\\Component\\Validator\\Constraints\\CallbackValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CallbackValidator.php',
'Symfony\\Component\\Validator\\Constraints\\CardScheme' => __DIR__ . '/..' . '/symfony/validator/Constraints/CardScheme.php',
'Symfony\\Component\\Validator\\Constraints\\CardSchemeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CardSchemeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Cascade' => __DIR__ . '/..' . '/symfony/validator/Constraints/Cascade.php',
'Symfony\\Component\\Validator\\Constraints\\Choice' => __DIR__ . '/..' . '/symfony/validator/Constraints/Choice.php',
'Symfony\\Component\\Validator\\Constraints\\ChoiceValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ChoiceValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Cidr' => __DIR__ . '/..' . '/symfony/validator/Constraints/Cidr.php',
'Symfony\\Component\\Validator\\Constraints\\CidrValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CidrValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Collection' => __DIR__ . '/..' . '/symfony/validator/Constraints/Collection.php',
'Symfony\\Component\\Validator\\Constraints\\CollectionValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CollectionValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Composite' => __DIR__ . '/..' . '/symfony/validator/Constraints/Composite.php',
'Symfony\\Component\\Validator\\Constraints\\Compound' => __DIR__ . '/..' . '/symfony/validator/Constraints/Compound.php',
'Symfony\\Component\\Validator\\Constraints\\CompoundValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CompoundValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Count' => __DIR__ . '/..' . '/symfony/validator/Constraints/Count.php',
'Symfony\\Component\\Validator\\Constraints\\CountValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CountValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Country' => __DIR__ . '/..' . '/symfony/validator/Constraints/Country.php',
'Symfony\\Component\\Validator\\Constraints\\CountryValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CountryValidator.php',
'Symfony\\Component\\Validator\\Constraints\\CssColor' => __DIR__ . '/..' . '/symfony/validator/Constraints/CssColor.php',
'Symfony\\Component\\Validator\\Constraints\\CssColorValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CssColorValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Currency' => __DIR__ . '/..' . '/symfony/validator/Constraints/Currency.php',
'Symfony\\Component\\Validator\\Constraints\\CurrencyValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CurrencyValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Date' => __DIR__ . '/..' . '/symfony/validator/Constraints/Date.php',
'Symfony\\Component\\Validator\\Constraints\\DateTime' => __DIR__ . '/..' . '/symfony/validator/Constraints/DateTime.php',
'Symfony\\Component\\Validator\\Constraints\\DateTimeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/DateTimeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\DateValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/DateValidator.php',
'Symfony\\Component\\Validator\\Constraints\\DisableAutoMapping' => __DIR__ . '/..' . '/symfony/validator/Constraints/DisableAutoMapping.php',
'Symfony\\Component\\Validator\\Constraints\\DivisibleBy' => __DIR__ . '/..' . '/symfony/validator/Constraints/DivisibleBy.php',
'Symfony\\Component\\Validator\\Constraints\\DivisibleByValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/DivisibleByValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Email' => __DIR__ . '/..' . '/symfony/validator/Constraints/Email.php',
'Symfony\\Component\\Validator\\Constraints\\EmailValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/EmailValidator.php',
'Symfony\\Component\\Validator\\Constraints\\EnableAutoMapping' => __DIR__ . '/..' . '/symfony/validator/Constraints/EnableAutoMapping.php',
'Symfony\\Component\\Validator\\Constraints\\EqualTo' => __DIR__ . '/..' . '/symfony/validator/Constraints/EqualTo.php',
'Symfony\\Component\\Validator\\Constraints\\EqualToValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/EqualToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Existence' => __DIR__ . '/..' . '/symfony/validator/Constraints/Existence.php',
'Symfony\\Component\\Validator\\Constraints\\Expression' => __DIR__ . '/..' . '/symfony/validator/Constraints/Expression.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageProvider' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionLanguageProvider.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntax' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionLanguageSyntax.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntaxValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionLanguageSyntaxValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionSyntax' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionSyntax.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionSyntaxValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionSyntaxValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionValidator.php',
'Symfony\\Component\\Validator\\Constraints\\File' => __DIR__ . '/..' . '/symfony/validator/Constraints/File.php',
'Symfony\\Component\\Validator\\Constraints\\FileValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/FileValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThan' => __DIR__ . '/..' . '/symfony/validator/Constraints/GreaterThan.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqual' => __DIR__ . '/..' . '/symfony/validator/Constraints/GreaterThanOrEqual.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqualValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/GreaterThanOrEqualValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/GreaterThanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GroupSequence' => __DIR__ . '/..' . '/symfony/validator/Constraints/GroupSequence.php',
'Symfony\\Component\\Validator\\Constraints\\GroupSequenceProvider' => __DIR__ . '/..' . '/symfony/validator/Constraints/GroupSequenceProvider.php',
'Symfony\\Component\\Validator\\Constraints\\Hostname' => __DIR__ . '/..' . '/symfony/validator/Constraints/Hostname.php',
'Symfony\\Component\\Validator\\Constraints\\HostnameValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/HostnameValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Iban' => __DIR__ . '/..' . '/symfony/validator/Constraints/Iban.php',
'Symfony\\Component\\Validator\\Constraints\\IbanValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IbanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IdenticalTo' => __DIR__ . '/..' . '/symfony/validator/Constraints/IdenticalTo.php',
'Symfony\\Component\\Validator\\Constraints\\IdenticalToValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IdenticalToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Image' => __DIR__ . '/..' . '/symfony/validator/Constraints/Image.php',
'Symfony\\Component\\Validator\\Constraints\\ImageValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ImageValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Ip' => __DIR__ . '/..' . '/symfony/validator/Constraints/Ip.php',
'Symfony\\Component\\Validator\\Constraints\\IpValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IpValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsFalse' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsFalse.php',
'Symfony\\Component\\Validator\\Constraints\\IsFalseValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsFalseValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsNull' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsNull.php',
'Symfony\\Component\\Validator\\Constraints\\IsNullValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsNullValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsTrue' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsTrue.php',
'Symfony\\Component\\Validator\\Constraints\\IsTrueValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsTrueValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Isbn' => __DIR__ . '/..' . '/symfony/validator/Constraints/Isbn.php',
'Symfony\\Component\\Validator\\Constraints\\IsbnValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsbnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Isin' => __DIR__ . '/..' . '/symfony/validator/Constraints/Isin.php',
'Symfony\\Component\\Validator\\Constraints\\IsinValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsinValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Issn' => __DIR__ . '/..' . '/symfony/validator/Constraints/Issn.php',
'Symfony\\Component\\Validator\\Constraints\\IssnValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IssnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Json' => __DIR__ . '/..' . '/symfony/validator/Constraints/Json.php',
'Symfony\\Component\\Validator\\Constraints\\JsonValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/JsonValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Language' => __DIR__ . '/..' . '/symfony/validator/Constraints/Language.php',
'Symfony\\Component\\Validator\\Constraints\\LanguageValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LanguageValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Length' => __DIR__ . '/..' . '/symfony/validator/Constraints/Length.php',
'Symfony\\Component\\Validator\\Constraints\\LengthValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LengthValidator.php',
'Symfony\\Component\\Validator\\Constraints\\LessThan' => __DIR__ . '/..' . '/symfony/validator/Constraints/LessThan.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanOrEqual' => __DIR__ . '/..' . '/symfony/validator/Constraints/LessThanOrEqual.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanOrEqualValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LessThanOrEqualValidator.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LessThanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Locale' => __DIR__ . '/..' . '/symfony/validator/Constraints/Locale.php',
'Symfony\\Component\\Validator\\Constraints\\LocaleValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LocaleValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Luhn' => __DIR__ . '/..' . '/symfony/validator/Constraints/Luhn.php',
'Symfony\\Component\\Validator\\Constraints\\LuhnValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LuhnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Negative' => __DIR__ . '/..' . '/symfony/validator/Constraints/Negative.php',
'Symfony\\Component\\Validator\\Constraints\\NegativeOrZero' => __DIR__ . '/..' . '/symfony/validator/Constraints/NegativeOrZero.php',
'Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharacters' => __DIR__ . '/..' . '/symfony/validator/Constraints/NoSuspiciousCharacters.php',
'Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharactersValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NoSuspiciousCharactersValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotBlank' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotBlank.php',
'Symfony\\Component\\Validator\\Constraints\\NotBlankValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotBlankValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotCompromisedPassword' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotCompromisedPassword.php',
'Symfony\\Component\\Validator\\Constraints\\NotCompromisedPasswordValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotCompromisedPasswordValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotEqualTo' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotEqualTo.php',
'Symfony\\Component\\Validator\\Constraints\\NotEqualToValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotEqualToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotIdenticalTo' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotIdenticalTo.php',
'Symfony\\Component\\Validator\\Constraints\\NotIdenticalToValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotIdenticalToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotNull' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotNull.php',
'Symfony\\Component\\Validator\\Constraints\\NotNullValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotNullValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Optional' => __DIR__ . '/..' . '/symfony/validator/Constraints/Optional.php',
'Symfony\\Component\\Validator\\Constraints\\PasswordStrength' => __DIR__ . '/..' . '/symfony/validator/Constraints/PasswordStrength.php',
'Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/PasswordStrengthValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Positive' => __DIR__ . '/..' . '/symfony/validator/Constraints/Positive.php',
'Symfony\\Component\\Validator\\Constraints\\PositiveOrZero' => __DIR__ . '/..' . '/symfony/validator/Constraints/PositiveOrZero.php',
'Symfony\\Component\\Validator\\Constraints\\Range' => __DIR__ . '/..' . '/symfony/validator/Constraints/Range.php',
'Symfony\\Component\\Validator\\Constraints\\RangeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/RangeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Regex' => __DIR__ . '/..' . '/symfony/validator/Constraints/Regex.php',
'Symfony\\Component\\Validator\\Constraints\\RegexValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/RegexValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Required' => __DIR__ . '/..' . '/symfony/validator/Constraints/Required.php',
'Symfony\\Component\\Validator\\Constraints\\Sequentially' => __DIR__ . '/..' . '/symfony/validator/Constraints/Sequentially.php',
'Symfony\\Component\\Validator\\Constraints\\SequentiallyValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/SequentiallyValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Time' => __DIR__ . '/..' . '/symfony/validator/Constraints/Time.php',
'Symfony\\Component\\Validator\\Constraints\\TimeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/TimeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Timezone' => __DIR__ . '/..' . '/symfony/validator/Constraints/Timezone.php',
'Symfony\\Component\\Validator\\Constraints\\TimezoneValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/TimezoneValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Traverse' => __DIR__ . '/..' . '/symfony/validator/Constraints/Traverse.php',
'Symfony\\Component\\Validator\\Constraints\\Type' => __DIR__ . '/..' . '/symfony/validator/Constraints/Type.php',
'Symfony\\Component\\Validator\\Constraints\\TypeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/TypeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Ulid' => __DIR__ . '/..' . '/symfony/validator/Constraints/Ulid.php',
'Symfony\\Component\\Validator\\Constraints\\UlidValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/UlidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Unique' => __DIR__ . '/..' . '/symfony/validator/Constraints/Unique.php',
'Symfony\\Component\\Validator\\Constraints\\UniqueValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/UniqueValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Url' => __DIR__ . '/..' . '/symfony/validator/Constraints/Url.php',
'Symfony\\Component\\Validator\\Constraints\\UrlValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/UrlValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Uuid' => __DIR__ . '/..' . '/symfony/validator/Constraints/Uuid.php',
'Symfony\\Component\\Validator\\Constraints\\UuidValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/UuidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Valid' => __DIR__ . '/..' . '/symfony/validator/Constraints/Valid.php',
'Symfony\\Component\\Validator\\Constraints\\ValidValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ValidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\When' => __DIR__ . '/..' . '/symfony/validator/Constraints/When.php',
'Symfony\\Component\\Validator\\Constraints\\WhenValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/WhenValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ZeroComparisonConstraintTrait' => __DIR__ . '/..' . '/symfony/validator/Constraints/ZeroComparisonConstraintTrait.php',
'Symfony\\Component\\Validator\\ContainerConstraintValidatorFactory' => __DIR__ . '/..' . '/symfony/validator/ContainerConstraintValidatorFactory.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContext' => __DIR__ . '/..' . '/symfony/validator/Context/ExecutionContext.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextFactory' => __DIR__ . '/..' . '/symfony/validator/Context/ExecutionContextFactory.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextFactoryInterface' => __DIR__ . '/..' . '/symfony/validator/Context/ExecutionContextFactoryInterface.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextInterface' => __DIR__ . '/..' . '/symfony/validator/Context/ExecutionContextInterface.php',
'Symfony\\Component\\Validator\\DataCollector\\ValidatorDataCollector' => __DIR__ . '/..' . '/symfony/validator/DataCollector/ValidatorDataCollector.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddAutoMappingConfigurationPass' => __DIR__ . '/..' . '/symfony/validator/DependencyInjection/AddAutoMappingConfigurationPass.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddConstraintValidatorsPass' => __DIR__ . '/..' . '/symfony/validator/DependencyInjection/AddConstraintValidatorsPass.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddValidatorInitializersPass' => __DIR__ . '/..' . '/symfony/validator/DependencyInjection/AddValidatorInitializersPass.php',
'Symfony\\Component\\Validator\\Exception\\BadMethodCallException' => __DIR__ . '/..' . '/symfony/validator/Exception/BadMethodCallException.php',
'Symfony\\Component\\Validator\\Exception\\ConstraintDefinitionException' => __DIR__ . '/..' . '/symfony/validator/Exception/ConstraintDefinitionException.php',
'Symfony\\Component\\Validator\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/validator/Exception/ExceptionInterface.php',
'Symfony\\Component\\Validator\\Exception\\GroupDefinitionException' => __DIR__ . '/..' . '/symfony/validator/Exception/GroupDefinitionException.php',
'Symfony\\Component\\Validator\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/validator/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Validator\\Exception\\InvalidOptionsException' => __DIR__ . '/..' . '/symfony/validator/Exception/InvalidOptionsException.php',
'Symfony\\Component\\Validator\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/validator/Exception/LogicException.php',
'Symfony\\Component\\Validator\\Exception\\MappingException' => __DIR__ . '/..' . '/symfony/validator/Exception/MappingException.php',
'Symfony\\Component\\Validator\\Exception\\MissingOptionsException' => __DIR__ . '/..' . '/symfony/validator/Exception/MissingOptionsException.php',
'Symfony\\Component\\Validator\\Exception\\NoSuchMetadataException' => __DIR__ . '/..' . '/symfony/validator/Exception/NoSuchMetadataException.php',
'Symfony\\Component\\Validator\\Exception\\OutOfBoundsException' => __DIR__ . '/..' . '/symfony/validator/Exception/OutOfBoundsException.php',
'Symfony\\Component\\Validator\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/validator/Exception/RuntimeException.php',
'Symfony\\Component\\Validator\\Exception\\UnexpectedTypeException' => __DIR__ . '/..' . '/symfony/validator/Exception/UnexpectedTypeException.php',
'Symfony\\Component\\Validator\\Exception\\UnexpectedValueException' => __DIR__ . '/..' . '/symfony/validator/Exception/UnexpectedValueException.php',
'Symfony\\Component\\Validator\\Exception\\UnsupportedMetadataException' => __DIR__ . '/..' . '/symfony/validator/Exception/UnsupportedMetadataException.php',
'Symfony\\Component\\Validator\\Exception\\ValidationFailedException' => __DIR__ . '/..' . '/symfony/validator/Exception/ValidationFailedException.php',
'Symfony\\Component\\Validator\\Exception\\ValidatorException' => __DIR__ . '/..' . '/symfony/validator/Exception/ValidatorException.php',
'Symfony\\Component\\Validator\\GroupProviderInterface' => __DIR__ . '/..' . '/symfony/validator/GroupProviderInterface.php',
'Symfony\\Component\\Validator\\GroupSequenceProviderInterface' => __DIR__ . '/..' . '/symfony/validator/GroupSequenceProviderInterface.php',
'Symfony\\Component\\Validator\\Mapping\\AutoMappingStrategy' => __DIR__ . '/..' . '/symfony/validator/Mapping/AutoMappingStrategy.php',
'Symfony\\Component\\Validator\\Mapping\\CascadingStrategy' => __DIR__ . '/..' . '/symfony/validator/Mapping/CascadingStrategy.php',
'Symfony\\Component\\Validator\\Mapping\\ClassMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/ClassMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\ClassMetadataInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/ClassMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\BlackHoleMetadataFactory' => __DIR__ . '/..' . '/symfony/validator/Mapping/Factory/BlackHoleMetadataFactory.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\LazyLoadingMetadataFactory' => __DIR__ . '/..' . '/symfony/validator/Mapping/Factory/LazyLoadingMetadataFactory.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\MetadataFactoryInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/Factory/MetadataFactoryInterface.php',
'Symfony\\Component\\Validator\\Mapping\\GenericMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/GenericMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\GetterMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/GetterMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AbstractLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/AbstractLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AnnotationLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/AnnotationLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AttributeLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/AttributeLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AutoMappingTrait' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/AutoMappingTrait.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\FileLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/FileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\FilesLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/FilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\LoaderChain' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/LoaderChain.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\LoaderInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/LoaderInterface.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\PropertyInfoLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/PropertyInfoLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\StaticMethodLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/StaticMethodLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\XmlFileLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/XmlFileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\XmlFilesLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/XmlFilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\YamlFileLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/YamlFileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\YamlFilesLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/YamlFilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\MemberMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/MemberMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\MetadataInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/MetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/PropertyMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/PropertyMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\TraversalStrategy' => __DIR__ . '/..' . '/symfony/validator/Mapping/TraversalStrategy.php',
'Symfony\\Component\\Validator\\ObjectInitializerInterface' => __DIR__ . '/..' . '/symfony/validator/ObjectInitializerInterface.php',
'Symfony\\Component\\Validator\\Util\\PropertyPath' => __DIR__ . '/..' . '/symfony/validator/Util/PropertyPath.php',
'Symfony\\Component\\Validator\\Validation' => __DIR__ . '/..' . '/symfony/validator/Validation.php',
'Symfony\\Component\\Validator\\ValidatorBuilder' => __DIR__ . '/..' . '/symfony/validator/ValidatorBuilder.php',
'Symfony\\Component\\Validator\\Validator\\ContextualValidatorInterface' => __DIR__ . '/..' . '/symfony/validator/Validator/ContextualValidatorInterface.php',
'Symfony\\Component\\Validator\\Validator\\LazyProperty' => __DIR__ . '/..' . '/symfony/validator/Validator/LazyProperty.php',
'Symfony\\Component\\Validator\\Validator\\RecursiveContextualValidator' => __DIR__ . '/..' . '/symfony/validator/Validator/RecursiveContextualValidator.php',
'Symfony\\Component\\Validator\\Validator\\RecursiveValidator' => __DIR__ . '/..' . '/symfony/validator/Validator/RecursiveValidator.php',
'Symfony\\Component\\Validator\\Validator\\TraceableValidator' => __DIR__ . '/..' . '/symfony/validator/Validator/TraceableValidator.php',
'Symfony\\Component\\Validator\\Validator\\ValidatorInterface' => __DIR__ . '/..' . '/symfony/validator/Validator/ValidatorInterface.php',
'Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilder' => __DIR__ . '/..' . '/symfony/validator/Violation/ConstraintViolationBuilder.php',
'Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilderInterface' => __DIR__ . '/..' . '/symfony/validator/Violation/ConstraintViolationBuilderInterface.php',
'Symfony\\Component\\VarDumper\\Caster\\AmqpCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/AmqpCaster.php',
'Symfony\\Component\\VarDumper\\Caster\\ArgsStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ArgsStub.php',
'Symfony\\Component\\VarDumper\\Caster\\Caster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/Caster.php',

View File

@@ -5238,6 +5238,110 @@
],
"install-path": "../symfony/twig-bundle"
},
{
"name": "symfony/validator",
"version": "v6.4.29",
"version_normalized": "6.4.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/validator.git",
"reference": "99df8a769e64e399f510166141ea74f450e8dd1d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/validator/zipball/99df8a769e64e399f510166141ea74f450e8dd1d",
"reference": "99df8a769e64e399f510166141ea74f450e8dd1d",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php83": "^1.27",
"symfony/translation-contracts": "^2.5|^3"
},
"conflict": {
"doctrine/annotations": "<1.13",
"doctrine/lexer": "<1.1",
"symfony/dependency-injection": "<5.4",
"symfony/expression-language": "<5.4",
"symfony/http-kernel": "<5.4",
"symfony/intl": "<5.4",
"symfony/property-info": "<5.4",
"symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3",
"symfony/yaml": "<5.4"
},
"require-dev": {
"doctrine/annotations": "^1.13|^2",
"egulias/email-validator": "^2.1.10|^3|^4",
"symfony/cache": "^5.4|^6.0|^7.0",
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/console": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/expression-language": "^5.4|^6.0|^7.0",
"symfony/finder": "^5.4|^6.0|^7.0",
"symfony/http-client": "^5.4|^6.0|^7.0",
"symfony/http-foundation": "^5.4|^6.0|^7.0",
"symfony/http-kernel": "^5.4|^6.0|^7.0",
"symfony/intl": "^5.4|^6.0|^7.0",
"symfony/mime": "^5.4|^6.0|^7.0",
"symfony/property-access": "^5.4|^6.0|^7.0",
"symfony/property-info": "^5.4|^6.0|^7.0",
"symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3",
"symfony/yaml": "^5.4|^6.0|^7.0"
},
"time": "2025-11-06T20:26:06+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Validator\\": ""
},
"exclude-from-classmap": [
"/Tests/",
"/Resources/bin/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides tools to validate values",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/validator/tree/v6.4.29"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/validator"
},
{
"name": "symfony/var-dumper",
"version": "v6.4.26",

View File

@@ -3,7 +3,7 @@
'name' => 'combodo/itop',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '19d062aa830b6d6c7d17ac4046fc9ee2c5e3fab1',
'reference' => '06e5c8078690380fb8690371a69eb3c68469c1ed',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -22,7 +22,7 @@
'combodo/itop' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '19d062aa830b6d6c7d17ac4046fc9ee2c5e3fab1',
'reference' => '06e5c8078690380fb8690371a69eb3c68469c1ed',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -678,6 +678,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/validator' => array(
'pretty_version' => 'v6.4.29',
'version' => '6.4.29.0',
'reference' => '99df8a769e64e399f510166141ea74f450e8dd1d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/validator',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/var-dumper' => array(
'pretty_version' => 'v6.4.26',
'version' => '6.4.26.0',

View File

@@ -0,0 +1,7 @@
parameters:
level: 6
errorFormat: raw
editorUrl: '%%file%% %%line%% %%column%%: %%error%%'
paths:
- src
- tests

19
lib/symfony/mime/LICENSE Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2010-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Attribute;
#[\Attribute(\Attribute::TARGET_METHOD)]
final class HasNamedArguments
{
}

View File

@@ -0,0 +1,415 @@
CHANGELOG
=========
6.4
---
* Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate`
* Allow single integer for the `versions` option of the `Uuid` constraint
* Allow single constraint to be passed to the `constraints` option of the `When` constraint
* Deprecate Doctrine annotations support in favor of native attributes
* Deprecate `ValidatorBuilder::setDoctrineAnnotationReader()`
* Deprecate `ValidatorBuilder::addDefaultDoctrineAnnotationReader()`
* Add `number`, `finite-number` and `finite-float` types to `Type` constraint
* Add the `withSeconds` option to the `Time` constraint that allows to pass time without seconds
* Deprecate `ValidatorBuilder::enableAnnotationMapping()`, use `ValidatorBuilder::enableAttributeMapping()` instead
* Deprecate `ValidatorBuilder::disableAnnotationMapping()`, use `ValidatorBuilder::disableAttributeMapping()` instead
* Deprecate `AnnotationLoader`, use `AttributeLoader` instead
* Add `GroupProviderInterface` to implement validation group providers outside the underlying class
6.3
---
* Add method `getConstraint()` to `ConstraintViolationInterface`
* Add `Uuid::TIME_BASED_VERSIONS` to match that a UUID being validated embeds a timestamp
* Add the `pattern` parameter in violations of the `Regex` constraint
* Add a `NoSuspiciousCharacters` constraint to validate a string is not a spoofing attempt
* Add a `PasswordStrength` constraint to check the strength of a password
* Add the `countUnit` option to the `Length` constraint to allow counting the string length either by code points (like before, now the default setting `Length::COUNT_CODEPOINTS`), bytes (`Length::COUNT_BYTES`) or graphemes (`Length::COUNT_GRAPHEMES`)
* Add the `filenameMaxLength` option to the `File` constraint
* Add the `exclude` option to the `Cascade` constraint
* Add the `value_length` parameter to `Length` constraint
* Allow to disable the translation domain for `ConstraintViolationInterface` messages
6.2
---
* Add option `Email::VALIDATION_MODE_HTML5_ALLOW_NO_TLD` with "html5-allow-no-tld" e-mail validation mode, to match with the W3C official specification
* Add method `getCause()` to `ConstraintViolationInterface`
* Add the `When` constraint and validator
* Deprecate the "loose" e-mail validation mode, use "html5" instead
* Add the `negate` option to the `Expression` constraint, to inverse the logic of the violation's creation
* Add the `extensions` option to the `File` constraint as an alternative to `mimeTypes` which checks the mime type of the file, its extension, and the consistency between them
* Add padding for enhanced privacy to the `NotCompromisedPasswordValidator`
6.1
---
* Add the `fields` option to the `Unique` constraint, to define which collection keys should be checked for uniqueness
* Deprecate `Constraint::$errorNames`, use `Constraint::ERROR_NAMES` instead
* Deprecate constraint `ExpressionLanguageSyntax`, use `ExpressionSyntax` instead
* Add method `__toString()` to `ConstraintViolationInterface` & `ConstraintViolationListInterface`
* Allow creating constraints with required arguments
* Add the `match` option to the `Choice` constraint
6.0
---
* Remove the `allowEmptyString` option from the `Length` constraint
* Remove the `NumberConstraintTrait` trait
* `ValidatorBuilder::enableAnnotationMapping()` does not accept a Doctrine annotation reader anymore
* `ValidatorBuilder::enableAnnotationMapping()` won't automatically setup a Doctrine annotation reader anymore
5.4
---
* Add a `Cidr` constraint to validate CIDR notations
* Add a `CssColor` constraint to validate CSS colors
* Add support for `ConstraintViolationList::createFromMessage()`
* Add error's uid to `Count` and `Length` constraints with "exactly" option enabled
5.3
---
* Add the `normalizer` option to the `Unique` constraint
* Add `Validation::createIsValidCallable()` that returns true/false instead of throwing exceptions
5.2.0
-----
* added a `Cascade` constraint to ease validating nested typed object properties
* deprecated the `allowEmptyString` option of the `Length` constraint
Before:
```php
use Symfony\Component\Validator\Constraints as Assert;
/**
* @Assert\Length(min=5, allowEmptyString=true)
*/
```
After:
```php
use Symfony\Component\Validator\Constraints as Assert;
/**
* @Assert\AtLeastOneOf({
* @Assert\Blank(),
* @Assert\Length(min=5)
* })
*/
```
* added the `Isin` constraint and validator
* added the `ULID` constraint and validator
* added support for UUIDv6 in `Uuid` constraint
* enabled the validator to load constraints from PHP attributes
* deprecated the `NumberConstraintTrait` trait
* deprecated setting or creating a Doctrine annotation reader via `ValidatorBuilder::enableAnnotationMapping()`, pass `true` as first parameter and additionally call `setDoctrineAnnotationReader()` or `addDefaultDoctrineAnnotationReader()` to set up the annotation reader
5.1.0
-----
* Add `AtLeastOneOf` constraint that is considered to be valid if at least one of the nested constraints is valid
* added the `Hostname` constraint and validator
* added the `alpha3` option to the `Country` and `Language` constraints
* allow to define a reusable set of constraints by extending the `Compound` constraint
* added `Sequentially` constraint, to sequentially validate a set of constraints (any violation raised will prevent further validation of the nested constraints)
* added the `divisibleBy` option to the `Count` constraint
* added the `ExpressionLanguageSyntax` constraint
5.0.0
-----
* an `ExpressionLanguage` instance or null must be passed as the first argument of `ExpressionValidator::__construct()`
* removed the `checkDNS` and `dnsMessage` options of the `Url` constraint
* removed the `checkMX`, `checkHost` and `strict` options of the `Email` constraint
* removed support for validating instances of `\DateTimeInterface` in `DateTimeValidator`, `DateValidator` and `TimeValidator`
* removed support for using the `Bic`, `Country`, `Currency`, `Language` and `Locale` constraints without `symfony/intl`
* removed support for using the `Email` constraint without `egulias/email-validator`
* removed support for using the `Expression` constraint without `symfony/expression-language`
* changed default value of `canonicalize` option of `Locale` constraint to `true`
* removed `ValidatorBuilderInterface`
* passing a null message when instantiating a `ConstraintViolation` is not allowed
* changed the default value of `Length::$allowEmptyString` to `false` and made it optional
* removed `Symfony\Component\Validator\Mapping\Cache\CacheInterface` in favor of PSR-6.
* removed `ValidatorBuilder::setMetadataCache`, use `ValidatorBuilder::setMappingCache` instead.
4.4.0
-----
* [BC BREAK] using null as `$classValidatorRegexp` value in `PropertyInfoLoader::__construct` will not enable auto-mapping for all classes anymore, use `'{.*}'` instead.
* added `EnableAutoMapping` and `DisableAutoMapping` constraints to enable or disable auto mapping for class or a property
* using anything else than a `string` as the code of a `ConstraintViolation` is deprecated, a `string` type-hint will
be added to the constructor of the `ConstraintViolation` class and to the `ConstraintViolationBuilder::setCode()`
method in 5.0
* deprecated passing an `ExpressionLanguage` instance as the second argument of `ExpressionValidator::__construct()`. Pass it as the first argument instead.
* added the `compared_value_path` parameter in violations when using any
comparison constraint with the `propertyPath` option.
* added support for checking an array of types in `TypeValidator`
* added a new `allowEmptyString` option to the `Length` constraint to allow rejecting empty strings when `min` is set, by setting it to `false`.
* Added new `minPropertyPath` and `maxPropertyPath` options
to `Range` constraint in order to get the value to compare
from an array or object
* added the `min_limit_path` and `max_limit_path` parameters in violations when using
`Range` constraint with respectively the `minPropertyPath` and
`maxPropertyPath` options
* added a new `notInRangeMessage` option to the `Range` constraint that will
be used in the violation builder when both `min` and `max` are not null
* added ability to use stringable objects as violation messages
* Overriding the methods `ConstraintValidatorTestCase::setUp()` and `ConstraintValidatorTestCase::tearDown()` without the `void` return-type is deprecated.
* deprecated `Symfony\Component\Validator\Mapping\Cache\CacheInterface` in favor of PSR-6.
* deprecated `ValidatorBuilder::setMetadataCache`, use `ValidatorBuilder::setMappingCache` instead.
* Marked the `ValidatorDataCollector` class as `@final`.
4.3.0
-----
* added `Timezone` constraint
* added `NotCompromisedPassword` constraint
* added options `iban` and `ibanPropertyPath` to Bic constraint
* added UATP cards support to `CardSchemeValidator`
* added option `allowNull` to NotBlank constraint
* added `Json` constraint
* added `Unique` constraint
* added a new `normalizer` option to the string constraints and to the `NotBlank` constraint
* added `Positive` constraint
* added `PositiveOrZero` constraint
* added `Negative` constraint
* added `NegativeOrZero` constraint
4.2.0
-----
* added a new `UnexpectedValueException` that can be thrown by constraint validators, these exceptions are caught by
the validator and are converted into constraint violations
* added `DivisibleBy` constraint
* decoupled from `symfony/translation` by using `Symfony\Contracts\Translation\TranslatorInterface`
* deprecated `ValidatorBuilderInterface`
* made `ValidatorBuilder::setTranslator()` final
* marked `format` the default option in `DateTime` constraint
* deprecated validating instances of `\DateTimeInterface` in `DateTimeValidator`, `DateValidator` and `TimeValidator`.
* deprecated using the `Bic`, `Country`, `Currency`, `Language` and `Locale` constraints without `symfony/intl`
* deprecated using the `Email` constraint without `egulias/email-validator`
* deprecated using the `Expression` constraint without `symfony/expression-language`
4.1.0
-----
* Deprecated the `checkDNS` and `dnsMessage` options of the `Url` constraint.
* added a `values` option to the `Expression` constraint
* Deprecated use of `Locale` constraint without setting `true` at "canonicalize" option, which will be the default value in 5.0
4.0.0
-----
* Setting the `strict` option of the `Choice` constraint to anything but `true`
is not supported anymore.
* removed the `DateTimeValidator::PATTERN` constant
* removed the `AbstractConstraintValidatorTest` class
* removed support for setting the `checkDNS` option of the `Url` constraint to `true`
3.4.0
-----
* added support for validation groups to the `Valid` constraint
* not setting the `strict` option of the `Choice` constraint to `true` is
deprecated and will throw an exception in Symfony 4.0
* setting the `checkDNS` option of the `Url` constraint to `true` is deprecated in favor of
the `Url::CHECK_DNS_TYPE_*` constants values and will throw an exception in Symfony 4.0
* added min/max amount of pixels check to `Image` constraint via `minPixels` and `maxPixels`
* added a new "propertyPath" option to comparison constraints in order to get the value to compare from an array or object
3.3.0
-----
* added `AddValidatorInitializersPass`
* added `AddConstraintValidatorsPass`
* added `ContainerConstraintValidatorFactory`
3.2.0
-----
* deprecated `Tests\Constraints\AbstractConstraintValidatorTest` in favor of `Test\ConstraintValidatorTestCase`
* added support for PHP constants in YAML configuration files
3.1.0
-----
* deprecated `DateTimeValidator::PATTERN` constant
* added a `format` option to the `DateTime` constraint
2.8.0
-----
* added the BIC (SWIFT-Code) validator
2.7.0
-----
* deprecated `DefaultTranslator` in favor of `Symfony\Component\Translation\IdentityTranslator`
* deprecated PHP7-incompatible constraints (Null, True, False) and related validators (NullValidator, TrueValidator, FalseValidator) in favor of their `Is`-prefixed equivalent
2.6.0
-----
* [BC BREAK] `FileValidator` disallow empty files
* [BC BREAK] `UserPasswordValidator` source message change
* [BC BREAK] added internal `ExecutionContextInterface::setConstraint()`
* added `ConstraintViolation::getConstraint()`
* [BC BREAK] The `ExpressionValidator` will now evaluate the Expression even when the property value is null or an empty string
* deprecated `ClassMetadata::hasMemberMetadatas()`
* deprecated `ClassMetadata::getMemberMetadatas()`
* deprecated `ClassMetadata::addMemberMetadata()`
* [BC BREAK] added `Mapping\MetadataInterface::getConstraints()`
* added generic "payload" option to all constraints for attaching domain-specific data
* [BC BREAK] added `ConstraintViolationBuilderInterface::setCause()`
2.5.0
-----
* deprecated `ApcCache` in favor of `DoctrineCache`
* added `DoctrineCache` to adapt any Doctrine cache
* `GroupSequence` now implements `ArrayAccess`, `Countable` and `Traversable`
* [BC BREAK] changed `ClassMetadata::getGroupSequence()` to return a `GroupSequence` instance instead of an array
* `Callback` can now be put onto properties (useful when you pass a closure to the constraint)
* deprecated `ClassBasedInterface`
* deprecated `MetadataInterface`
* deprecated `PropertyMetadataInterface`
* deprecated `PropertyMetadataContainerInterface`
* deprecated `Mapping\ElementMetadata`
* added `Mapping\MetadataInterface`
* added `Mapping\ClassMetadataInterface`
* added `Mapping\PropertyMetadataInterface`
* added `Mapping\GenericMetadata`
* added `Mapping\CascadingStrategy`
* added `Mapping\TraversalStrategy`
* deprecated `Mapping\ClassMetadata::accept()`
* deprecated `Mapping\MemberMetadata::accept()`
* removed array type hint of `Mapping\ClassMetadata::setGroupSequence()`
* deprecated `MetadataFactoryInterface`
* deprecated `Mapping\BlackholeMetadataFactory`
* deprecated `Mapping\ClassMetadataFactory`
* added `Mapping\Factory\MetadataFactoryInterface`
* added `Mapping\Factory\BlackHoleMetadataFactory`
* added `Mapping\Factory\LazyLoadingMetadataFactory`
* deprecated `ExecutionContextInterface`
* deprecated `ExecutionContext`
* deprecated `GlobalExecutionContextInterface`
* added `Context\ExecutionContextInterface`
* added `Context\ExecutionContext`
* added `Context\ExecutionContextFactoryInterface`
* added `Context\ExecutionContextFactory`
* deprecated `ValidatorInterface`
* deprecated `Validator`
* deprecated `ValidationVisitorInterface`
* deprecated `ValidationVisitor`
* added `Validator\ValidatorInterface`
* added `Validator\RecursiveValidator`
* added `Validator\ContextualValidatorInterface`
* added `Validator\RecursiveContextualValidator`
* added `Violation\ConstraintViolationBuilderInterface`
* added `Violation\ConstraintViolationBuilder`
* added `ConstraintViolation::getParameters()`
* added `ConstraintViolation::getPlural()`
* added `Constraints\Traverse`
* deprecated `$deep` property in `Constraints\Valid`
* added `ValidatorBuilderInterface::setApiVersion()`
* added `Validation::API_VERSION_2_4`
* added `Validation::API_VERSION_2_5`
* added `Exception\OutOfBoundsException`
* added `Exception\UnsupportedMetadataException`
* made `Exception\ValidatorException` extend `Exception\RuntimeException`
* added `Util\PropertyPath`
* made the PropertyAccess component an optional dependency
* deprecated `ValidatorBuilder::setPropertyAccessor()`
* deprecated `validate` and `validateValue` on `Validator\Context\ExecutionContext` use `getValidator()` together with `inContext()` instead
2.4.0
-----
* added a constraint the uses the expression language
* added `minRatio`, `maxRatio`, `allowSquare`, `allowLandscape`, and `allowPortrait` to Image validator
2.3.29
------
* fixed compatibility with PHP7 and up by introducing new constraints (IsNull, IsTrue, IsFalse) and related validators (IsNullValidator, IsTrueValidator, IsFalseValidator)
2.3.0
-----
* added the ISBN, ISSN, and IBAN validators
* copied the constraints `Optional` and `Required` to the
`Symfony\Component\Validator\Constraints\` namespace and deprecated the original
classes.
* added comparison validators (EqualTo, NotEqualTo, LessThan, LessThanOrEqualTo, GreaterThan, GreaterThanOrEqualTo, IdenticalTo, NotIdenticalTo)
2.2.0
-----
* added a CardScheme validator
* added a Luhn validator
* moved @api-tags from `Validator` to `ValidatorInterface`
* moved @api-tags from `ConstraintViolation` to the new `ConstraintViolationInterface`
* moved @api-tags from `ConstraintViolationList` to the new `ConstraintViolationListInterface`
* moved @api-tags from `ExecutionContext` to the new `ExecutionContextInterface`
* [BC BREAK] `ConstraintValidatorInterface::initialize` is now type hinted against `ExecutionContextInterface` instead of `ExecutionContext`
* [BC BREAK] changed the visibility of the properties in `Validator` from protected to private
* deprecated `ClassMetadataFactoryInterface` in favor of the new `MetadataFactoryInterface`
* deprecated `ClassMetadataFactory::getClassMetadata` in favor of `getMetadataFor`
* created `MetadataInterface`, `PropertyMetadataInterface`, `ClassBasedInterface` and `PropertyMetadataContainerInterface`
* deprecated `GraphWalker` in favor of the new `ValidationVisitorInterface`
* deprecated `ExecutionContext::addViolationAtPath`
* deprecated `ExecutionContext::addViolationAtSubPath` in favor of `ExecutionContextInterface::addViolationAt`
* deprecated `ExecutionContext::getCurrentClass` in favor of `ExecutionContextInterface::getClassName`
* deprecated `ExecutionContext::getCurrentProperty` in favor of `ExecutionContextInterface::getPropertyName`
* deprecated `ExecutionContext::getCurrentValue` in favor of `ExecutionContextInterface::getValue`
* deprecated `ExecutionContext::getGraphWalker` in favor of `ExecutionContextInterface::validate` and `ExecutionContextInterface::validateValue`
* improved `ValidatorInterface::validateValue` to accept arrays of constraints
* changed `ValidatorInterface::getMetadataFactory` to return a `MetadataFactoryInterface` instead of a `ClassMetadataFactoryInterface`
* removed `ClassMetadataFactoryInterface` type hint from `ValidatorBuilderInterface::setMetadataFactory`.
As of Symfony 2.3, this method will be typed against `MetadataFactoryInterface` instead.
* [BC BREAK] the switches `traverse` and `deep` in the `Valid` constraint and in `GraphWalker::walkReference`
are ignored for arrays now. Arrays are always traversed recursively.
* added dependency to Translation component
* violation messages are now translated with a TranslatorInterface implementation
* [BC BREAK] inserted argument `$message` in the constructor of `ConstraintViolation`
* [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `ExecutionContext`
* [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `GraphWalker`
* [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `ValidationVisitor`
* [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `Validator`
* [BC BREAK] added `setTranslator()` and `setTranslationDomain()` to `ValidatorBuilderInterface`
* improved the Validator to support pluralized messages by default
* [BC BREAK] changed the source of all pluralized messages in the translation files to the pluralized version
* added ExceptionInterface, BadMethodCallException and InvalidArgumentException
2.1.0
-----
* added support for `ctype_*` assertions in `TypeValidator`
* improved the ImageValidator with min width, max width, min height, and max height constraints
* added support for MIME with wildcard in FileValidator
* changed Collection validator to add "missing" and "extra" errors to
individual fields
* changed default value for `extraFieldsMessage` and `missingFieldsMessage`
in Collection constraint
* made ExecutionContext immutable
* deprecated Constraint methods `setMessage`, `getMessageTemplate` and
`getMessageParameters`
* added support for dynamic group sequences with the GroupSequenceProvider pattern
* [BC BREAK] ConstraintValidatorInterface method `isValid` has been renamed to
`validate`, its return value was dropped. ConstraintValidator still contains
`isValid` for BC
* [BC BREAK] collections in fields annotated with `Valid` are not traversed
recursively anymore by default. `Valid` contains a new property `deep`
which enables the BC behavior.
* added Count constraint
* added Length constraint
* added Range constraint
* deprecated the Min and Max constraints
* deprecated the MinLength and MaxLength constraints
* added Validation and ValidatorBuilderInterface
* deprecated ValidatorContext, ValidatorContextInterface and ValidatorFactory

View File

@@ -0,0 +1,253 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Dumper;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Mapping\AutoMappingStrategy;
use Symfony\Component\Validator\Mapping\CascadingStrategy;
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
use Symfony\Component\Validator\Mapping\GenericMetadata;
use Symfony\Component\Validator\Mapping\TraversalStrategy;
/**
* A console command to debug Validators information.
*
* @author Loïc Frémont <lc.fremont@gmail.com>
*/
#[AsCommand(name: 'debug:validator', description: 'Display validation constraints for classes')]
class DebugCommand extends Command
{
private MetadataFactoryInterface $validator;
public function __construct(MetadataFactoryInterface $validator)
{
parent::__construct();
$this->validator = $validator;
}
/**
* @return void
*/
protected function configure()
{
$this
->addArgument('class', InputArgument::REQUIRED, 'A fully qualified class name or a path')
->addOption('show-all', null, InputOption::VALUE_NONE, 'Show all classes even if they have no validation constraints')
->setHelp(<<<'EOF'
The <info>%command.name% 'App\Entity\Dummy'</info> command dumps the validators for the dummy class.
The <info>%command.name% src/</info> command dumps the validators for the `src` directory.
EOF
)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$class = $input->getArgument('class');
if (class_exists($class)) {
$this->dumpValidatorsForClass($input, $output, $class);
return 0;
}
try {
foreach ($this->getResourcesByPath($class) as $class) {
$this->dumpValidatorsForClass($input, $output, $class);
}
} catch (DirectoryNotFoundException) {
$io = new SymfonyStyle($input, $output);
$io->error(\sprintf('Neither class nor path were found with "%s" argument.', $input->getArgument('class')));
return 1;
}
return 0;
}
private function dumpValidatorsForClass(InputInterface $input, OutputInterface $output, string $class): void
{
$io = new SymfonyStyle($input, $output);
$title = \sprintf('<info>%s</info>', $class);
$rows = [];
$dump = new Dumper($output);
/** @var ClassMetadataInterface $classMetadata */
$classMetadata = $this->validator->getMetadataFor($class);
foreach ($this->getClassConstraintsData($classMetadata) as $data) {
$rows[] = [
'-',
$data['class'],
implode(', ', $data['groups']),
$dump($data['options']),
];
}
foreach ($this->getConstrainedPropertiesData($classMetadata) as $propertyName => $constraintsData) {
foreach ($constraintsData as $data) {
$rows[] = [
$propertyName,
$data['class'],
implode(', ', $data['groups']),
$dump($data['options']),
];
}
}
if (!$rows) {
if (false === $input->getOption('show-all')) {
return;
}
$io->section($title);
$io->text('No validators were found for this class.');
return;
}
$io->section($title);
$table = new Table($output);
$table->setHeaders(['Property', 'Name', 'Groups', 'Options']);
$table->setRows($rows);
$table->setColumnMaxWidth(3, 80);
$table->render();
}
private function getClassConstraintsData(ClassMetadataInterface $classMetadata): iterable
{
foreach ($classMetadata->getConstraints() as $constraint) {
yield [
'class' => $constraint::class,
'groups' => $constraint->groups,
'options' => $this->getConstraintOptions($constraint),
];
}
}
private function getConstrainedPropertiesData(ClassMetadataInterface $classMetadata): array
{
$data = [];
foreach ($classMetadata->getConstrainedProperties() as $constrainedProperty) {
$data[$constrainedProperty] = $this->getPropertyData($classMetadata, $constrainedProperty);
}
return $data;
}
private function getPropertyData(ClassMetadataInterface $classMetadata, string $constrainedProperty): array
{
$data = [];
$propertyMetadata = $classMetadata->getPropertyMetadata($constrainedProperty);
foreach ($propertyMetadata as $metadata) {
$autoMapingStrategy = 'Not supported';
if ($metadata instanceof GenericMetadata) {
$autoMapingStrategy = match ($metadata->getAutoMappingStrategy()) {
AutoMappingStrategy::ENABLED => 'Enabled',
AutoMappingStrategy::DISABLED => 'Disabled',
AutoMappingStrategy::NONE => 'None',
};
}
$traversalStrategy = 'None';
if (TraversalStrategy::TRAVERSE === $metadata->getTraversalStrategy()) {
$traversalStrategy = 'Traverse';
}
if (TraversalStrategy::IMPLICIT === $metadata->getTraversalStrategy()) {
$traversalStrategy = 'Implicit';
}
$data[] = [
'class' => 'property options',
'groups' => [],
'options' => [
'cascadeStrategy' => CascadingStrategy::CASCADE === $metadata->getCascadingStrategy() ? 'Cascade' : 'None',
'autoMappingStrategy' => $autoMapingStrategy,
'traversalStrategy' => $traversalStrategy,
],
];
foreach ($metadata->getConstraints() as $constraint) {
$data[] = [
'class' => $constraint::class,
'groups' => $constraint->groups,
'options' => $this->getConstraintOptions($constraint),
];
}
}
return $data;
}
private function getConstraintOptions(Constraint $constraint): array
{
$options = [];
foreach (array_keys(get_object_vars($constraint)) as $propertyName) {
// Groups are dumped on a specific column.
if ('groups' === $propertyName) {
continue;
}
$options[$propertyName] = $constraint->$propertyName;
}
ksort($options);
return $options;
}
private function getResourcesByPath(string $path): array
{
$finder = new Finder();
$finder->files()->in($path)->name('*.php')->sortByName(true);
$classes = [];
foreach ($finder as $file) {
$fileContent = file_get_contents($file->getRealPath());
preg_match('/namespace (.+);/', $fileContent, $matches);
$namespace = $matches[1] ?? null;
if (!preg_match('/class +([^{ ]+)/', $fileContent, $matches)) {
// no class found
continue;
}
$className = trim($matches[1]);
if (null !== $namespace) {
$classes[] = $namespace.'\\'.$className;
} else {
$classes[] = $className;
}
}
return $classes;
}
}

View File

@@ -0,0 +1,321 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\InvalidArgumentException;
use Symfony\Component\Validator\Exception\InvalidOptionsException;
use Symfony\Component\Validator\Exception\MissingOptionsException;
/**
* Contains the properties of a constraint definition.
*
* A constraint can be defined on a class, a property or a getter method.
* The Constraint class encapsulates all the configuration required for
* validating this class, property or getter result successfully.
*
* Constraint instances are immutable and serializable.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
abstract class Constraint
{
/**
* The name of the group given to all constraints with no explicit group.
*/
public const DEFAULT_GROUP = 'Default';
/**
* Marks a constraint that can be put onto classes.
*/
public const CLASS_CONSTRAINT = 'class';
/**
* Marks a constraint that can be put onto properties.
*/
public const PROPERTY_CONSTRAINT = 'property';
/**
* Maps error codes to the names of their constants.
*
* @var array<string, string>
*/
protected const ERROR_NAMES = [];
/**
* @deprecated since Symfony 6.1, use protected const ERROR_NAMES instead
*/
protected static $errorNames = [];
/**
* Domain-specific data attached to a constraint.
*
* @var mixed
*/
public $payload;
/**
* The groups that the constraint belongs to.
*
* @var string[]
*/
public $groups;
/**
* Returns the name of the given error code.
*
* @throws InvalidArgumentException If the error code does not exist
*/
public static function getErrorName(string $errorCode): string
{
if (isset(static::ERROR_NAMES[$errorCode])) {
return static::ERROR_NAMES[$errorCode];
}
if (!isset(static::$errorNames[$errorCode])) {
throw new InvalidArgumentException(\sprintf('The error code "%s" does not exist for constraint of type "%s".', $errorCode, static::class));
}
trigger_deprecation('symfony/validator', '6.1', 'The "%s::$errorNames" property is deprecated, use protected const ERROR_NAMES instead.', static::class);
return static::$errorNames[$errorCode];
}
/**
* Initializes the constraint with options.
*
* You should pass an associative array. The keys should be the names of
* existing properties in this class. The values should be the value for these
* properties.
*
* Alternatively you can override the method getDefaultOption() to return the
* name of an existing property. If no associative array is passed, this
* property is set instead.
*
* You can force that certain options are set by overriding
* getRequiredOptions() to return the names of these options. If any
* option is not set here, an exception is thrown.
*
* @param mixed $options The options (as associative array)
* or the value for the default
* option (any other type)
* @param string[] $groups An array of validation groups
* @param mixed $payload Domain-specific data attached to a constraint
*
* @throws InvalidOptionsException When you pass the names of non-existing
* options
* @throws MissingOptionsException When you don't pass any of the options
* returned by getRequiredOptions()
* @throws ConstraintDefinitionException When you don't pass an associative
* array, but getDefaultOption() returns
* null
*/
public function __construct(mixed $options = null, ?array $groups = null, mixed $payload = null)
{
unset($this->groups); // enable lazy initialization
$options = $this->normalizeOptions($options);
if (null !== $groups) {
$options['groups'] = $groups;
}
$options['payload'] = $payload ?? $options['payload'] ?? null;
foreach ($options as $name => $value) {
$this->$name = $value;
}
}
protected function normalizeOptions(mixed $options): array
{
$normalizedOptions = [];
$defaultOption = $this->getDefaultOption();
$invalidOptions = [];
$missingOptions = array_flip((array) $this->getRequiredOptions());
$knownOptions = get_class_vars(static::class);
if (\is_array($options) && isset($options['value']) && !property_exists($this, 'value')) {
if (null === $defaultOption) {
throw new ConstraintDefinitionException(\sprintf('No default option is configured for constraint "%s".', static::class));
}
$options[$defaultOption] = $options['value'];
unset($options['value']);
}
if (\is_array($options)) {
reset($options);
}
if ($options && \is_array($options) && \is_string(key($options))) {
foreach ($options as $option => $value) {
if (\array_key_exists($option, $knownOptions)) {
$normalizedOptions[$option] = $value;
unset($missingOptions[$option]);
} else {
$invalidOptions[] = $option;
}
}
} elseif (null !== $options && !(\is_array($options) && 0 === \count($options))) {
if (null === $defaultOption) {
throw new ConstraintDefinitionException(\sprintf('No default option is configured for constraint "%s".', static::class));
}
if (\array_key_exists($defaultOption, $knownOptions)) {
$normalizedOptions[$defaultOption] = $options;
unset($missingOptions[$defaultOption]);
} else {
$invalidOptions[] = $defaultOption;
}
}
if (\count($invalidOptions) > 0) {
throw new InvalidOptionsException(\sprintf('The options "%s" do not exist in constraint "%s".', implode('", "', $invalidOptions), static::class), $invalidOptions);
}
if (\count($missingOptions) > 0) {
throw new MissingOptionsException(\sprintf('The options "%s" must be set for constraint "%s".', implode('", "', array_keys($missingOptions)), static::class), array_keys($missingOptions));
}
return $normalizedOptions;
}
/**
* Sets the value of a lazily initialized option.
*
* Corresponding properties are added to the object on first access. Hence
* this method will be called at most once per constraint instance and
* option name.
*
* @return void
*
* @throws InvalidOptionsException If an invalid option name is given
*/
public function __set(string $option, mixed $value)
{
if ('groups' === $option) {
$this->groups = (array) $value;
return;
}
throw new InvalidOptionsException(\sprintf('The option "%s" does not exist in constraint "%s".', $option, static::class), [$option]);
}
/**
* Returns the value of a lazily initialized option.
*
* Corresponding properties are added to the object on first access. Hence
* this method will be called at most once per constraint instance and
* option name.
*
* @throws InvalidOptionsException If an invalid option name is given
*/
public function __get(string $option): mixed
{
if ('groups' === $option) {
$this->groups = [self::DEFAULT_GROUP];
return $this->groups;
}
throw new InvalidOptionsException(\sprintf('The option "%s" does not exist in constraint "%s".', $option, static::class), [$option]);
}
public function __isset(string $option): bool
{
return 'groups' === $option;
}
/**
* Adds the given group if this constraint is in the Default group.
*
* @return void
*/
public function addImplicitGroupName(string $group)
{
if (null === $this->groups && \array_key_exists('groups', (array) $this)) {
throw new \LogicException(\sprintf('"%s::$groups" is set to null. Did you forget to call "%s::__construct()"?', static::class, self::class));
}
if (\in_array(self::DEFAULT_GROUP, $this->groups) && !\in_array($group, $this->groups)) {
$this->groups[] = $group;
}
}
/**
* Returns the name of the default option.
*
* Override this method to define a default option.
*
* @return string|null
*
* @see __construct()
*/
public function getDefaultOption()
{
return null;
}
/**
* Returns the name of the required options.
*
* Override this method if you want to define required options.
*
* @return string[]
*
* @see __construct()
*/
public function getRequiredOptions()
{
return [];
}
/**
* Returns the name of the class that validates this constraint.
*
* By default, this is the fully qualified name of the constraint class
* suffixed with "Validator". You can override this method to change that
* behavior.
*
* @return string
*/
public function validatedBy()
{
return static::class.'Validator';
}
/**
* Returns whether the constraint can be put onto classes, properties or
* both.
*
* This method should return one or more of the constants
* Constraint::CLASS_CONSTRAINT and Constraint::PROPERTY_CONSTRAINT.
*
* @return string|string[] One or more constant values
*/
public function getTargets()
{
return self::PROPERTY_CONSTRAINT;
}
/**
* Optimizes the serialized value to minimize storage space.
*
* @internal
*/
public function __sleep(): array
{
// Initialize "groups" option if it is not set
$this->groups;
return array_keys(get_object_vars($this));
}
}

View File

@@ -0,0 +1,157 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Base class for constraint validators.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
abstract class ConstraintValidator implements ConstraintValidatorInterface
{
/**
* Whether to format {@link \DateTime} objects, either with the {@link \IntlDateFormatter}
* (if it is available) or as RFC-3339 dates ("Y-m-d H:i:s").
*/
public const PRETTY_DATE = 1;
/**
* Whether to cast objects with a "__toString()" method to strings.
*/
public const OBJECT_TO_STRING = 2;
/**
* @var ExecutionContextInterface
*/
protected $context;
/**
* @return void
*/
public function initialize(ExecutionContextInterface $context)
{
$this->context = $context;
}
/**
* Returns a string representation of the type of the value.
*
* This method should be used if you pass the type of a value as
* message parameter to a constraint violation. Note that such
* parameters should usually not be included in messages aimed at
* non-technical people.
*/
protected function formatTypeOf(mixed $value): string
{
return get_debug_type($value);
}
/**
* Returns a string representation of the value.
*
* This method returns the equivalent PHP tokens for most scalar types
* (i.e. "false" for false, "1" for 1 etc.). Strings are always wrapped
* in double quotes ("). Objects, arrays and resources are formatted as
* "object", "array" and "resource". If the $format bitmask contains
* the PRETTY_DATE bit, then {@link \DateTime} objects will be formatted
* with the {@link \IntlDateFormatter}. If it is not available, they will be
* formatted as RFC-3339 dates ("Y-m-d H:i:s").
*
* Be careful when passing message parameters to a constraint violation
* that (may) contain objects, arrays or resources. These parameters
* should only be displayed for technical users. Non-technical users
* won't know what an "object", "array" or "resource" is and will be
* confused by the violation message.
*
* @param int $format A bitwise combination of the format constants in this class
*/
protected function formatValue(mixed $value, int $format = 0): string
{
if (($format & self::PRETTY_DATE) && $value instanceof \DateTimeInterface) {
if (class_exists(\IntlDateFormatter::class)) {
$formatter = new \IntlDateFormatter(\Locale::getDefault(), \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, 'UTC');
return $formatter->format(new \DateTimeImmutable(
$value->format('Y-m-d H:i:s.u'),
new \DateTimeZone('UTC')
));
}
return $value->format('Y-m-d H:i:s');
}
if ($value instanceof \UnitEnum) {
return $value->name;
}
if (\is_object($value)) {
if (($format & self::OBJECT_TO_STRING) && $value instanceof \Stringable) {
return $value->__toString();
}
return 'object';
}
if (\is_array($value)) {
return 'array';
}
if (\is_string($value)) {
return '"'.$value.'"';
}
if (\is_resource($value)) {
return 'resource';
}
if (null === $value) {
return 'null';
}
if (false === $value) {
return 'false';
}
if (true === $value) {
return 'true';
}
if (is_nan($value)) {
return 'NAN';
}
return (string) $value;
}
/**
* Returns a string representation of a list of values.
*
* Each of the values is converted to a string using
* {@link formatValue()}. The values are then concatenated with commas.
*
* @param array $values A list of values
* @param int $format A bitwise combination of the format
* constants in this class
*
* @see formatValue()
*/
protected function formatValues(array $values, int $format = 0): string
{
foreach ($values as $key => $value) {
$values[$key] = $this->formatValue($value, $format);
}
return implode(', ', $values);
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
use Symfony\Component\Validator\Constraints\ExpressionValidator;
/**
* Default implementation of the ConstraintValidatorFactoryInterface.
*
* This enforces the convention that the validatedBy() method on any
* Constraint will return the class name of the ConstraintValidator that
* should validate the Constraint.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
{
protected $validators = [];
public function __construct(array $validators = [])
{
$this->validators = $validators;
}
public function getInstance(Constraint $constraint): ConstraintValidatorInterface
{
if ('validator.expression' === $name = $class = $constraint->validatedBy()) {
$class = ExpressionValidator::class;
}
return $this->validators[$name] ??= new $class();
}
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
/**
* Specifies an object able to return the correct ConstraintValidatorInterface
* instance given a Constraint object.
*/
interface ConstraintValidatorFactoryInterface
{
/**
* Given a Constraint, this returns the ConstraintValidatorInterface
* object that should be used to verify its validity.
*/
public function getInstance(Constraint $constraint): ConstraintValidatorInterface;
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface ConstraintValidatorInterface
{
/**
* Initializes the constraint validator.
*
* @return void
*/
public function initialize(ExecutionContextInterface $context);
/**
* Checks if the passed value is valid.
*
* @return void
*/
public function validate(mixed $value, Constraint $constraint);
}

View File

@@ -0,0 +1,144 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
/**
* Default implementation of {@ConstraintViolationInterface}.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class ConstraintViolation implements ConstraintViolationInterface
{
private string|\Stringable $message;
private ?string $messageTemplate;
private array $parameters;
private ?int $plural;
private mixed $root;
private ?string $propertyPath;
private mixed $invalidValue;
private ?Constraint $constraint;
private ?string $code;
private mixed $cause;
/**
* Creates a new constraint violation.
*
* @param string|\Stringable $message The violation message as a string or a stringable object
* @param string|null $messageTemplate The raw violation message
* @param array $parameters The parameters to substitute in the
* raw violation message
* @param mixed $root The value originally passed to the
* validator
* @param string|null $propertyPath The property path from the root
* value to the invalid value
* @param mixed $invalidValue The invalid value that caused this
* violation
* @param int|null $plural The number for determining the plural
* form when translating the message
* @param string|null $code The error code of the violation
* @param Constraint|null $constraint The constraint whose validation
* caused the violation
* @param mixed $cause The cause of the violation
*/
public function __construct(string|\Stringable $message, ?string $messageTemplate, array $parameters, mixed $root, ?string $propertyPath, mixed $invalidValue, ?int $plural = null, ?string $code = null, ?Constraint $constraint = null, mixed $cause = null)
{
$this->message = $message;
$this->messageTemplate = $messageTemplate;
$this->parameters = $parameters;
$this->plural = $plural;
$this->root = $root;
$this->propertyPath = $propertyPath;
$this->invalidValue = $invalidValue;
$this->constraint = $constraint;
$this->code = $code;
$this->cause = $cause;
}
public function __toString(): string
{
if (\is_object($this->root)) {
$class = 'Object('.$this->root::class.')';
} elseif (\is_array($this->root)) {
$class = 'Array';
} else {
$class = (string) $this->root;
}
$propertyPath = (string) $this->propertyPath;
if ('' !== $propertyPath && '[' !== $propertyPath[0] && '' !== $class) {
$class .= '.';
}
if (null !== ($code = $this->code) && '' !== $code) {
$code = ' (code '.$code.')';
}
return $class.$propertyPath.":\n ".$this->getMessage().$code;
}
public function getMessageTemplate(): string
{
return (string) $this->messageTemplate;
}
public function getParameters(): array
{
return $this->parameters;
}
public function getPlural(): ?int
{
return $this->plural;
}
public function getMessage(): string|\Stringable
{
return $this->message;
}
public function getRoot(): mixed
{
return $this->root;
}
public function getPropertyPath(): string
{
return (string) $this->propertyPath;
}
public function getInvalidValue(): mixed
{
return $this->invalidValue;
}
/**
* Returns the constraint whose validation caused the violation.
*/
public function getConstraint(): ?Constraint
{
return $this->constraint;
}
/**
* Returns the cause of the violation.
*/
public function getCause(): mixed
{
return $this->cause;
}
public function getCode(): ?string
{
return $this->code;
}
}

View File

@@ -0,0 +1,116 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
/**
* A violation of a constraint that happened during validation.
*
* For each constraint that fails during validation one or more violations are
* created. The violations store the violation message, the path to the failing
* element in the validation graph and the root element that was originally
* passed to the validator. For example, take the following graph:
*
* (Person)---(firstName: string)
* \
* (address: Address)---(street: string)
*
* If the <tt>Person</tt> object is validated and validation fails for the
* "firstName" property, the generated violation has the <tt>Person</tt>
* instance as root and the property path "firstName". If validation fails
* for the "street" property of the related <tt>Address</tt> instance, the root
* element is still the person, but the property path is "address.street".
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @method Constraint|null getConstraint() Returns the constraint whose validation caused the violation. Not implementing it is deprecated since Symfony 6.3.
* @method mixed getCause() Returns the cause of the violation. Not implementing it is deprecated since Symfony 6.2.
* @method string __toString() Converts the violation into a string for debugging purposes. Not implementing it is deprecated since Symfony 6.1.
*/
interface ConstraintViolationInterface
{
/**
* Returns the violation message.
*/
public function getMessage(): string|\Stringable;
/**
* Returns the raw violation message.
*
* The raw violation message contains placeholders for the parameters
* returned by {@link getParameters}. Typically you'll pass the
* message template and parameters to a translation engine.
*/
public function getMessageTemplate(): string;
/**
* Returns the parameters to be inserted into the raw violation message.
*
* @return array a possibly empty list of parameters indexed by the names
* that appear in the message template
*
* @see getMessageTemplate()
*/
public function getParameters(): array;
/**
* Returns a number for pluralizing the violation message.
*
* For example, the message template could have different translation based
* on a parameter "choices":
*
* <ul>
* <li>Please select exactly one entry. (choices=1)</li>
* <li>Please select two entries. (choices=2)</li>
* </ul>
*
* This method returns the value of the parameter for choosing the right
* pluralization form (in this case "choices").
*/
public function getPlural(): ?int;
/**
* Returns the root element of the validation.
*
* @return mixed The value that was passed originally to the validator when
* the validation was started. Because the validator traverses
* the object graph, the value at which the violation occurs
* is not necessarily the value that was originally validated.
*/
public function getRoot(): mixed;
/**
* Returns the property path from the root element to the violation.
*
* @return string The property path indicates how the validator reached
* the invalid value from the root element. If the root
* element is a <tt>Person</tt> instance with a property
* "address" that contains an <tt>Address</tt> instance
* with an invalid property "street", the generated property
* path is "address.street". Property access is denoted by
* dots, while array access is denoted by square brackets,
* for example "addresses[1].street".
*/
public function getPropertyPath(): string;
/**
* Returns the value that caused the violation.
*
* @return mixed the invalid value that caused the validated constraint to
* fail
*/
public function getInvalidValue(): mixed;
/**
* Returns a machine-digestible error code for the violation.
*/
public function getCode(): ?string;
}

View File

@@ -0,0 +1,163 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
use Symfony\Component\Validator\Exception\OutOfBoundsException;
/**
* Default implementation of {@ConstraintViolationListInterface}.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @implements \IteratorAggregate<int, ConstraintViolationInterface>
*/
class ConstraintViolationList implements \IteratorAggregate, ConstraintViolationListInterface
{
/**
* @var list<ConstraintViolationInterface>
*/
private array $violations = [];
/**
* Creates a new constraint violation list.
*
* @param iterable<mixed, ConstraintViolationInterface> $violations The constraint violations to add to the list
*/
public function __construct(iterable $violations = [])
{
foreach ($violations as $violation) {
$this->add($violation);
}
}
public static function createFromMessage(string $message): self
{
$self = new self();
$self->add(new ConstraintViolation($message, '', [], null, '', null));
return $self;
}
public function __toString(): string
{
$string = '';
foreach ($this->violations as $violation) {
$string .= $violation."\n";
}
return $string;
}
/**
* @return void
*/
public function add(ConstraintViolationInterface $violation)
{
$this->violations[] = $violation;
}
/**
* @return void
*/
public function addAll(ConstraintViolationListInterface $otherList)
{
foreach ($otherList as $violation) {
$this->violations[] = $violation;
}
}
public function get(int $offset): ConstraintViolationInterface
{
if (!isset($this->violations[$offset])) {
throw new OutOfBoundsException(\sprintf('The offset "%s" does not exist.', $offset));
}
return $this->violations[$offset];
}
public function has(int $offset): bool
{
return isset($this->violations[$offset]);
}
/**
* @return void
*/
public function set(int $offset, ConstraintViolationInterface $violation)
{
$this->violations[$offset] = $violation;
}
/**
* @return void
*/
public function remove(int $offset)
{
unset($this->violations[$offset]);
}
/**
* @return \ArrayIterator<int, ConstraintViolationInterface>
*/
public function getIterator(): \ArrayIterator
{
return new \ArrayIterator($this->violations);
}
public function count(): int
{
return \count($this->violations);
}
public function offsetExists(mixed $offset): bool
{
return $this->has($offset);
}
public function offsetGet(mixed $offset): ConstraintViolationInterface
{
return $this->get($offset);
}
public function offsetSet(mixed $offset, mixed $violation): void
{
if (null === $offset) {
$this->add($violation);
} else {
$this->set($offset, $violation);
}
}
public function offsetUnset(mixed $offset): void
{
$this->remove($offset);
}
/**
* Creates iterator for errors with specific codes.
*
* @param string|string[] $codes The codes to find
*/
public function findByCodes(string|array $codes): static
{
$codes = (array) $codes;
$violations = [];
foreach ($this as $violation) {
if (\in_array($violation->getCode(), $codes, true)) {
$violations[] = $violation;
}
}
return new static($violations);
}
}

View File

@@ -0,0 +1,75 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
use Symfony\Component\Validator\Exception\OutOfBoundsException;
/**
* A list of constraint violations.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @extends \ArrayAccess<int, ConstraintViolationInterface>
* @extends \Traversable<int, ConstraintViolationInterface>
*
* @method string __toString() Converts the violation into a string for debugging purposes. Not implementing it is deprecated since Symfony 6.1.
*/
interface ConstraintViolationListInterface extends \Traversable, \Countable, \ArrayAccess
{
/**
* Adds a constraint violation to this list.
*
* @return void
*/
public function add(ConstraintViolationInterface $violation);
/**
* Merges an existing violation list into this list.
*
* @return void
*/
public function addAll(self $otherList);
/**
* Returns the violation at a given offset.
*
* @param int $offset The offset of the violation
*
* @throws OutOfBoundsException if the offset does not exist
*/
public function get(int $offset): ConstraintViolationInterface;
/**
* Returns whether the given offset exists.
*
* @param int $offset The violation offset
*/
public function has(int $offset): bool;
/**
* Sets a violation at a given offset.
*
* @param int $offset The violation offset
*
* @return void
*/
public function set(int $offset, ConstraintViolationInterface $violation);
/**
* Removes a violation at a given offset.
*
* @param int $offset The offset to remove
*
* @return void
*/
public function remove(int $offset);
}

View File

@@ -0,0 +1,61 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\LogicException;
/**
* Used for the comparison of values.
*
* @author Daniel Holmes <daniel@danielholmes.org>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
abstract class AbstractComparison extends Constraint
{
public $message;
public $value;
public $propertyPath;
public function __construct(mixed $value = null, ?string $propertyPath = null, ?string $message = null, ?array $groups = null, mixed $payload = null, array $options = [])
{
if (\is_array($value)) {
$options = array_merge($value, $options);
} elseif (null !== $value) {
$options['value'] = $value;
}
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
$this->propertyPath = $propertyPath ?? $this->propertyPath;
if (null === $this->value && null === $this->propertyPath) {
throw new ConstraintDefinitionException(\sprintf('The "%s" constraint requires either the "value" or "propertyPath" option to be set.', static::class));
}
if (null !== $this->value && null !== $this->propertyPath) {
throw new ConstraintDefinitionException(\sprintf('The "%s" constraint requires only one of the "value" or "propertyPath" options to be set, not both.', static::class));
}
if (null !== $this->propertyPath && !class_exists(PropertyAccess::class)) {
throw new LogicException(\sprintf('The "%s" constraint requires the Symfony PropertyAccess component to use the "propertyPath" option. Try running "composer require symfony/property-access".', static::class));
}
}
public function getDefaultOption(): ?string
{
return 'value';
}
}

View File

@@ -0,0 +1,110 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* Provides a base class for the validation of property comparisons.
*
* @author Daniel Holmes <daniel@danielholmes.org>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
abstract class AbstractComparisonValidator extends ConstraintValidator
{
private ?PropertyAccessorInterface $propertyAccessor;
public function __construct(?PropertyAccessorInterface $propertyAccessor = null)
{
$this->propertyAccessor = $propertyAccessor;
}
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof AbstractComparison) {
throw new UnexpectedTypeException($constraint, AbstractComparison::class);
}
if (null === $value) {
return;
}
if ($path = $constraint->propertyPath) {
if (null === $object = $this->context->getObject()) {
return;
}
try {
$comparedValue = $this->getPropertyAccessor()->getValue($object, $path);
} catch (NoSuchPropertyException $e) {
throw new ConstraintDefinitionException(\sprintf('Invalid property path "%s" provided to "%s" constraint: ', $path, get_debug_type($constraint)).$e->getMessage(), 0, $e);
} catch (UninitializedPropertyException) {
$comparedValue = null;
}
} else {
$comparedValue = $constraint->value;
}
// Convert strings to date-time objects if comparing to another date-time object
// This allows to compare with any date/time value supported by date-time constructors:
// https://php.net/datetime.formats
if (\is_string($comparedValue) && $value instanceof \DateTimeInterface) {
try {
$comparedValue = new $value($comparedValue);
} catch (\Exception) {
throw new ConstraintDefinitionException(\sprintf('The compared value "%s" could not be converted to a "%s" instance in the "%s" constraint.', $comparedValue, get_debug_type($value), get_debug_type($constraint)));
}
}
if (!$this->compareValues($value, $comparedValue)) {
$violationBuilder = $this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value, self::OBJECT_TO_STRING | self::PRETTY_DATE))
->setParameter('{{ compared_value }}', $this->formatValue($comparedValue, self::OBJECT_TO_STRING | self::PRETTY_DATE))
->setParameter('{{ compared_value_type }}', $this->formatTypeOf($comparedValue))
->setCode($this->getErrorCode());
if (null !== $path) {
$violationBuilder->setParameter('{{ compared_value_path }}', $path);
}
$violationBuilder->addViolation();
}
}
private function getPropertyAccessor(): PropertyAccessorInterface
{
return $this->propertyAccessor ??= PropertyAccess::createPropertyAccessor();
}
/**
* Compares the two given values to find if their relationship is valid.
*/
abstract protected function compareValues(mixed $value1, mixed $value2): bool;
/**
* Returns the error code used if the comparison fails.
*/
protected function getErrorCode(): ?string
{
return null;
}
}

View File

@@ -0,0 +1,44 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class All extends Composite
{
public $constraints = [];
public function __construct(mixed $constraints = null, ?array $groups = null, mixed $payload = null)
{
parent::__construct($constraints ?? [], $groups, $payload);
}
public function getDefaultOption(): ?string
{
return 'constraints';
}
public function getRequiredOptions(): array
{
return ['constraints'];
}
protected function getCompositeOption(): string
{
return 'constraints';
}
}

View File

@@ -0,0 +1,49 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class AllValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof All) {
throw new UnexpectedTypeException($constraint, All::class);
}
if (null === $value) {
return;
}
if (!\is_array($value) && !$value instanceof \Traversable) {
throw new UnexpectedValueException($value, 'iterable');
}
$context = $this->context;
$validator = $context->getValidator()->inContext($context);
foreach ($value as $key => $element) {
$validator->atPath('['.$key.']')->validate($element, $constraint->constraints);
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Przemysław Bogusz <przemyslaw.bogusz@tubotax.pl>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class AtLeastOneOf extends Composite
{
public const AT_LEAST_ONE_OF_ERROR = 'f27e6d6c-261a-4056-b391-6673a623531c';
protected const ERROR_NAMES = [
self::AT_LEAST_ONE_OF_ERROR => 'AT_LEAST_ONE_OF_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $constraints = [];
public $message = 'This value should satisfy at least one of the following constraints:';
public $messageCollection = 'Each element of this collection should satisfy its own set of constraints.';
public $includeInternalMessages = true;
public function __construct(mixed $constraints = null, ?array $groups = null, mixed $payload = null, ?string $message = null, ?string $messageCollection = null, ?bool $includeInternalMessages = null)
{
parent::__construct($constraints ?? [], $groups, $payload);
$this->message = $message ?? $this->message;
$this->messageCollection = $messageCollection ?? $this->messageCollection;
$this->includeInternalMessages = $includeInternalMessages ?? $this->includeInternalMessages;
}
public function getDefaultOption(): ?string
{
return 'constraints';
}
public function getRequiredOptions(): array
{
return ['constraints'];
}
protected function getCompositeOption(): string
{
return 'constraints';
}
}

View File

@@ -0,0 +1,73 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* @author Przemysław Bogusz <przemyslaw.bogusz@tubotax.pl>
*/
class AtLeastOneOfValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof AtLeastOneOf) {
throw new UnexpectedTypeException($constraint, AtLeastOneOf::class);
}
$validator = $this->context->getValidator();
// Build a first violation to have the base message of the constraint translated
$baseMessageContext = clone $this->context;
$baseMessageContext->buildViolation($constraint->message)->addViolation();
$baseViolations = $baseMessageContext->getViolations();
$messages = [(string) $baseViolations->get(\count($baseViolations) - 1)->getMessage()];
foreach ($constraint->constraints as $key => $item) {
if (!\in_array($this->context->getGroup(), $item->groups, true)) {
continue;
}
$context = $this->context;
$executionContext = clone $this->context;
$executionContext->setNode($value, $this->context->getObject(), $this->context->getMetadata(), $this->context->getPropertyPath());
$violations = $validator->inContext($executionContext)->validate($value, $item, $this->context->getGroup())->getViolations();
$this->context = $context;
if (\count($this->context->getViolations()) === \count($violations)) {
return;
}
if ($constraint->includeInternalMessages) {
$message = ' ['.($key + 1).'] ';
if ($item instanceof All || $item instanceof Collection) {
$message .= $constraint->messageCollection;
} else {
$message .= $violations->get(\count($violations) - 1)->getMessage();
}
$messages[] = $message;
}
}
$this->context->buildViolation(implode('', $messages))
->setCode(AtLeastOneOf::AT_LEAST_ONE_OF_ERROR)
->addViolation()
;
}
}

View File

@@ -0,0 +1,75 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Intl\Countries;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\LogicException;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Michael Hirschler <michael.vhirsch@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Bic extends Constraint
{
public const INVALID_LENGTH_ERROR = '66dad313-af0b-4214-8566-6c799be9789c';
public const INVALID_CHARACTERS_ERROR = 'f424c529-7add-4417-8f2d-4b656e4833e2';
public const INVALID_BANK_CODE_ERROR = '00559357-6170-4f29-aebd-d19330aa19cf';
public const INVALID_COUNTRY_CODE_ERROR = '1ce76f8d-3c1f-451c-9e62-fe9c3ed486ae';
public const INVALID_CASE_ERROR = '11884038-3312-4ae5-9d04-699f782130c7';
public const INVALID_IBAN_COUNTRY_CODE_ERROR = '29a2c3bb-587b-4996-b6f5-53081364cea5';
protected const ERROR_NAMES = [
self::INVALID_LENGTH_ERROR => 'INVALID_LENGTH_ERROR',
self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR',
self::INVALID_BANK_CODE_ERROR => 'INVALID_BANK_CODE_ERROR',
self::INVALID_COUNTRY_CODE_ERROR => 'INVALID_COUNTRY_CODE_ERROR',
self::INVALID_CASE_ERROR => 'INVALID_CASE_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This is not a valid Business Identifier Code (BIC).';
public $ibanMessage = 'This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.';
public $iban;
public $ibanPropertyPath;
public function __construct(?array $options = null, ?string $message = null, ?string $iban = null, ?string $ibanPropertyPath = null, ?string $ibanMessage = null, ?array $groups = null, mixed $payload = null)
{
if (!class_exists(Countries::class)) {
throw new LogicException('The Intl component is required to use the Bic constraint. Try running "composer require symfony/intl".');
}
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
$this->ibanMessage = $ibanMessage ?? $this->ibanMessage;
$this->iban = $iban ?? $this->iban;
$this->ibanPropertyPath = $ibanPropertyPath ?? $this->ibanPropertyPath;
if (null !== $this->iban && null !== $this->ibanPropertyPath) {
throw new ConstraintDefinitionException('The "iban" and "ibanPropertyPath" options of the Iban constraint cannot be used at the same time.');
}
if (null !== $this->ibanPropertyPath && !class_exists(PropertyAccess::class)) {
throw new LogicException(\sprintf('The "symfony/property-access" component is required to use the "%s" constraint with the "ibanPropertyPath" option. Try running "composer require symfony/property-access".', self::class));
}
}
}

View File

@@ -0,0 +1,167 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Intl\Countries;
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\LogicException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Michael Hirschler <michael.vhirsch@gmail.com>
*
* @see https://en.wikipedia.org/wiki/ISO_9362#Structure
*/
class BicValidator extends ConstraintValidator
{
// Reference: https://www.iban.com/structure
private const BIC_COUNTRY_TO_IBAN_COUNTRY_MAP = [
// FR includes:
'GF' => 'FR', // French Guiana
'PF' => 'FR', // French Polynesia
'TF' => 'FR', // French Southern Territories
'GP' => 'FR', // Guadeloupe
'MQ' => 'FR', // Martinique
'YT' => 'FR', // Mayotte
'NC' => 'FR', // New Caledonia
'RE' => 'FR', // Reunion
'BL' => 'FR', // Saint Barthelemy
'MF' => 'FR', // Saint Martin (French part)
'PM' => 'FR', // Saint Pierre and Miquelon
'WF' => 'FR', // Wallis and Futuna Islands
// GB includes:
'JE' => 'GB', // Jersey
'IM' => 'GB', // Isle of Man
'GG' => 'GB', // Guernsey
'VG' => 'GB', // British Virgin Islands
// FI includes:
'AX' => 'FI', // Aland Islands
// ES includes:
'IC' => 'ES', // Canary Islands
'EA' => 'ES', // Ceuta and Melilla
];
private ?PropertyAccessor $propertyAccessor;
public function __construct(?PropertyAccessor $propertyAccessor = null)
{
$this->propertyAccessor = $propertyAccessor;
}
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Bic) {
throw new UnexpectedTypeException($constraint, Bic::class);
}
if (null === $value || '' === $value) {
return;
}
if (!\is_scalar($value) && !$value instanceof \Stringable) {
throw new UnexpectedValueException($value, 'string');
}
$canonicalize = str_replace(' ', '', $value);
// the bic must be either 8 or 11 characters long
if (!\in_array(\strlen($canonicalize), [8, 11])) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Bic::INVALID_LENGTH_ERROR)
->addViolation();
return;
}
// must contain alphanumeric values only
if (!ctype_alnum($canonicalize)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Bic::INVALID_CHARACTERS_ERROR)
->addViolation();
return;
}
$bicCountryCode = substr($canonicalize, 4, 2);
if (!isset(self::BIC_COUNTRY_TO_IBAN_COUNTRY_MAP[$bicCountryCode]) && !Countries::exists($bicCountryCode)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Bic::INVALID_COUNTRY_CODE_ERROR)
->addViolation();
return;
}
// should contain uppercase characters only
if (strtoupper($canonicalize) !== $canonicalize) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Bic::INVALID_CASE_ERROR)
->addViolation();
return;
}
// check against an IBAN
$iban = $constraint->iban;
$path = $constraint->ibanPropertyPath;
if ($path && null !== $object = $this->context->getObject()) {
try {
$iban = $this->getPropertyAccessor()->getValue($object, $path);
} catch (NoSuchPropertyException $e) {
throw new ConstraintDefinitionException(\sprintf('Invalid property path "%s" provided to "%s" constraint: ', $path, get_debug_type($constraint)).$e->getMessage(), 0, $e);
} catch (UninitializedPropertyException) {
$iban = null;
}
}
if (!$iban) {
return;
}
$ibanCountryCode = substr($iban, 0, 2);
if (ctype_alpha($ibanCountryCode) && !$this->bicAndIbanCountriesMatch($bicCountryCode, $ibanCountryCode)) {
$this->context->buildViolation($constraint->ibanMessage)
->setParameter('{{ value }}', $this->formatValue($value))
->setParameter('{{ iban }}', $iban)
->setCode(Bic::INVALID_IBAN_COUNTRY_CODE_ERROR)
->addViolation();
}
}
private function getPropertyAccessor(): PropertyAccessor
{
if (null === $this->propertyAccessor) {
if (!class_exists(PropertyAccess::class)) {
throw new LogicException('Unable to use property path as the Symfony PropertyAccess component is not installed. Try running "composer require symfony/property-access".');
}
$this->propertyAccessor = PropertyAccess::createPropertyAccessor();
}
return $this->propertyAccessor;
}
private function bicAndIbanCountriesMatch(string $bicCountryCode, string $ibanCountryCode): bool
{
return $ibanCountryCode === $bicCountryCode || $ibanCountryCode === (self::BIC_COUNTRY_TO_IBAN_COUNTRY_MAP[$bicCountryCode] ?? null);
}
}

View File

@@ -0,0 +1,44 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Blank extends Constraint
{
public const NOT_BLANK_ERROR = '183ad2de-533d-4796-a439-6d3c3852b549';
protected const ERROR_NAMES = [
self::NOT_BLANK_ERROR => 'NOT_BLANK_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This value should be blank.';
public function __construct(?array $options = null, ?string $message = null, ?array $groups = null, mixed $payload = null)
{
parent::__construct($options ?? [], $groups, $payload);
$this->message = $message ?? $this->message;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class BlankValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Blank) {
throw new UnexpectedTypeException($constraint, Blank::class);
}
if ('' !== $value && null !== $value) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Blank::NOT_BLANK_ERROR)
->addViolation();
}
}
}

View File

@@ -0,0 +1,55 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
* @Target({"CLASS", "PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Callback extends Constraint
{
/**
* @var string|callable
*/
public $callback;
public function __construct(array|string|callable|null $callback = null, ?array $groups = null, mixed $payload = null, array $options = [])
{
// Invocation through annotations with an array parameter only
if (\is_array($callback) && 1 === \count($callback) && isset($callback['value'])) {
$callback = $callback['value'];
}
if (!\is_array($callback) || (!isset($callback['callback']) && !isset($callback['groups']) && !isset($callback['payload']))) {
$options['callback'] = $callback;
} else {
$options = array_merge($callback, $options);
}
parent::__construct($options, $groups, $payload);
}
public function getDefaultOption(): ?string
{
return 'callback';
}
public function getTargets(): string|array
{
return [self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT];
}
}

View File

@@ -0,0 +1,61 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* Validator for Callback constraint.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class CallbackValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $object, Constraint $constraint)
{
if (!$constraint instanceof Callback) {
throw new UnexpectedTypeException($constraint, Callback::class);
}
$method = $constraint->callback;
if ($method instanceof \Closure) {
$method($object, $this->context, $constraint->payload);
} elseif (\is_array($method)) {
if (!\is_callable($method)) {
if (isset($method[0]) && \is_object($method[0])) {
$method[0] = $method[0]::class;
}
throw new ConstraintDefinitionException(json_encode($method).' targeted by Callback constraint is not a valid callable.');
}
$method($object, $this->context, $constraint->payload);
} elseif (null !== $object) {
if (!method_exists($object, $method)) {
throw new ConstraintDefinitionException(\sprintf('Method "%s" targeted by Callback constraint does not exist in class "%s".', $method, get_debug_type($object)));
}
$reflMethod = new \ReflectionMethod($object, $method);
if ($reflMethod->isStatic()) {
$reflMethod->invoke(null, $object, $this->context, $constraint->payload);
} else {
$reflMethod->invoke($object, $this->context, $constraint->payload);
}
}
}
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* Metadata for the CardSchemeValidator.
*
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Tim Nagel <t.nagel@infinite.net.au>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class CardScheme extends Constraint
{
public const AMEX = 'AMEX';
public const CHINA_UNIONPAY = 'CHINA_UNIONPAY';
public const DINERS = 'DINERS';
public const DISCOVER = 'DISCOVER';
public const INSTAPAYMENT = 'INSTAPAYMENT';
public const JCB = 'JCB';
public const LASER = 'LASER';
public const MAESTRO = 'MAESTRO';
public const MASTERCARD = 'MASTERCARD';
public const MIR = 'MIR';
public const UATP = 'UATP';
public const VISA = 'VISA';
public const NOT_NUMERIC_ERROR = 'a2ad9231-e827-485f-8a1e-ef4d9a6d5c2e';
public const INVALID_FORMAT_ERROR = 'a8faedbf-1c2f-4695-8d22-55783be8efed';
protected const ERROR_NAMES = [
self::NOT_NUMERIC_ERROR => 'NOT_NUMERIC_ERROR',
self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'Unsupported card type or invalid card number.';
public $schemes;
public function __construct(array|string|null $schemes, ?string $message = null, ?array $groups = null, mixed $payload = null, array $options = [])
{
if (\is_array($schemes) && \is_string(key($schemes))) {
$options = array_merge($schemes, $options);
} elseif (null !== $schemes) {
$options['value'] = $schemes;
}
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
}
public function getDefaultOption(): ?string
{
return 'schemes';
}
public function getRequiredOptions(): array
{
return ['schemes'];
}
}

View File

@@ -0,0 +1,134 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* Validates that a card number belongs to a specified scheme.
*
* @author Tim Nagel <t.nagel@infinite.net.au>
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @see https://en.wikipedia.org/wiki/Payment_card_number
* @see https://www.regular-expressions.info/creditcard.html
*/
class CardSchemeValidator extends ConstraintValidator
{
protected $schemes = [
// American Express card numbers start with 34 or 37 and have 15 digits.
CardScheme::AMEX => [
'/^3[47][0-9]{13}$/D',
],
// China UnionPay cards start with 62 and have between 16 and 19 digits.
// Please note that these cards do not follow Luhn Algorithm as a checksum.
CardScheme::CHINA_UNIONPAY => [
'/^62[0-9]{14,17}$/D',
],
// Diners Club card numbers begin with 300 through 305, 36 or 38. All have 14 digits.
// There are Diners Club cards that begin with 5 and have 16 digits.
// These are a joint venture between Diners Club and MasterCard, and should be processed like a MasterCard.
CardScheme::DINERS => [
'/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/D',
],
// Discover card numbers begin with 6011, 622126 through 622925, 644 through 649 or 65.
// All have 16 digits.
CardScheme::DISCOVER => [
'/^6011[0-9]{12}$/D',
'/^64[4-9][0-9]{13}$/D',
'/^65[0-9]{14}$/D',
'/^622(12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|91[0-9]|92[0-5])[0-9]{10}$/D',
],
// InstaPayment cards begin with 637 through 639 and have 16 digits.
CardScheme::INSTAPAYMENT => [
'/^63[7-9][0-9]{13}$/D',
],
// JCB cards beginning with 2131 or 1800 have 15 digits.
// JCB cards beginning with 35 have 16 digits.
CardScheme::JCB => [
'/^(?:2131|1800|35[0-9]{3})[0-9]{11}$/D',
],
// Laser cards begin with either 6304, 6706, 6709 or 6771 and have between 16 and 19 digits.
CardScheme::LASER => [
'/^(6304|670[69]|6771)[0-9]{12,15}$/D',
],
// Maestro international cards begin with 675900..675999 and have between 12 and 19 digits.
// Maestro UK cards begin with either 500000..509999 or 560000..699999 and have between 12 and 19 digits.
CardScheme::MAESTRO => [
'/^(6759[0-9]{2})[0-9]{6,13}$/D',
'/^(50[0-9]{4})[0-9]{6,13}$/D',
'/^5[6-9][0-9]{10,17}$/D',
'/^6[0-9]{11,18}$/D',
],
// All MasterCard numbers start with the numbers 51 through 55. All have 16 digits.
// October 2016 MasterCard numbers can also start with 222100 through 272099.
CardScheme::MASTERCARD => [
'/^5[1-5][0-9]{14}$/D',
'/^2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12})$/D',
],
// Payment system MIR numbers start with 220, then 1 digit from 0 to 4, then between 12 and 15 digits
CardScheme::MIR => [
'/^220[0-4][0-9]{12,15}$/D',
],
// All UATP card numbers start with a 1 and have a length of 15 digits.
CardScheme::UATP => [
'/^1[0-9]{14}$/D',
],
// All Visa card numbers start with a 4 and have a length of 13, 16, or 19 digits.
CardScheme::VISA => [
'/^4([0-9]{12}|[0-9]{15}|[0-9]{18})$/D',
],
];
/**
* Validates a creditcard belongs to a specified scheme.
*
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof CardScheme) {
throw new UnexpectedTypeException($constraint, CardScheme::class);
}
if (null === $value || '' === $value) {
return;
}
if (!is_numeric($value)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(CardScheme::NOT_NUMERIC_ERROR)
->addViolation();
return;
}
$schemes = array_flip((array) $constraint->schemes);
$schemeRegexes = array_intersect_key($this->schemes, $schemes);
foreach ($schemeRegexes as $regexes) {
foreach ($regexes as $regex) {
if (preg_match($regex, $value)) {
return;
}
}
}
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(CardScheme::INVALID_FORMAT_ERROR)
->addViolation();
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
/**
* @Annotation
* @Target({"CLASS"})
*
* @author Jules Pietri <jules@heahprod.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class Cascade extends Constraint
{
public array $exclude = [];
public function __construct(array|string|null $exclude = null, ?array $options = null)
{
if (\is_array($exclude) && !array_is_list($exclude)) {
$options = array_merge($exclude, $options ?? []);
$options['exclude'] = array_flip((array) ($options['exclude'] ?? []));
} else {
$this->exclude = array_flip((array) $exclude);
}
if (\is_array($options) && \array_key_exists('groups', $options)) {
throw new ConstraintDefinitionException(\sprintf('The option "groups" is not supported by the constraint "%s".', __CLASS__));
}
parent::__construct($options);
}
public function getTargets(): string|array
{
return self::CLASS_CONSTRAINT;
}
}

View File

@@ -0,0 +1,95 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Choice extends Constraint
{
public const NO_SUCH_CHOICE_ERROR = '8e179f1b-97aa-4560-a02f-2a8b42e49df7';
public const TOO_FEW_ERROR = '11edd7eb-5872-4b6e-9f12-89923999fd0e';
public const TOO_MANY_ERROR = '9bd98e49-211c-433f-8630-fd1c2d0f08c3';
protected const ERROR_NAMES = [
self::NO_SUCH_CHOICE_ERROR => 'NO_SUCH_CHOICE_ERROR',
self::TOO_FEW_ERROR => 'TOO_FEW_ERROR',
self::TOO_MANY_ERROR => 'TOO_MANY_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $choices;
/** @var callable|string|null */
public $callback;
public $multiple = false;
public $strict = true;
public $min;
public $max;
public $message = 'The value you selected is not a valid choice.';
public $multipleMessage = 'One or more of the given values is invalid.';
public $minMessage = 'You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.';
public $maxMessage = 'You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.';
public bool $match = true;
public function getDefaultOption(): ?string
{
return 'choices';
}
public function __construct(
string|array $options = [],
?array $choices = null,
callable|string|null $callback = null,
?bool $multiple = null,
?bool $strict = null,
?int $min = null,
?int $max = null,
?string $message = null,
?string $multipleMessage = null,
?string $minMessage = null,
?string $maxMessage = null,
?array $groups = null,
mixed $payload = null,
?bool $match = null,
) {
if (\is_array($options) && $options && array_is_list($options)) {
$choices ??= $options;
$options = [];
}
if (null !== $choices) {
$options['value'] = $choices;
}
parent::__construct($options, $groups, $payload);
$this->callback = $callback ?? $this->callback;
$this->multiple = $multiple ?? $this->multiple;
$this->strict = $strict ?? $this->strict;
$this->min = $min ?? $this->min;
$this->max = $max ?? $this->max;
$this->message = $message ?? $this->message;
$this->multipleMessage = $multipleMessage ?? $this->multipleMessage;
$this->minMessage = $minMessage ?? $this->minMessage;
$this->maxMessage = $maxMessage ?? $this->maxMessage;
$this->match = $match ?? $this->match;
}
}

View File

@@ -0,0 +1,113 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\RuntimeException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* ChoiceValidator validates that the value is one of the expected values.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Florian Eckerstorfer <florian@eckerstorfer.org>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class ChoiceValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Choice) {
throw new UnexpectedTypeException($constraint, Choice::class);
}
if (!\is_array($constraint->choices) && !$constraint->callback) {
throw new ConstraintDefinitionException('Either "choices" or "callback" must be specified on constraint Choice.');
}
if (null === $value) {
return;
}
if ($constraint->multiple && !\is_array($value)) {
throw new UnexpectedValueException($value, 'array');
}
if ($constraint->callback) {
if (!\is_callable($choices = [$this->context->getObject(), $constraint->callback])
&& !\is_callable($choices = [$this->context->getClassName(), $constraint->callback])
&& !\is_callable($choices = $constraint->callback)
) {
throw new ConstraintDefinitionException('The Choice constraint expects a valid callback.');
}
$choices = $choices();
if (!\is_array($choices)) {
throw new ConstraintDefinitionException(\sprintf('The Choice constraint callback "%s" is expected to return an array, but returned "%s".', trim($this->formatValue($constraint->callback), '"'), get_debug_type($choices)));
}
} else {
$choices = $constraint->choices;
}
if (true !== $constraint->strict) {
throw new RuntimeException('The "strict" option of the Choice constraint should not be used.');
}
if ($constraint->multiple) {
foreach ($value as $_value) {
if ($constraint->match xor \in_array($_value, $choices, true)) {
$this->context->buildViolation($constraint->multipleMessage)
->setParameter('{{ value }}', $this->formatValue($_value))
->setParameter('{{ choices }}', $this->formatValues($choices))
->setCode(Choice::NO_SUCH_CHOICE_ERROR)
->setInvalidValue($_value)
->addViolation();
return;
}
}
$count = \count($value);
if (null !== $constraint->min && $count < $constraint->min) {
$this->context->buildViolation($constraint->minMessage)
->setParameter('{{ limit }}', $constraint->min)
->setPlural((int) $constraint->min)
->setCode(Choice::TOO_FEW_ERROR)
->addViolation();
return;
}
if (null !== $constraint->max && $count > $constraint->max) {
$this->context->buildViolation($constraint->maxMessage)
->setParameter('{{ limit }}', $constraint->max)
->setPlural((int) $constraint->max)
->setCode(Choice::TOO_MANY_ERROR)
->addViolation();
return;
}
} elseif ($constraint->match xor \in_array($value, $choices, true)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setParameter('{{ choices }}', $this->formatValues($choices))
->setCode(Choice::NO_SUCH_CHOICE_ERROR)
->addViolation();
}
}
}

View File

@@ -0,0 +1,85 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
/**
* Validates that a value is a valid CIDR notation.
*
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Sorin Pop <popsorin15@gmail.com>
* @author Calin Bolea <calin.bolea@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Cidr extends Constraint
{
public const INVALID_CIDR_ERROR = '5649e53a-5afb-47c5-a360-ffbab3be8567';
public const OUT_OF_RANGE_ERROR = 'b9f14a51-acbd-401a-a078-8c6b204ab32f';
protected const ERROR_NAMES = [
self::INVALID_CIDR_ERROR => 'INVALID_CIDR_ERROR',
self::OUT_OF_RANGE_ERROR => 'OUT_OF_RANGE_VIOLATION',
];
private const NET_MAXES = [
Ip::ALL => 128,
Ip::V4 => 32,
Ip::V6 => 128,
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $version = Ip::ALL;
public $message = 'This value is not a valid CIDR notation.';
public $netmaskRangeViolationMessage = 'The value of the netmask should be between {{ min }} and {{ max }}.';
public $netmaskMin = 0;
public $netmaskMax;
public function __construct(
?array $options = null,
?string $version = null,
?int $netmaskMin = null,
?int $netmaskMax = null,
?string $message = null,
?array $groups = null,
$payload = null,
) {
$this->version = $version ?? $options['version'] ?? $this->version;
if (!\array_key_exists($this->version, self::NET_MAXES)) {
throw new ConstraintDefinitionException(\sprintf('The option "version" must be one of "%s".', implode('", "', array_keys(self::NET_MAXES))));
}
$this->netmaskMin = $netmaskMin ?? $options['netmaskMin'] ?? $this->netmaskMin;
$this->netmaskMax = $netmaskMax ?? $options['netmaskMax'] ?? self::NET_MAXES[$this->version];
$this->message = $message ?? $this->message;
unset($options['netmaskMin'], $options['netmaskMax'], $options['version']);
if ($this->netmaskMin < 0 || $this->netmaskMax > self::NET_MAXES[$this->version] || $this->netmaskMin > $this->netmaskMax) {
throw new ConstraintDefinitionException(\sprintf('The netmask range must be between 0 and %d.', self::NET_MAXES[$this->version]));
}
parent::__construct($options, $groups, $payload);
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
class CidrValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint): void
{
if (!$constraint instanceof Cidr) {
throw new UnexpectedTypeException($constraint, Cidr::class);
}
if (null === $value || '' === $value) {
return;
}
if (!\is_string($value)) {
throw new UnexpectedValueException($value, 'string');
}
$cidrParts = explode('/', $value, 2);
if (!isset($cidrParts[1])
|| !ctype_digit($cidrParts[1])
|| '' === $cidrParts[0]
) {
$this->context
->buildViolation($constraint->message)
->setCode(Cidr::INVALID_CIDR_ERROR)
->addViolation();
return;
}
$ipAddress = $cidrParts[0];
$netmask = (int) $cidrParts[1];
$validV4 = Ip::V6 !== $constraint->version
&& filter_var($ipAddress, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)
&& $netmask <= 32;
$validV6 = Ip::V4 !== $constraint->version
&& filter_var($ipAddress, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6);
if (!$validV4 && !$validV6) {
$this->context
->buildViolation($constraint->message)
->setCode(Cidr::INVALID_CIDR_ERROR)
->addViolation();
return;
}
if ($netmask < $constraint->netmaskMin || $netmask > $constraint->netmaskMax) {
$this->context
->buildViolation($constraint->netmaskRangeViolationMessage)
->setParameter('{{ min }}', $constraint->netmaskMin)
->setParameter('{{ max }}', $constraint->netmaskMax)
->setCode(Cidr::OUT_OF_RANGE_ERROR)
->addViolation();
}
}
}

View File

@@ -0,0 +1,119 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Collection extends Composite
{
public const MISSING_FIELD_ERROR = '2fa2158c-2a7f-484b-98aa-975522539ff8';
public const NO_SUCH_FIELD_ERROR = '7703c766-b5d5-4cef-ace7-ae0dd82304e9';
protected const ERROR_NAMES = [
self::MISSING_FIELD_ERROR => 'MISSING_FIELD_ERROR',
self::NO_SUCH_FIELD_ERROR => 'NO_SUCH_FIELD_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $fields = [];
public $allowExtraFields = false;
public $allowMissingFields = false;
public $extraFieldsMessage = 'This field was not expected.';
public $missingFieldsMessage = 'This field is missing.';
public function __construct(mixed $fields = null, ?array $groups = null, mixed $payload = null, ?bool $allowExtraFields = null, ?bool $allowMissingFields = null, ?string $extraFieldsMessage = null, ?string $missingFieldsMessage = null)
{
if (self::isFieldsOption($fields)) {
$fields = ['fields' => $fields];
}
parent::__construct($fields, $groups, $payload);
$this->allowExtraFields = $allowExtraFields ?? $this->allowExtraFields;
$this->allowMissingFields = $allowMissingFields ?? $this->allowMissingFields;
$this->extraFieldsMessage = $extraFieldsMessage ?? $this->extraFieldsMessage;
$this->missingFieldsMessage = $missingFieldsMessage ?? $this->missingFieldsMessage;
}
/**
* @return void
*/
protected function initializeNestedConstraints()
{
parent::initializeNestedConstraints();
if (!\is_array($this->fields)) {
throw new ConstraintDefinitionException(\sprintf('The option "fields" is expected to be an array in constraint "%s".', __CLASS__));
}
foreach ($this->fields as $fieldName => $field) {
// the XmlFileLoader and YamlFileLoader pass the field Optional
// and Required constraint as an array with exactly one element
if (\is_array($field) && 1 == \count($field)) {
$this->fields[$fieldName] = $field = $field[0];
}
if (!$field instanceof Optional && !$field instanceof Required) {
$this->fields[$fieldName] = new Required($field);
}
}
}
public function getRequiredOptions(): array
{
return ['fields'];
}
protected function getCompositeOption(): string
{
return 'fields';
}
private static function isFieldsOption($options): bool
{
if (!\is_array($options)) {
return false;
}
foreach ($options as $optionOrField) {
if ($optionOrField instanceof Constraint) {
return true;
}
if (null === $optionOrField) {
continue;
}
if (!\is_array($optionOrField)) {
return false;
}
if ($optionOrField && !($optionOrField[0] ?? null) instanceof Constraint) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,86 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class CollectionValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Collection) {
throw new UnexpectedTypeException($constraint, Collection::class);
}
if (null === $value) {
return;
}
if (!\is_array($value) && !($value instanceof \Traversable && $value instanceof \ArrayAccess)) {
throw new UnexpectedValueException($value, 'array|(Traversable&ArrayAccess)');
}
// We need to keep the initialized context when CollectionValidator
// calls itself recursively (Collection constraints can be nested).
// Since the context of the validator is overwritten when initialize()
// is called for the nested constraint, the outer validator is
// acting on the wrong context when the nested validation terminates.
//
// A better solution - which should be approached in Symfony 3.0 - is to
// remove the initialize() method and pass the context as last argument
// to validate() instead.
$context = $this->context;
foreach ($constraint->fields as $field => $fieldConstraint) {
$existsInArray = \is_array($value) && \array_key_exists($field, $value);
$existsInArrayAccess = $value instanceof \ArrayAccess && $value->offsetExists($field);
if ($existsInArray || $existsInArrayAccess) {
if (\count($fieldConstraint->constraints) > 0) {
$context->getValidator()
->inContext($context)
->atPath('['.$field.']')
->validate($value[$field], $fieldConstraint->constraints);
}
} elseif (!$fieldConstraint instanceof Optional && !$constraint->allowMissingFields) {
$context->buildViolation($constraint->missingFieldsMessage)
->atPath('['.$field.']')
->setParameter('{{ field }}', $this->formatValue($field))
->setInvalidValue(null)
->setCode(Collection::MISSING_FIELD_ERROR)
->addViolation();
}
}
if (!$constraint->allowExtraFields) {
foreach ($value as $field => $fieldValue) {
if (!isset($constraint->fields[$field])) {
$context->buildViolation($constraint->extraFieldsMessage)
->atPath('['.$field.']')
->setParameter('{{ field }}', $this->formatValue($field))
->setInvalidValue($fieldValue)
->setCode(Collection::NO_SUCH_FIELD_ERROR)
->addViolation();
}
}
}
}
}

View File

@@ -0,0 +1,157 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
/**
* A constraint that is composed of other constraints.
*
* You should never use the nested constraint instances anywhere else, because
* their groups are adapted when passed to the constructor of this class.
*
* If you want to create your own composite constraint, extend this class and
* let {@link getCompositeOption()} return the name of the property which
* contains the nested constraints.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
abstract class Composite extends Constraint
{
/**
* The groups of the composite and its nested constraints are made
* consistent using the following strategy:
*
* - If groups are passed explicitly to the composite constraint, but
* not to the nested constraints, the options of the composite
* constraint are copied to the nested constraints;
*
* - If groups are passed explicitly to the nested constraints, but not
* to the composite constraint, the groups of all nested constraints
* are merged and used as groups for the composite constraint;
*
* - If groups are passed explicitly to both the composite and its nested
* constraints, the groups of the nested constraints must be a subset
* of the groups of the composite constraint. If not, a
* {@link ConstraintDefinitionException} is thrown.
*
* All this is done in the constructor, because constraints can then be
* cached. When constraints are loaded from the cache, no more group
* checks need to be done.
*/
public function __construct(mixed $options = null, ?array $groups = null, mixed $payload = null)
{
parent::__construct($options, $groups, $payload);
$this->initializeNestedConstraints();
/** @var Constraint[] $nestedConstraints */
$compositeOption = $this->getCompositeOption();
$nestedConstraints = $this->$compositeOption;
if (!\is_array($nestedConstraints)) {
$nestedConstraints = [$nestedConstraints];
}
foreach ($nestedConstraints as $constraint) {
if (!$constraint instanceof Constraint) {
if (\is_object($constraint)) {
$constraint = $constraint::class;
}
throw new ConstraintDefinitionException(\sprintf('The value "%s" is not an instance of Constraint in constraint "%s".', $constraint, static::class));
}
if ($constraint instanceof Valid) {
throw new ConstraintDefinitionException(\sprintf('The constraint Valid cannot be nested inside constraint "%s". You can only declare the Valid constraint directly on a field or method.', static::class));
}
}
if (!isset(((array) $this)['groups'])) {
$mergedGroups = [];
foreach ($nestedConstraints as $constraint) {
foreach ($constraint->groups as $group) {
$mergedGroups[$group] = true;
}
}
// prevent empty composite constraint to have empty groups
$this->groups = array_keys($mergedGroups) ?: [self::DEFAULT_GROUP];
$this->$compositeOption = $nestedConstraints;
return;
}
foreach ($nestedConstraints as $constraint) {
if (isset(((array) $constraint)['groups'])) {
$excessGroups = array_diff($constraint->groups, $this->groups);
if (\count($excessGroups) > 0) {
throw new ConstraintDefinitionException(\sprintf('The group(s) "%s" passed to the constraint "%s" should also be passed to its containing constraint "%s".', implode('", "', $excessGroups), get_debug_type($constraint), static::class));
}
} else {
$constraint->groups = $this->groups;
}
}
$this->$compositeOption = $nestedConstraints;
}
/**
* Implicit group names are forwarded to nested constraints.
*
* @return void
*/
public function addImplicitGroupName(string $group)
{
parent::addImplicitGroupName($group);
/** @var Constraint[] $nestedConstraints */
$nestedConstraints = $this->{$this->getCompositeOption()};
foreach ($nestedConstraints as $constraint) {
$constraint->addImplicitGroupName($group);
}
}
/**
* Returns the name of the property that contains the nested constraints.
*/
abstract protected function getCompositeOption(): string;
/**
* @internal Used by metadata
*
* @return Constraint[]
*/
public function getNestedConstraints(): array
{
/** @var Constraint[] $nestedConstraints */
return $this->{$this->getCompositeOption()};
}
/**
* Initializes the nested constraints.
*
* This method can be overwritten in subclasses to clean up the nested
* constraints passed to the constructor.
*
* @see Collection::initializeNestedConstraints()
*
* @return void
*/
protected function initializeNestedConstraints()
{
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
/**
* Extend this class to create a reusable set of constraints.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*/
abstract class Compound extends Composite
{
/** @var Constraint[] */
public $constraints = [];
public function __construct(mixed $options = null)
{
if (isset($options[$this->getCompositeOption()])) {
throw new ConstraintDefinitionException(\sprintf('You can\'t redefine the "%s" option. Use the "%s::getConstraints()" method instead.', $this->getCompositeOption(), __CLASS__));
}
$this->constraints = $this->getConstraints($this->normalizeOptions($options));
parent::__construct($options);
}
final protected function getCompositeOption(): string
{
return 'constraints';
}
final public function validatedBy(): string
{
return CompoundValidator::class;
}
/**
* @return Constraint[]
*/
abstract protected function getConstraints(array $options): array;
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*/
class CompoundValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Compound) {
throw new UnexpectedTypeException($constraint, Compound::class);
}
$context = $this->context;
$validator = $context->getValidator()->inContext($context);
$validator->validate($value, $constraint->constraints);
}
}

View File

@@ -0,0 +1,92 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\MissingOptionsException;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Count extends Constraint
{
public const TOO_FEW_ERROR = 'bef8e338-6ae5-4caf-b8e2-50e7b0579e69';
public const TOO_MANY_ERROR = '756b1212-697c-468d-a9ad-50dd783bb169';
public const NOT_EQUAL_COUNT_ERROR = '9fe5d43f-3784-4ece-a0e1-473fc02dadbc';
public const NOT_DIVISIBLE_BY_ERROR = DivisibleBy::NOT_DIVISIBLE_BY;
protected const ERROR_NAMES = [
self::TOO_FEW_ERROR => 'TOO_FEW_ERROR',
self::TOO_MANY_ERROR => 'TOO_MANY_ERROR',
self::NOT_EQUAL_COUNT_ERROR => 'NOT_EQUAL_COUNT_ERROR',
self::NOT_DIVISIBLE_BY_ERROR => 'NOT_DIVISIBLE_BY_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $minMessage = 'This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.';
public $maxMessage = 'This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.';
public $exactMessage = 'This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.';
public $divisibleByMessage = 'The number of elements in this collection should be a multiple of {{ compared_value }}.';
public $min;
public $max;
public $divisibleBy;
public function __construct(
int|array|null $exactly = null,
?int $min = null,
?int $max = null,
?int $divisibleBy = null,
?string $exactMessage = null,
?string $minMessage = null,
?string $maxMessage = null,
?string $divisibleByMessage = null,
?array $groups = null,
mixed $payload = null,
array $options = [],
) {
if (\is_array($exactly)) {
$options = array_merge($exactly, $options);
$exactly = $options['value'] ?? null;
}
$min ??= $options['min'] ?? null;
$max ??= $options['max'] ?? null;
unset($options['value'], $options['min'], $options['max']);
if (null !== $exactly && null === $min && null === $max) {
$min = $max = $exactly;
}
parent::__construct($options, $groups, $payload);
$this->min = $min;
$this->max = $max;
$this->divisibleBy = $divisibleBy ?? $this->divisibleBy;
$this->exactMessage = $exactMessage ?? $this->exactMessage;
$this->minMessage = $minMessage ?? $this->minMessage;
$this->maxMessage = $maxMessage ?? $this->maxMessage;
$this->divisibleByMessage = $divisibleByMessage ?? $this->divisibleByMessage;
if (null === $this->min && null === $this->max && null === $this->divisibleBy) {
throw new MissingOptionsException(\sprintf('Either option "min", "max" or "divisibleBy" must be given for constraint "%s".', __CLASS__), ['min', 'max', 'divisibleBy']);
}
}
}

View File

@@ -0,0 +1,83 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class CountValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Count) {
throw new UnexpectedTypeException($constraint, Count::class);
}
if (null === $value) {
return;
}
if (!\is_array($value) && !$value instanceof \Countable) {
throw new UnexpectedValueException($value, 'array|\Countable');
}
$count = \count($value);
if (null !== $constraint->max && $count > $constraint->max) {
$exactlyOptionEnabled = $constraint->min == $constraint->max;
$this->context->buildViolation($exactlyOptionEnabled ? $constraint->exactMessage : $constraint->maxMessage)
->setParameter('{{ count }}', $count)
->setParameter('{{ limit }}', $constraint->max)
->setInvalidValue($value)
->setPlural((int) $constraint->max)
->setCode($exactlyOptionEnabled ? Count::NOT_EQUAL_COUNT_ERROR : Count::TOO_MANY_ERROR)
->addViolation();
return;
}
if (null !== $constraint->min && $count < $constraint->min) {
$exactlyOptionEnabled = $constraint->min == $constraint->max;
$this->context->buildViolation($exactlyOptionEnabled ? $constraint->exactMessage : $constraint->minMessage)
->setParameter('{{ count }}', $count)
->setParameter('{{ limit }}', $constraint->min)
->setInvalidValue($value)
->setPlural((int) $constraint->min)
->setCode($exactlyOptionEnabled ? Count::NOT_EQUAL_COUNT_ERROR : Count::TOO_FEW_ERROR)
->addViolation();
return;
}
if (null !== $constraint->divisibleBy) {
$this->context
->getValidator()
->inContext($this->context)
->validate($count, [
new DivisibleBy([
'value' => $constraint->divisibleBy,
'message' => $constraint->divisibleByMessage,
]),
], $this->context->getGroup());
}
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Intl\Countries;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\LogicException;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Country extends Constraint
{
public const NO_SUCH_COUNTRY_ERROR = '8f900c12-61bd-455d-9398-996cd040f7f0';
protected const ERROR_NAMES = [
self::NO_SUCH_COUNTRY_ERROR => 'NO_SUCH_COUNTRY_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This value is not a valid country.';
public $alpha3 = false;
public function __construct(
?array $options = null,
?string $message = null,
?bool $alpha3 = null,
?array $groups = null,
mixed $payload = null,
) {
if (!class_exists(Countries::class)) {
throw new LogicException('The Intl component is required to use the Country constraint. Try running "composer require symfony/intl".');
}
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
$this->alpha3 = $alpha3 ?? $this->alpha3;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Intl\Countries;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* Validates whether a value is a valid country code.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class CountryValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Country) {
throw new UnexpectedTypeException($constraint, Country::class);
}
if (null === $value || '' === $value) {
return;
}
if (!\is_scalar($value) && !$value instanceof \Stringable) {
throw new UnexpectedValueException($value, 'string');
}
$value = (string) $value;
if ($constraint->alpha3 ? !Countries::alpha3CodeExists($value) : !Countries::exists($value)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Country::NO_SUCH_COUNTRY_ERROR)
->addViolation();
}
}
}

View File

@@ -0,0 +1,111 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\InvalidArgumentException;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Mathieu Santostefano <msantostefano@protonmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class CssColor extends Constraint
{
public const HEX_LONG = 'hex_long';
public const HEX_LONG_WITH_ALPHA = 'hex_long_with_alpha';
public const HEX_SHORT = 'hex_short';
public const HEX_SHORT_WITH_ALPHA = 'hex_short_with_alpha';
public const BASIC_NAMED_COLORS = 'basic_named_colors';
public const EXTENDED_NAMED_COLORS = 'extended_named_colors';
public const SYSTEM_COLORS = 'system_colors';
public const KEYWORDS = 'keywords';
public const RGB = 'rgb';
public const RGBA = 'rgba';
public const HSL = 'hsl';
public const HSLA = 'hsla';
public const INVALID_FORMAT_ERROR = '454ab47b-aacf-4059-8f26-184b2dc9d48d';
protected const ERROR_NAMES = [
self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
/**
* @var string[]
*/
private static array $validationModes = [
self::HEX_LONG,
self::HEX_LONG_WITH_ALPHA,
self::HEX_SHORT,
self::HEX_SHORT_WITH_ALPHA,
self::BASIC_NAMED_COLORS,
self::EXTENDED_NAMED_COLORS,
self::SYSTEM_COLORS,
self::KEYWORDS,
self::RGB,
self::RGBA,
self::HSL,
self::HSLA,
];
public $message = 'This value is not a valid CSS color.';
public $formats;
/**
* @param array|string $formats The types of CSS colors allowed (e.g. hexadecimal only, RGB and HSL only, etc.).
*/
public function __construct($formats = [], ?string $message = null, ?array $groups = null, $payload = null, ?array $options = null)
{
$validationModesAsString = implode(', ', self::$validationModes);
if (!$formats) {
$options['value'] = self::$validationModes;
} elseif (\is_array($formats) && \is_string(key($formats))) {
$options = array_merge($formats, $options ?? []);
} elseif (\is_array($formats)) {
if ([] === array_intersect(self::$validationModes, $formats)) {
throw new InvalidArgumentException(\sprintf('The "formats" parameter value is not valid. It must contain one or more of the following values: "%s".', $validationModesAsString));
}
$options['value'] = $formats;
} elseif (\is_string($formats)) {
if (!\in_array($formats, self::$validationModes)) {
throw new InvalidArgumentException(\sprintf('The "formats" parameter value is not valid. It must contain one or more of the following values: "%s".', $validationModesAsString));
}
$options['value'] = [$formats];
} else {
throw new InvalidArgumentException('The "formats" parameter type is not valid. It should be a string or an array.');
}
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
}
public function getDefaultOption(): string
{
return 'formats';
}
public function getRequiredOptions(): array
{
return ['formats'];
}
}

View File

@@ -0,0 +1,83 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Mathieu Santostefano <msantostefano@protonmail.com>
*/
class CssColorValidator extends ConstraintValidator
{
private const PATTERN_HEX_LONG = '/^#[0-9a-f]{6}$/iD';
private const PATTERN_HEX_LONG_WITH_ALPHA = '/^#[0-9a-f]{8}$/iD';
private const PATTERN_HEX_SHORT = '/^#[0-9a-f]{3}$/iD';
private const PATTERN_HEX_SHORT_WITH_ALPHA = '/^#[0-9a-f]{4}$/iD';
// List comes from https://www.w3.org/wiki/CSS/Properties/color/keywords#Basic_Colors
private const PATTERN_BASIC_NAMED_COLORS = '/^(black|silver|gray|white|maroon|red|purple|fuchsia|green|lime|olive|yellow|navy|blue|teal|aqua)$/iD';
// List comes from https://www.w3.org/wiki/CSS/Properties/color/keywords#Extended_colors
private const PATTERN_EXTENDED_NAMED_COLORS = '/^(aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen)$/iD';
// List comes from https://drafts.csswg.org/css-color/#css-system-colors
private const PATTERN_SYSTEM_COLORS = '/^(Canvas|CanvasText|LinkText|VisitedText|ActiveText|ButtonFace|ButtonText|ButtonBorder|Field|FieldText|Highlight|HighlightText|SelectedItem|SelectedItemText|Mark|MarkText|GrayText)$/iD';
private const PATTERN_KEYWORDS = '/^(transparent|currentColor)$/iD';
private const PATTERN_RGB = '/^rgb\(\s*(0|255|25[0-4]|2[0-4]\d|1\d\d|0?\d?\d),\s*(0|255|25[0-4]|2[0-4]\d|1\d\d|0?\d?\d),\s*(0|255|25[0-4]|2[0-4]\d|1\d\d|0?\d?\d)\s*\)$/iD';
private const PATTERN_RGBA = '/^rgba\(\s*(0|255|25[0-4]|2[0-4]\d|1\d\d|0?\d?\d),\s*(0|255|25[0-4]|2[0-4]\d|1\d\d|0?\d?\d),\s*(0|255|25[0-4]|2[0-4]\d|1\d\d|0?\d?\d),\s*(0|0?\.\d+|1(\.0)?)\s*\)$/iD';
private const PATTERN_HSL = '/^hsl\(\s*(0|360|35\d|3[0-4]\d|[12]\d\d|0?\d?\d),\s*(0|100|\d{1,2})%,\s*(0|100|\d{1,2})%\s*\)$/iD';
private const PATTERN_HSLA = '/^hsla\(\s*(0|360|35\d|3[0-4]\d|[12]\d\d|0?\d?\d),\s*(0|100|\d{1,2})%,\s*(0|100|\d{1,2})%,\s*(0|0?\.\d+|1(\.0)?)\s*\)$/iD';
private const COLOR_PATTERNS = [
CssColor::HEX_LONG => self::PATTERN_HEX_LONG,
CssColor::HEX_LONG_WITH_ALPHA => self::PATTERN_HEX_LONG_WITH_ALPHA,
CssColor::HEX_SHORT => self::PATTERN_HEX_SHORT,
CssColor::HEX_SHORT_WITH_ALPHA => self::PATTERN_HEX_SHORT_WITH_ALPHA,
CssColor::BASIC_NAMED_COLORS => self::PATTERN_BASIC_NAMED_COLORS,
CssColor::EXTENDED_NAMED_COLORS => self::PATTERN_EXTENDED_NAMED_COLORS,
CssColor::SYSTEM_COLORS => self::PATTERN_SYSTEM_COLORS,
CssColor::KEYWORDS => self::PATTERN_KEYWORDS,
CssColor::RGB => self::PATTERN_RGB,
CssColor::RGBA => self::PATTERN_RGBA,
CssColor::HSL => self::PATTERN_HSL,
CssColor::HSLA => self::PATTERN_HSLA,
];
public function validate($value, Constraint $constraint): void
{
if (!$constraint instanceof CssColor) {
throw new UnexpectedTypeException($constraint, CssColor::class);
}
if (null === $value || '' === $value) {
return;
}
if (!\is_string($value)) {
throw new UnexpectedValueException($value, 'string');
}
$formats = array_flip((array) $constraint->formats);
$formatRegexes = array_intersect_key(self::COLOR_PATTERNS, $formats);
foreach ($formatRegexes as $regex) {
if (preg_match($regex, (string) $value)) {
return;
}
}
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(CssColor::INVALID_FORMAT_ERROR)
->addViolation();
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Intl\Currencies;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\LogicException;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Miha Vrhovnik <miha.vrhovnik@pagein.si>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Currency extends Constraint
{
public const NO_SUCH_CURRENCY_ERROR = '69945ac1-2db4-405f-bec7-d2772f73df52';
protected const ERROR_NAMES = [
self::NO_SUCH_CURRENCY_ERROR => 'NO_SUCH_CURRENCY_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This value is not a valid currency.';
public function __construct(?array $options = null, ?string $message = null, ?array $groups = null, mixed $payload = null)
{
if (!class_exists(Currencies::class)) {
throw new LogicException('The Intl component is required to use the Currency constraint. Try running "composer require symfony/intl".');
}
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Intl\Currencies;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* Validates whether a value is a valid currency.
*
* @author Miha Vrhovnik <miha.vrhovnik@pagein.si>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class CurrencyValidator extends ConstraintValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Currency) {
throw new UnexpectedTypeException($constraint, Currency::class);
}
if (null === $value || '' === $value) {
return;
}
if (!\is_scalar($value) && !$value instanceof \Stringable) {
throw new UnexpectedValueException($value, 'string');
}
$value = (string) $value;
if (!Currencies::exists($value)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Currency::NO_SUCH_CURRENCY_ERROR)
->addViolation();
}
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Date extends Constraint
{
public const INVALID_FORMAT_ERROR = '69819696-02ac-4a99-9ff0-14e127c4d1bc';
public const INVALID_DATE_ERROR = '3c184ce5-b31d-4de7-8b76-326da7b2be93';
protected const ERROR_NAMES = [
self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR',
self::INVALID_DATE_ERROR => 'INVALID_DATE_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This value is not a valid date.';
public function __construct(?array $options = null, ?string $message = null, ?array $groups = null, mixed $payload = null)
{
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
}
}

View File

@@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class DateTime extends Constraint
{
public const INVALID_FORMAT_ERROR = '1a9da513-2640-4f84-9b6a-4d99dcddc628';
public const INVALID_DATE_ERROR = 'd52afa47-620d-4d99-9f08-f4d85b36e33c';
public const INVALID_TIME_ERROR = '5e797c9d-74f7-4098-baa3-94390c447b27';
protected const ERROR_NAMES = [
self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR',
self::INVALID_DATE_ERROR => 'INVALID_DATE_ERROR',
self::INVALID_TIME_ERROR => 'INVALID_TIME_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $format = 'Y-m-d H:i:s';
public $message = 'This value is not a valid datetime.';
public function __construct(string|array|null $format = null, ?string $message = null, ?array $groups = null, mixed $payload = null, array $options = [])
{
if (\is_array($format)) {
$options = array_merge($format, $options);
} elseif (null !== $format) {
$options['value'] = $format;
}
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
}
public function getDefaultOption(): ?string
{
return 'format';
}
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Diego Saint Esteben <diego@saintesteben.me>
*/
class DateTimeValidator extends DateValidator
{
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof DateTime) {
throw new UnexpectedTypeException($constraint, DateTime::class);
}
if (null === $value || '' === $value) {
return;
}
if (!\is_scalar($value) && !$value instanceof \Stringable) {
throw new UnexpectedValueException($value, 'string');
}
$value = (string) $value;
\DateTimeImmutable::createFromFormat($constraint->format, $value);
$errors = \DateTimeImmutable::getLastErrors() ?: ['error_count' => 0, 'warnings' => []];
if (0 < $errors['error_count']) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_FORMAT_ERROR)
->addViolation();
return;
}
if (str_ends_with($constraint->format, '+')) {
$errors['warnings'] = array_filter($errors['warnings'], fn ($warning) => 'Trailing data' !== $warning);
}
foreach ($errors['warnings'] as $warning) {
if ('The parsed date was invalid' === $warning) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_DATE_ERROR)
->addViolation();
} elseif ('The parsed time was invalid' === $warning) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_TIME_ERROR)
->addViolation();
} else {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(DateTime::INVALID_FORMAT_ERROR)
->addViolation();
}
}
}
}

View File

@@ -0,0 +1,75 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class DateValidator extends ConstraintValidator
{
public const PATTERN = '/^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/D';
/**
* Checks whether a date is valid.
*
* @internal
*/
public static function checkDate(int $year, int $month, int $day): bool
{
return checkdate($month, $day, $year);
}
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Date) {
throw new UnexpectedTypeException($constraint, Date::class);
}
if (null === $value || '' === $value) {
return;
}
if (!\is_scalar($value) && !$value instanceof \Stringable) {
throw new UnexpectedValueException($value, 'string');
}
$value = (string) $value;
if (!preg_match(static::PATTERN, $value, $matches)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Date::INVALID_FORMAT_ERROR)
->addViolation();
return;
}
if (!self::checkDate(
$matches['year'] ?? $matches[1],
$matches['month'] ?? $matches[2],
$matches['day'] ?? $matches[3]
)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Date::INVALID_DATE_ERROR)
->addViolation();
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
/**
* Disables auto mapping.
*
* Using the annotations on a property has higher precedence than using it on a class,
* which has higher precedence than any configuration that might be defined outside the class.
*
* @Annotation
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::TARGET_CLASS)]
class DisableAutoMapping extends Constraint
{
public function __construct(?array $options = null)
{
if (\is_array($options) && \array_key_exists('groups', $options)) {
throw new ConstraintDefinitionException(\sprintf('The option "groups" is not supported by the constraint "%s".', __CLASS__));
}
parent::__construct($options);
}
public function getTargets(): string|array
{
return [self::PROPERTY_CONSTRAINT, self::CLASS_CONSTRAINT];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Colin O'Dell <colinodell@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class DivisibleBy extends AbstractComparison
{
public const NOT_DIVISIBLE_BY = '6d99d6c3-1464-4ccf-bdc7-14d083cf455c';
protected const ERROR_NAMES = [
self::NOT_DIVISIBLE_BY => 'NOT_DIVISIBLE_BY',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This value should be a multiple of {{ compared_value }}.';
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* Validates that values are a multiple of the given number.
*
* @author Colin O'Dell <colinodell@gmail.com>
*/
class DivisibleByValidator extends AbstractComparisonValidator
{
protected function compareValues(mixed $value1, mixed $value2): bool
{
if (!is_numeric($value1)) {
throw new UnexpectedValueException($value1, 'numeric');
}
if (!is_numeric($value2)) {
throw new UnexpectedValueException($value2, 'numeric');
}
if (!$value2 = abs($value2)) {
return false;
}
if (\is_int($value1 = abs($value1)) && \is_int($value2)) {
return 0 === ($value1 % $value2);
}
if (!$remainder = fmod($value1, $value2)) {
return true;
}
if (\is_float($value2) && \INF !== $value2) {
$quotient = $value1 / $value2;
$rounded = round($quotient);
return \sprintf('%.12e', $quotient) === \sprintf('%.12e', $rounded);
}
return \sprintf('%.12e', $value2) === \sprintf('%.12e', $remainder);
}
protected function getErrorCode(): ?string
{
return DivisibleBy::NOT_DIVISIBLE_BY;
}
}

View File

@@ -0,0 +1,93 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Egulias\EmailValidator\EmailValidator as StrictEmailValidator;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\InvalidArgumentException;
use Symfony\Component\Validator\Exception\LogicException;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class Email extends Constraint
{
public const VALIDATION_MODE_HTML5_ALLOW_NO_TLD = 'html5-allow-no-tld';
public const VALIDATION_MODE_HTML5 = 'html5';
public const VALIDATION_MODE_STRICT = 'strict';
/**
* @deprecated since Symfony 6.2, use VALIDATION_MODE_HTML5 instead
*/
public const VALIDATION_MODE_LOOSE = 'loose';
public const INVALID_FORMAT_ERROR = 'bd79c0ab-ddba-46cc-a703-a7a4b08de310';
public const VALIDATION_MODES = [
self::VALIDATION_MODE_HTML5_ALLOW_NO_TLD,
self::VALIDATION_MODE_HTML5,
self::VALIDATION_MODE_STRICT,
self::VALIDATION_MODE_LOOSE,
];
protected const ERROR_NAMES = [
self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This value is not a valid email address.';
public $mode;
/** @var callable|null */
public $normalizer;
public function __construct(
?array $options = null,
?string $message = null,
?string $mode = null,
?callable $normalizer = null,
?array $groups = null,
mixed $payload = null,
) {
if (\is_array($options) && \array_key_exists('mode', $options) && !\in_array($options['mode'], self::VALIDATION_MODES, true)) {
throw new InvalidArgumentException('The "mode" parameter value is not valid.');
}
if (null !== $mode && !\in_array($mode, self::VALIDATION_MODES, true)) {
throw new InvalidArgumentException('The "mode" parameter value is not valid.');
}
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
$this->mode = $mode ?? $this->mode;
$this->normalizer = $normalizer ?? $this->normalizer;
if (self::VALIDATION_MODE_LOOSE === $this->mode) {
trigger_deprecation('symfony/validator', '6.2', 'The "%s" mode is deprecated. It will be removed in 7.0 and the default mode will be changed to "%s".', self::VALIDATION_MODE_LOOSE, self::VALIDATION_MODE_HTML5);
}
if (self::VALIDATION_MODE_STRICT === $this->mode && !class_exists(StrictEmailValidator::class)) {
throw new LogicException(\sprintf('The "egulias/email-validator" component is required to use the "%s" constraint in strict mode. Try running "composer require egulias/email-validator".', __CLASS__));
}
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
throw new InvalidArgumentException(\sprintf('The "normalizer" option must be a valid callable ("%s" given).', get_debug_type($this->normalizer)));
}
}
}

View File

@@ -0,0 +1,119 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Egulias\EmailValidator\EmailValidator as EguliasEmailValidator;
use Egulias\EmailValidator\Validation\EmailValidation;
use Egulias\EmailValidator\Validation\NoRFCWarningsValidation;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\InvalidArgumentException;
use Symfony\Component\Validator\Exception\LogicException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class EmailValidator extends ConstraintValidator
{
private const PATTERN_HTML5_ALLOW_NO_TLD = '/^[a-zA-Z0-9.!#$%&\'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/D';
private const PATTERN_HTML5 = '/^[a-zA-Z0-9.!#$%&\'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/D';
private const PATTERN_LOOSE = '/^.+\@\S+\.\S+$/D';
private const EMAIL_PATTERNS = [
Email::VALIDATION_MODE_LOOSE => self::PATTERN_LOOSE,
Email::VALIDATION_MODE_HTML5 => self::PATTERN_HTML5,
Email::VALIDATION_MODE_HTML5_ALLOW_NO_TLD => self::PATTERN_HTML5_ALLOW_NO_TLD,
];
private string $defaultMode;
public function __construct(string $defaultMode = Email::VALIDATION_MODE_LOOSE)
{
if (!\in_array($defaultMode, Email::VALIDATION_MODES, true)) {
throw new InvalidArgumentException('The "defaultMode" parameter value is not valid.');
}
if (Email::VALIDATION_MODE_LOOSE === $defaultMode) {
trigger_deprecation('symfony/validator', '6.2', 'The "%s" mode is deprecated. It will be removed in 7.0 and the default mode will be changed to "%s".', Email::VALIDATION_MODE_LOOSE, Email::VALIDATION_MODE_HTML5);
}
$this->defaultMode = $defaultMode;
}
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Email) {
throw new UnexpectedTypeException($constraint, Email::class);
}
if (null === $value || '' === $value) {
return;
}
if (!\is_scalar($value) && !$value instanceof \Stringable) {
throw new UnexpectedValueException($value, 'string');
}
$value = (string) $value;
if ('' === $value) {
return;
}
if (null !== $constraint->normalizer) {
$value = ($constraint->normalizer)($value);
}
if (null === $constraint->mode) {
if (Email::VALIDATION_MODE_STRICT === $this->defaultMode && !class_exists(EguliasEmailValidator::class)) {
throw new LogicException(\sprintf('The "egulias/email-validator" component is required to make the "%s" constraint default to strict mode. Try running "composer require egulias/email-validator".', Email::class));
}
$constraint->mode = $this->defaultMode;
}
if (!\in_array($constraint->mode, Email::VALIDATION_MODES, true)) {
throw new InvalidArgumentException(\sprintf('The "%s::$mode" parameter value is not valid.', get_debug_type($constraint)));
}
if (Email::VALIDATION_MODE_STRICT === $constraint->mode) {
$strictValidator = new EguliasEmailValidator();
if (interface_exists(EmailValidation::class) && !$strictValidator->isValid($value, new NoRFCWarningsValidation())) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Email::INVALID_FORMAT_ERROR)
->addViolation();
return;
} elseif (!interface_exists(EmailValidation::class) && !$strictValidator->isValid($value, false, true)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Email::INVALID_FORMAT_ERROR)
->addViolation();
return;
}
} elseif (!preg_match(self::EMAIL_PATTERNS[$constraint->mode], $value)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Email::INVALID_FORMAT_ERROR)
->addViolation();
return;
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
/**
* Enables auto mapping.
*
* Using the annotations on a property has higher precedence than using it on a class,
* which has higher precedence than any configuration that might be defined outside the class.
*
* @Annotation
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::TARGET_CLASS)]
class EnableAutoMapping extends Constraint
{
public function __construct(?array $options = null)
{
if (\is_array($options) && \array_key_exists('groups', $options)) {
throw new ConstraintDefinitionException(\sprintf('The option "groups" is not supported by the constraint "%s".', __CLASS__));
}
parent::__construct($options);
}
public function getTargets(): string|array
{
return [self::PROPERTY_CONSTRAINT, self::CLASS_CONSTRAINT];
}
}

View File

@@ -0,0 +1,36 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Daniel Holmes <daniel@danielholmes.org>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class EqualTo extends AbstractComparison
{
public const NOT_EQUAL_ERROR = '478618a7-95ba-473d-9101-cabd45e49115';
protected const ERROR_NAMES = [
self::NOT_EQUAL_ERROR => 'NOT_EQUAL_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This value should be equal to {{ compared_value }}.';
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
/**
* Validates values are equal (==).
*
* @author Daniel Holmes <daniel@danielholmes.org>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class EqualToValidator extends AbstractComparisonValidator
{
protected function compareValues(mixed $value1, mixed $value2): bool
{
return $value1 == $value2;
}
protected function getErrorCode(): ?string
{
return EqualTo::NOT_EQUAL_ERROR;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
abstract class Existence extends Composite
{
public $constraints = [];
public function getDefaultOption(): ?string
{
return 'constraints';
}
protected function getCompositeOption(): string
{
return 'constraints';
}
}

View File

@@ -0,0 +1,90 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\ExpressionLanguage\Expression as ExpressionObject;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\LogicException;
/**
* @Annotation
* @Target({"CLASS", "PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
class Expression extends Constraint
{
public const EXPRESSION_FAILED_ERROR = '6b3befbc-2f01-4ddf-be21-b57898905284';
protected const ERROR_NAMES = [
self::EXPRESSION_FAILED_ERROR => 'EXPRESSION_FAILED_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This value is not valid.';
public $expression;
public $values = [];
public bool $negate = true;
public function __construct(
string|ExpressionObject|array|null $expression,
?string $message = null,
?array $values = null,
?array $groups = null,
mixed $payload = null,
array $options = [],
?bool $negate = null,
) {
if (!class_exists(ExpressionLanguage::class)) {
throw new LogicException(\sprintf('The "symfony/expression-language" component is required to use the "%s" constraint. Try running "composer require symfony/expression-language".', __CLASS__));
}
if (\is_array($expression)) {
$options = array_merge($expression, $options);
} elseif (null !== $expression) {
$options['value'] = $expression;
}
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
$this->values = $values ?? $this->values;
$this->negate = $negate ?? $this->negate;
}
public function getDefaultOption(): ?string
{
return 'expression';
}
public function getRequiredOptions(): array
{
return ['expression'];
}
public function getTargets(): string|array
{
return [self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT];
}
public function validatedBy(): string
{
return 'validator.expression';
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface
{
public function getFunctions(): array
{
return [
new ExpressionFunction('is_valid', function (...$arguments) {
return \sprintf(
'0 === $context->getValidator()->inContext($context)->validate(%s)->getViolations()->count()',
implode(', ', $arguments)
);
}, function (array $variables, ...$arguments): bool {
return 0 === $variables['context']->getValidator()->inContext($variables['context'])->validate(...$arguments)->getViolations()->count();
}),
];
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
trigger_deprecation('symfony/validator', '6.1', 'The "%s" constraint is deprecated since symfony 6.1, use "ExpressionSyntax" instead.', ExpressionLanguageSyntax::class);
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Andrey Sevastianov <mrpkmail@gmail.com>
*
* @deprecated since symfony 6.1, use ExpressionSyntax instead
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class ExpressionLanguageSyntax extends Constraint
{
public const EXPRESSION_LANGUAGE_SYNTAX_ERROR = '1766a3f3-ff03-40eb-b053-ab7aa23d988a';
protected const ERROR_NAMES = [
self::EXPRESSION_LANGUAGE_SYNTAX_ERROR => 'EXPRESSION_LANGUAGE_SYNTAX_ERROR',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $message = 'This value should be a valid expression.';
public $service;
public $allowedVariables;
public function __construct(?array $options = null, ?string $message = null, ?string $service = null, ?array $allowedVariables = null, ?array $groups = null, mixed $payload = null)
{
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
$this->service = $service ?? $this->service;
$this->allowedVariables = $allowedVariables ?? $this->allowedVariables;
}
public function validatedBy(): string
{
return $this->service ?? static::class.'Validator';
}
}

View File

@@ -0,0 +1,63 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\SyntaxError;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
trigger_deprecation('symfony/validator', '6.1', 'The "%s" constraint is deprecated since symfony 6.1, use "ExpressionSyntaxValidator" instead.', ExpressionLanguageSyntaxValidator::class);
/**
* @author Andrey Sevastianov <mrpkmail@gmail.com>
*
* @deprecated since symfony 6.1, use ExpressionSyntaxValidator instead
*/
class ExpressionLanguageSyntaxValidator extends ConstraintValidator
{
private ?ExpressionLanguage $expressionLanguage;
public function __construct(?ExpressionLanguage $expressionLanguage = null)
{
if (!class_exists(ExpressionLanguage::class)) {
throw new \LogicException(\sprintf('The "%s" class requires the "ExpressionLanguage" component. Try running "composer require symfony/expression-language".', self::class));
}
$this->expressionLanguage = $expressionLanguage;
}
public function validate(mixed $expression, Constraint $constraint): void
{
if (!$constraint instanceof ExpressionLanguageSyntax) {
throw new UnexpectedTypeException($constraint, ExpressionLanguageSyntax::class);
}
if (!\is_string($expression)) {
throw new UnexpectedValueException($expression, 'string');
}
$this->expressionLanguage ??= new ExpressionLanguage();
try {
$this->expressionLanguage->lint($expression, $constraint->allowedVariables);
} catch (SyntaxError $exception) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ syntax_error }}', $this->formatValue($exception->getMessage()))
->setInvalidValue((string) $expression)
->setCode(ExpressionLanguageSyntax::EXPRESSION_LANGUAGE_SYNTAX_ERROR)
->addViolation();
}
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Andrey Sevastianov <mrpkmail@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class ExpressionSyntax extends Constraint
{
public const EXPRESSION_SYNTAX_ERROR = 'e219aa22-8b11-48ec-81a0-fc07cdb0e13f';
protected const ERROR_NAMES = [
self::EXPRESSION_SYNTAX_ERROR => 'EXPRESSION_SYNTAX_ERROR',
];
public $message = 'This value should be a valid expression.';
public $service;
public $allowedVariables;
public function __construct(?array $options = null, ?string $message = null, ?string $service = null, ?array $allowedVariables = null, ?array $groups = null, mixed $payload = null)
{
parent::__construct($options, $groups, $payload);
$this->message = $message ?? $this->message;
$this->service = $service ?? $this->service;
$this->allowedVariables = $allowedVariables ?? $this->allowedVariables;
}
public function validatedBy(): string
{
return $this->service ?? static::class.'Validator';
}
}

View File

@@ -0,0 +1,59 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\SyntaxError;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Andrey Sevastianov <mrpkmail@gmail.com>
*/
class ExpressionSyntaxValidator extends ConstraintValidator
{
private ?ExpressionLanguage $expressionLanguage;
public function __construct(?ExpressionLanguage $expressionLanguage = null)
{
$this->expressionLanguage = $expressionLanguage;
}
public function validate(mixed $expression, Constraint $constraint): void
{
if (!$constraint instanceof ExpressionSyntax) {
throw new UnexpectedTypeException($constraint, ExpressionSyntax::class);
}
if (null === $expression || '' === $expression) {
return;
}
if (!\is_string($expression)) {
throw new UnexpectedValueException($expression, 'string');
}
$this->expressionLanguage ??= new ExpressionLanguage();
try {
$this->expressionLanguage->lint($expression, $constraint->allowedVariables);
} catch (SyntaxError $exception) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ syntax_error }}', $this->formatValue($exception->getMessage()))
->setInvalidValue((string) $expression)
->setCode(ExpressionSyntax::EXPRESSION_SYNTAX_ERROR)
->addViolation();
}
}
}

View File

@@ -0,0 +1,65 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bschussek@symfony.com>
*/
class ExpressionValidator extends ConstraintValidator
{
private ExpressionLanguage $expressionLanguage;
public function __construct(?ExpressionLanguage $expressionLanguage = null)
{
if ($expressionLanguage) {
$this->expressionLanguage = $expressionLanguage;
}
}
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof Expression) {
throw new UnexpectedTypeException($constraint, Expression::class);
}
$variables = $constraint->values;
$variables['value'] = $value;
$variables['this'] = $this->context->getObject();
$variables['context'] = $this->context;
if ($constraint->negate xor $this->getExpressionLanguage()->evaluate($constraint->expression, $variables)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value, self::OBJECT_TO_STRING))
->setCode(Expression::EXPRESSION_FAILED_ERROR)
->addViolation();
}
}
private function getExpressionLanguage(): ExpressionLanguage
{
if (!isset($this->expressionLanguage)) {
$this->expressionLanguage = new ExpressionLanguage();
$this->expressionLanguage->registerProvider(new ExpressionLanguageProvider());
}
return $this->expressionLanguage;
}
}

View File

@@ -0,0 +1,186 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @property int $maxSize
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class File extends Constraint
{
// Check the Image constraint for clashes if adding new constants here
public const NOT_FOUND_ERROR = 'd2a3fb6e-7ddc-4210-8fbf-2ab345ce1998';
public const NOT_READABLE_ERROR = 'c20c92a4-5bfa-4202-9477-28e800e0f6ff';
public const EMPTY_ERROR = '5d743385-9775-4aa5-8ff5-495fb1e60137';
public const TOO_LARGE_ERROR = 'df8637af-d466-48c6-a59d-e7126250a654';
public const INVALID_MIME_TYPE_ERROR = '744f00bc-4389-4c74-92de-9a43cde55534';
public const INVALID_EXTENSION_ERROR = 'c8c7315c-6186-4719-8b71-5659e16bdcb7';
public const FILENAME_TOO_LONG = 'e5706483-91a8-49d8-9a59-5e81a3c634a8';
protected const ERROR_NAMES = [
self::NOT_FOUND_ERROR => 'NOT_FOUND_ERROR',
self::NOT_READABLE_ERROR => 'NOT_READABLE_ERROR',
self::EMPTY_ERROR => 'EMPTY_ERROR',
self::TOO_LARGE_ERROR => 'TOO_LARGE_ERROR',
self::INVALID_MIME_TYPE_ERROR => 'INVALID_MIME_TYPE_ERROR',
self::INVALID_EXTENSION_ERROR => 'INVALID_EXTENSION_ERROR',
self::FILENAME_TOO_LONG => 'FILENAME_TOO_LONG',
];
/**
* @deprecated since Symfony 6.1, use const ERROR_NAMES instead
*/
protected static $errorNames = self::ERROR_NAMES;
public $binaryFormat;
public $mimeTypes = [];
public ?int $filenameMaxLength = null;
public array|string|null $extensions = [];
public $notFoundMessage = 'The file could not be found.';
public $notReadableMessage = 'The file is not readable.';
public $maxSizeMessage = 'The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.';
public $mimeTypesMessage = 'The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}.';
public string $extensionsMessage = 'The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}.';
public $disallowEmptyMessage = 'An empty file is not allowed.';
public $filenameTooLongMessage = 'The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less.';
public $uploadIniSizeErrorMessage = 'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.';
public $uploadFormSizeErrorMessage = 'The file is too large.';
public $uploadPartialErrorMessage = 'The file was only partially uploaded.';
public $uploadNoFileErrorMessage = 'No file was uploaded.';
public $uploadNoTmpDirErrorMessage = 'No temporary folder was configured in php.ini.';
public $uploadCantWriteErrorMessage = 'Cannot write temporary file to disk.';
public $uploadExtensionErrorMessage = 'A PHP extension caused the upload to fail.';
public $uploadErrorMessage = 'The file could not be uploaded.';
protected $maxSize;
/**
* @param array<string|string[]>|string $extensions
*/
public function __construct(
?array $options = null,
int|string|null $maxSize = null,
?bool $binaryFormat = null,
array|string|null $mimeTypes = null,
?int $filenameMaxLength = null,
?string $notFoundMessage = null,
?string $notReadableMessage = null,
?string $maxSizeMessage = null,
?string $mimeTypesMessage = null,
?string $disallowEmptyMessage = null,
?string $filenameTooLongMessage = null,
?string $uploadIniSizeErrorMessage = null,
?string $uploadFormSizeErrorMessage = null,
?string $uploadPartialErrorMessage = null,
?string $uploadNoFileErrorMessage = null,
?string $uploadNoTmpDirErrorMessage = null,
?string $uploadCantWriteErrorMessage = null,
?string $uploadExtensionErrorMessage = null,
?string $uploadErrorMessage = null,
?array $groups = null,
mixed $payload = null,
array|string|null $extensions = null,
?string $extensionsMessage = null,
) {
parent::__construct($options, $groups, $payload);
$this->maxSize = $maxSize ?? $this->maxSize;
$this->binaryFormat = $binaryFormat ?? $this->binaryFormat;
$this->mimeTypes = $mimeTypes ?? $this->mimeTypes;
$this->filenameMaxLength = $filenameMaxLength ?? $this->filenameMaxLength;
$this->extensions = $extensions ?? $this->extensions;
$this->notFoundMessage = $notFoundMessage ?? $this->notFoundMessage;
$this->notReadableMessage = $notReadableMessage ?? $this->notReadableMessage;
$this->maxSizeMessage = $maxSizeMessage ?? $this->maxSizeMessage;
$this->mimeTypesMessage = $mimeTypesMessage ?? $this->mimeTypesMessage;
$this->extensionsMessage = $extensionsMessage ?? $this->extensionsMessage;
$this->disallowEmptyMessage = $disallowEmptyMessage ?? $this->disallowEmptyMessage;
$this->filenameTooLongMessage = $filenameTooLongMessage ?? $this->filenameTooLongMessage;
$this->uploadIniSizeErrorMessage = $uploadIniSizeErrorMessage ?? $this->uploadIniSizeErrorMessage;
$this->uploadFormSizeErrorMessage = $uploadFormSizeErrorMessage ?? $this->uploadFormSizeErrorMessage;
$this->uploadPartialErrorMessage = $uploadPartialErrorMessage ?? $this->uploadPartialErrorMessage;
$this->uploadNoFileErrorMessage = $uploadNoFileErrorMessage ?? $this->uploadNoFileErrorMessage;
$this->uploadNoTmpDirErrorMessage = $uploadNoTmpDirErrorMessage ?? $this->uploadNoTmpDirErrorMessage;
$this->uploadCantWriteErrorMessage = $uploadCantWriteErrorMessage ?? $this->uploadCantWriteErrorMessage;
$this->uploadExtensionErrorMessage = $uploadExtensionErrorMessage ?? $this->uploadExtensionErrorMessage;
$this->uploadErrorMessage = $uploadErrorMessage ?? $this->uploadErrorMessage;
if (null !== $this->maxSize) {
$this->normalizeBinaryFormat($this->maxSize);
}
}
/**
* @return void
*/
public function __set(string $option, mixed $value)
{
if ('maxSize' === $option) {
$this->normalizeBinaryFormat($value);
return;
}
parent::__set($option, $value);
}
public function __get(string $option): mixed
{
if ('maxSize' === $option) {
return $this->maxSize;
}
return parent::__get($option);
}
public function __isset(string $option): bool
{
if ('maxSize' === $option) {
return true;
}
return parent::__isset($option);
}
private function normalizeBinaryFormat(int|string $maxSize): void
{
$factors = [
'k' => 1000,
'ki' => 1 << 10,
'm' => 1000 * 1000,
'mi' => 1 << 20,
'g' => 1000 * 1000 * 1000,
'gi' => 1 << 30,
];
if (ctype_digit((string) $maxSize)) {
$this->maxSize = (int) $maxSize;
$this->binaryFormat ??= false;
} elseif (preg_match('/^(\d++)('.implode('|', array_keys($factors)).')$/i', $maxSize, $matches)) {
$this->maxSize = $matches[1] * $factors[$unit = strtolower($matches[2])];
$this->binaryFormat ??= 2 === \strlen($unit);
} else {
throw new ConstraintDefinitionException(\sprintf('"%s" is not a valid maximum size.', $maxSize));
}
}
}

View File

@@ -0,0 +1,309 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\HttpFoundation\File\File as FileObject;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\LogicException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FileValidator extends ConstraintValidator
{
public const KB_BYTES = 1000;
public const MB_BYTES = 1000000;
public const KIB_BYTES = 1024;
public const MIB_BYTES = 1048576;
private const SUFFICES = [
1 => 'bytes',
self::KB_BYTES => 'kB',
self::MB_BYTES => 'MB',
self::KIB_BYTES => 'KiB',
self::MIB_BYTES => 'MiB',
];
/**
* @return void
*/
public function validate(mixed $value, Constraint $constraint)
{
if (!$constraint instanceof File) {
throw new UnexpectedTypeException($constraint, File::class);
}
if (null === $value || '' === $value) {
return;
}
if ($value instanceof UploadedFile && !$value->isValid()) {
switch ($value->getError()) {
case \UPLOAD_ERR_INI_SIZE:
$iniLimitSize = UploadedFile::getMaxFilesize();
if ($constraint->maxSize && $constraint->maxSize < $iniLimitSize) {
$limitInBytes = $constraint->maxSize;
$binaryFormat = $constraint->binaryFormat;
} else {
$limitInBytes = $iniLimitSize;
$binaryFormat = $constraint->binaryFormat ?? true;
}
[, $limitAsString, $suffix] = $this->factorizeSizes(0, $limitInBytes, $binaryFormat);
$this->context->buildViolation($constraint->uploadIniSizeErrorMessage)
->setParameter('{{ limit }}', $limitAsString)
->setParameter('{{ suffix }}', $suffix)
->setCode((string) \UPLOAD_ERR_INI_SIZE)
->addViolation();
return;
case \UPLOAD_ERR_FORM_SIZE:
$this->context->buildViolation($constraint->uploadFormSizeErrorMessage)
->setCode((string) \UPLOAD_ERR_FORM_SIZE)
->addViolation();
return;
case \UPLOAD_ERR_PARTIAL:
$this->context->buildViolation($constraint->uploadPartialErrorMessage)
->setCode((string) \UPLOAD_ERR_PARTIAL)
->addViolation();
return;
case \UPLOAD_ERR_NO_FILE:
$this->context->buildViolation($constraint->uploadNoFileErrorMessage)
->setCode((string) \UPLOAD_ERR_NO_FILE)
->addViolation();
return;
case \UPLOAD_ERR_NO_TMP_DIR:
$this->context->buildViolation($constraint->uploadNoTmpDirErrorMessage)
->setCode((string) \UPLOAD_ERR_NO_TMP_DIR)
->addViolation();
return;
case \UPLOAD_ERR_CANT_WRITE:
$this->context->buildViolation($constraint->uploadCantWriteErrorMessage)
->setCode((string) \UPLOAD_ERR_CANT_WRITE)
->addViolation();
return;
case \UPLOAD_ERR_EXTENSION:
$this->context->buildViolation($constraint->uploadExtensionErrorMessage)
->setCode((string) \UPLOAD_ERR_EXTENSION)
->addViolation();
return;
default:
$this->context->buildViolation($constraint->uploadErrorMessage)
->setCode((string) $value->getError())
->addViolation();
return;
}
}
if (!\is_scalar($value) && !$value instanceof FileObject && !$value instanceof \Stringable) {
throw new UnexpectedValueException($value, 'string');
}
$path = $value instanceof FileObject ? $value->getPathname() : (string) $value;
if (!is_file($path)) {
$this->context->buildViolation($constraint->notFoundMessage)
->setParameter('{{ file }}', $this->formatValue($path))
->setCode(File::NOT_FOUND_ERROR)
->addViolation();
return;
}
if (!is_readable($path)) {
$this->context->buildViolation($constraint->notReadableMessage)
->setParameter('{{ file }}', $this->formatValue($path))
->setCode(File::NOT_READABLE_ERROR)
->addViolation();
return;
}
$sizeInBytes = filesize($path);
$basename = $value instanceof UploadedFile ? $value->getClientOriginalName() : basename($path);
if ($constraint->filenameMaxLength && $constraint->filenameMaxLength < $filenameLength = \strlen($basename)) {
$this->context->buildViolation($constraint->filenameTooLongMessage)
->setParameter('{{ filename_max_length }}', $this->formatValue($constraint->filenameMaxLength))
->setCode(File::FILENAME_TOO_LONG)
->setPlural($constraint->filenameMaxLength)
->addViolation();
return;
}
if (0 === $sizeInBytes) {
$this->context->buildViolation($constraint->disallowEmptyMessage)
->setParameter('{{ file }}', $this->formatValue($path))
->setParameter('{{ name }}', $this->formatValue($basename))
->setCode(File::EMPTY_ERROR)
->addViolation();
return;
}
if ($constraint->maxSize) {
$limitInBytes = $constraint->maxSize;
if ($sizeInBytes > $limitInBytes) {
[$sizeAsString, $limitAsString, $suffix] = $this->factorizeSizes($sizeInBytes, $limitInBytes, $constraint->binaryFormat);
$this->context->buildViolation($constraint->maxSizeMessage)
->setParameter('{{ file }}', $this->formatValue($path))
->setParameter('{{ size }}', $sizeAsString)
->setParameter('{{ limit }}', $limitAsString)
->setParameter('{{ suffix }}', $suffix)
->setParameter('{{ name }}', $this->formatValue($basename))
->setCode(File::TOO_LARGE_ERROR)
->addViolation();
return;
}
}
$mimeTypes = (array) $constraint->mimeTypes;
if ($constraint->extensions) {
$fileExtension = strtolower(pathinfo($basename, \PATHINFO_EXTENSION));
$found = false;
$normalizedExtensions = [];
foreach ((array) $constraint->extensions as $k => $v) {
if (!\is_string($k)) {
$k = $v;
$v = null;
}
$normalizedExtensions[] = $k;
if ($fileExtension !== $k) {
continue;
}
$found = true;
if (null === $v) {
if (!class_exists(MimeTypes::class)) {
throw new LogicException('You cannot validate the mime-type of files as the Mime component is not installed. Try running "composer require symfony/mime".');
}
$mimeTypesHelper = MimeTypes::getDefault();
$v = $mimeTypesHelper->getMimeTypes($k);
}
$mimeTypes = $mimeTypes ? array_intersect($v, $mimeTypes) : (array) $v;
break;
}
if (!$found) {
$this->context->buildViolation($constraint->extensionsMessage)
->setParameter('{{ file }}', $this->formatValue($path))
->setParameter('{{ extension }}', $this->formatValue($fileExtension))
->setParameter('{{ extensions }}', $this->formatValues($normalizedExtensions))
->setParameter('{{ name }}', $this->formatValue($basename))
->setCode(File::INVALID_EXTENSION_ERROR)
->addViolation();
}
}
if ($mimeTypes) {
if ($value instanceof FileObject) {
$mime = $value->getMimeType();
} elseif (isset($mimeTypesHelper) || class_exists(MimeTypes::class)) {
$mime = ($mimeTypesHelper ?? MimeTypes::getDefault())->guessMimeType($path);
} elseif (!class_exists(FileObject::class)) {
throw new LogicException('You cannot validate the mime-type of files as the Mime component is not installed. Try running "composer require symfony/mime".');
} else {
$mime = (new FileObject($value))->getMimeType();
}
foreach ($mimeTypes as $mimeType) {
if ($mimeType === $mime) {
return;
}
if ($discrete = strstr($mimeType, '/*', true)) {
if (strstr($mime, '/', true) === $discrete) {
return;
}
}
}
$this->context->buildViolation($constraint->mimeTypesMessage)
->setParameter('{{ file }}', $this->formatValue($path))
->setParameter('{{ type }}', $this->formatValue($mime))
->setParameter('{{ types }}', $this->formatValues($mimeTypes))
->setParameter('{{ name }}', $this->formatValue($basename))
->setCode(File::INVALID_MIME_TYPE_ERROR)
->addViolation();
}
}
private static function moreDecimalsThan(string $double, int $numberOfDecimals): bool
{
return \strlen($double) > \strlen(round($double, $numberOfDecimals));
}
/**
* Convert the limit to the smallest possible number
* (i.e. try "MB", then "kB", then "bytes").
*/
private function factorizeSizes(int $size, int|float $limit, bool $binaryFormat): array
{
if ($binaryFormat) {
$coef = self::MIB_BYTES;
$coefFactor = self::KIB_BYTES;
} else {
$coef = self::MB_BYTES;
$coefFactor = self::KB_BYTES;
}
// If $limit < $coef, $limitAsString could be < 1 with less than 3 decimals.
// In this case, we would end up displaying an allowed size < 1 (eg: 0.1 MB).
// It looks better to keep on factorizing (to display 100 kB for example).
while ($limit < $coef) {
$coef /= $coefFactor;
}
$limitAsString = (string) ($limit / $coef);
// Restrict the limit to 2 decimals (without rounding! we
// need the precise value)
while (self::moreDecimalsThan($limitAsString, 2)) {
$coef /= $coefFactor;
$limitAsString = (string) ($limit / $coef);
}
// Convert size to the same measure, but round to 2 decimals
$sizeAsString = (string) round($size / $coef, 2);
// If the size and limit produce the same string output
// (due to rounding), reduce the coefficient
while ($sizeAsString === $limitAsString) {
$coef /= $coefFactor;
$limitAsString = (string) ($limit / $coef);
$sizeAsString = (string) round($size / $coef, 2);
}
return [$sizeAsString, $limitAsString, self::SUFFICES[$coef]];
}
}

Some files were not shown because too many files have changed in this diff Show More