aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/symfony
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/symfony')
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/.gitignore4
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/CHANGELOG.md16
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php202
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php32
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Event.php121
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php185
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcherInterface.php96
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventSubscriberInterface.php50
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/GenericEvent.php186
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php92
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/LICENSE19
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/README.md25
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php257
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php320
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventTest.php84
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php140
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ImmutableEventDispatcherTest.php106
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/composer.json38
-rw-r--r--vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/phpunit.xml.dist30
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/.gitignore4
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/CHANGELOG.md18
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/ExceptionInterface.php24
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/IOException.php24
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/Filesystem.php471
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/LICENSE19
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/README.md45
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/Tests/FilesystemTest.php982
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/composer.json31
-rw-r--r--vendor/symfony/filesystem/Symfony/Component/Filesystem/phpunit.xml.dist28
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/.gitignore4
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/AbstractExtension.php195
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/AbstractRendererEngine.php206
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/AbstractType.php56
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/AbstractTypeExtension.php48
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Button.php436
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/ButtonBuilder.php864
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/ButtonTypeInterface.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/CHANGELOG.md238
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/CallbackTransformer.php70
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/ClickableInterface.php27
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/DataMapperInterface.php38
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/DataTransformerInterface.php77
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/AlreadyBoundException.php22
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/AlreadySubmittedException.php22
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/BadMethodCallException.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/ErrorMappingException.php16
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/ExceptionInterface.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/InvalidArgumentException.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/InvalidConfigurationException.php16
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/LogicException.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/OutOfBoundsException.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/RuntimeException.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/StringCastException.php16
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/TransformationFailedException.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Exception/UnexpectedTypeException.php20
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php510
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceListInterface.php149
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/LazyChoiceList.php149
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php184
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/SimpleChoiceList.php164
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/CoreExtension.php59
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php92
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php86
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php52
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BooleanToStringTransformer.php85
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToBooleanArrayTransformer.php118
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php62
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToBooleanArrayTransformer.php117
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php83
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php86
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php184
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php169
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php82
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php231
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php89
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php53
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php90
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php184
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php149
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php91
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixCheckboxInputListener.php62
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixRadioInputListener.php66
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php56
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php137
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php173
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/TrimListener.php55
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BaseType.php121
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php44
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ButtonType.php38
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php67
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php274
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CollectionType.php103
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CountryType.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php281
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateType.php309
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/EmailType.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FileType.php61
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FormType.php214
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/HiddenType.php40
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/IntegerType.php68
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LanguageType.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LocaleType.php46
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/MoneyType.php111
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/NumberType.php66
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PasswordType.php57
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PercentType.php55
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RadioType.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php67
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ResetType.php39
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SearchType.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SubmitType.php46
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextType.php36
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextareaType.php43
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimeType.php225
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php86
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/UrlType.php54
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Core/View/ChoiceView.php55
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php64
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderInterface.php49
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php78
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php57
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php115
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php129
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php101
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/EventListener/BindRequestListener.php91
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php29
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php79
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php56
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingRendererEngine.php125
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/Form.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php236
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php68
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php56
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php84
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php28
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php64
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php57
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php286
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php106
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php299
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php33
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php250
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php30
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Form.php1046
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormBuilder.php275
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormBuilderInterface.php87
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormConfigBuilder.php919
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormConfigBuilderInterface.php287
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormConfigInterface.php243
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormError.php105
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormEvent.php65
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormEvents.php49
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormExtensionInterface.php63
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormFactory.php156
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormFactoryBuilder.php162
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormFactoryBuilderInterface.php108
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormFactoryInterface.php109
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormInterface.php288
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormRegistry.php180
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormRegistryInterface.php57
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormRenderer.php304
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormRendererEngineInterface.php150
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormRendererInterface.php103
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormTypeExtensionInterface.php75
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormTypeGuesserChain.php104
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormTypeGuesserInterface.php64
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormTypeInterface.php95
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/FormView.php159
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Forms.php185
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Guess/Guess.php113
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Guess/TypeGuess.php70
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Guess/ValueGuess.php50
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/LICENSE19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/NativeRequestHandler.php194
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/PreloadedExtension.php97
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/README.md26
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/RequestHandlerInterface.php28
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/ResolvedFormType.php284
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeFactory.php26
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeFactoryInterface.php38
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeInterface.php106
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/config/validation.xml13
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ar.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.bg.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ca.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.cs.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.da.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.de.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.el.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.en.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.es.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.et.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.eu.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fa.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fi.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fr.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.gl.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.he.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hr.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hu.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hy.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.id.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.it.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ja.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lb.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lt.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lv.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.mn.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.nb.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.nl.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pl.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pt.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ro.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ru.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sk.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sl.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sv.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ua.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf19
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/ReversedTransformer.php55
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/SubmitButton.php52
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/SubmitButtonBuilder.php30
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/SubmitButtonTypeInterface.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Test/DeprecationErrorHandler.php42
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Test/FormBuilderInterface.php16
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Test/FormIntegrationTestCase.php41
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Test/FormInterface.php16
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Test/FormPerformanceTestCase.php70
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Test/TypeTestCase.php41
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php732
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/AbstractExtensionTest.php43
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/AbstractFormTest.php147
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/AbstractLayoutTest.php1876
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php280
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php509
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/CompoundFormPerformanceTest.php48
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/CompoundFormTest.php759
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ChoiceListTest.php200
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/LazyChoiceListTest.php116
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ObjectChoiceListTest.php212
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/SimpleChoiceListTest.php188
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php319
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ArrayToPartsTransformerTest.php149
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BooleanToStringTransformerTest.php60
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php76
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php76
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DataTransformerChainTest.php53
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeTestCase.php20
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php512
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php275
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php132
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php181
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php104
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php115
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php74
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php393
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php114
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ValueToDuplicatesTransformerTest.php120
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixRadioInputListenerTest.php106
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php61
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/Fixtures/randomhashbin0 -> 35 bytes
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayObjectTest.php27
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayTest.php27
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerCustomArrayObjectTest.php28
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php259
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php255
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php79
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php135
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php28
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CheckboxTypeTest.php162
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypePerformanceTest.php38
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php949
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php200
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php52
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php37
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php477
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php781
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php83
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php578
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php34
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/LanguageTypeTest.php47
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php36
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/MoneyTypeTest.php59
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php63
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/PasswordTypeTest.php51
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php149
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/SubmitTypeTest.php54
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php649
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TimezoneTypeTest.php30
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TypeTestCase.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php61
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/CsrfProvider/DefaultCsrfProviderTest.php81
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/CsrfProvider/SessionCsrfProviderTest.php75
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php78
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php301
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/HttpFoundation/EventListener/BindRequestListenerTest.php286
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php54
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php748
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php145
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php85
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Type/TypeTestCase.php49
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Util/ServerParamsTest.php46
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php1481
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationPathTest.php245
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/AlternatingRowType.php27
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/Author.php71
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/AuthorType.php30
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php70
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FixedDataTransformer.php45
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FixedFilterListener.php66
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooSubType.php32
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooSubTypeWithParentInstance.php32
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooType.php32
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooTypeBarExtension.php35
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooTypeBazExtension.php28
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/TestExtension.php72
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/foo0
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/FormBuilderTest.php232
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/FormConfigTest.php148
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/FormFactoryBuilderTest.php59
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/FormFactoryTest.php506
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/FormIntegrationTestCase.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/FormPerformanceTestCase.php21
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/FormRegistryTest.php243
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/FormRendererTest.php27
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/Guess/GuessTest.php36
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php219
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php280
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Tests/SimpleFormTest.php1045
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Util/FormUtil.php42
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Util/InheritDataAwareIterator.php35
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/Util/VirtualFormAwareIterator.php50
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/composer.json43
-rw-r--r--vendor/symfony/form/Symfony/Component/Form/phpunit.xml.dist29
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/.gitignore3
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/IcuCurrencyBundle.php28
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/IcuData.php66
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/IcuLanguageBundle.php28
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/IcuLocaleBundle.php28
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/IcuRegionBundle.php28
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/LICENSE19
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/README.md18
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/Resources/data/curr/en.php1791
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/Resources/data/lang/en.php750
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/Resources/data/locales/en.php305
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/Resources/data/region/en.php273
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/Resources/data/version.txt1
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/Tests/IcuIntegrationTest.php55
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/composer.json26
-rw-r--r--vendor/symfony/icu/Symfony/Component/Icu/phpunit.xml.dist29
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/.gitignore3
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/CONTRIBUTING.md91
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Collator/Collator.php295
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/AmPmTransformer.php46
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayOfWeekTransformer.php59
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayOfYearTransformer.php46
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayTransformer.php46
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/FullTransformer.php356
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour1200Transformer.php62
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour1201Transformer.php62
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour2400Transformer.php61
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour2401Transformer.php64
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/HourTransformer.php30
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/MinuteTransformer.php48
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/MonthTransformer.php143
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/QuarterTransformer.php64
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/SecondTransformer.php48
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/TimeZoneTransformer.php99
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Transformer.php64
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/YearTransformer.php50
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php631
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Exception/BadMethodCallException.php21
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Exception/ExceptionInterface.php21
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Exception/InvalidArgumentException.php21
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodArgumentNotImplementedException.php32
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodArgumentValueNotImplementedException.php41
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodNotImplementedException.php28
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Exception/NotImplementedException.php32
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Exception/OutOfBoundsException.php21
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Exception/RuntimeException.php21
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Globals/IntlGlobals.php137
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Intl.php211
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/LICENSE19
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Locale/Locale.php317
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php891
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/README.md25
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/AbstractBundle.php71
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Compiler/BundleCompiler.php71
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Compiler/BundleCompilerInterface.php29
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php94
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php74
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php115
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php64
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php52
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php41
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/AbstractBundleReader.php42
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BinaryBundleReader.php51
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BufferedBundleReader.php62
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BundleReaderInterface.php40
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/PhpBundleReader.php61
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/StructuredBundleReader.php113
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/StructuredBundleReaderInterface.php50
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/RegionBundle.php52
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php41
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php27
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/BundleTransformer.php96
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/CompilationContext.php97
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/CompilationContextInterface.php56
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/CurrencyBundleTransformationRule.php94
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/LanguageBundleTransformationRule.php71
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/LocaleBundleTransformationRule.php251
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/RegionBundleTransformationRule.php70
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/TransformationRuleInterface.php70
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/StubbingContext.php80
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/StubbingContextInterface.php46
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/ArrayAccessibleResourceBundle.php79
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/RecursiveArrayAccess.php33
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/RingBuffer.php88
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/BundleWriterInterface.php29
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/PhpBundleWriter.php50
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/TextBundleWriter.php202
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/autoload.php18
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/common.php69
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/copy-stubs-to-component.php63
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/create-stubs.php112
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/icu-version.php18
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/icu.ini9
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/test-compat.php56
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/update-icu-component.php212
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/util/test-compat-helper.php23
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/Collator.php21
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/IntlDateFormatter.php21
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/Locale.php21
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/NumberFormatter.php21
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/functions.php80
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/AbstractCollatorTest.php62
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/CollatorTest.php109
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/Verification/CollatorTest.php37
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php932
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php220
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/Verification/IntlDateFormatterTest.php64
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/AbstractIntlGlobalsTest.php41
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/IntlGlobalsTest.php22
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/Verification/IntlGlobalsTest.php36
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/AbstractLocaleTest.php29
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/LocaleTest.php159
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/Verification/LocaleTest.php38
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php707
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/NumberFormatterTest.php239
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/Verification/NumberFormatterTest.php54
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/AbstractBundleTest.php55
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/CurrencyBundleTest.php98
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/LanguageBundleTest.php197
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/LocaleBundleTest.php64
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/AbstractBundleReaderTest.php64
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/BinaryBundleReaderTest.php58
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/NotAFile/en.php/.gitkeep0
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.php14
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.resbin0 -> 84 bytes
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.txt3
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/PhpBundleReaderTest.php63
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/StructuredBundleReaderTest.php223
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/RegionBundleTest.php63
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Util/RingBufferTest.php101
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.php23
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.resbin0 -> 316 bytes
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.txt23
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/PhpBundleWriterTest.php62
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/TextBundleWriterTest.php67
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Util/IcuVersionTest.php111
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Tests/Util/VersionTest.php87
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Util/IcuVersion.php105
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Util/IntlTestHelper.php128
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Util/SvnCommit.php66
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Util/SvnRepository.php141
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/Util/Version.php96
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/composer.json48
-rw-r--r--vendor/symfony/intl/Symfony/Component/Intl/phpunit.xml.dist29
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/.gitignore4
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/ExceptionInterface.php21
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/InvalidOptionsException.php21
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/MissingOptionsException.php21
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/OptionDefinitionException.php21
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/LICENSE19
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Options.php513
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/OptionsResolver.php346
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/OptionsResolverInterface.php210
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/README.md107
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php681
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Tests/OptionsTest.php529
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/composer.json31
-rw-r--r--vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/phpunit.xml.dist29
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitattributes2
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitignore4
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/CHANGELOG.md14
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php21
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/InvalidPropertyPathException.php21
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/NoSuchPropertyException.php21
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/OutOfBoundsException.php21
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/RuntimeException.php21
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/UnexpectedTypeException.php25
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/LICENSE19
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccess.php60
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessor.php442
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php67
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php81
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPath.php225
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathBuilder.php306
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathInterface.php86
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIterator.php55
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIteratorInterface.php34
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/README.md14
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php195
-rw-r--r--vendor/symfony/property-access/Symfony/Component/PropertyAccess/composer.json31
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/.gitignore4
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Annotation/Route.php156
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/CHANGELOG.md162
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/CompiledRoute.php134
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php23
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php23
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php46
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php24
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php25
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php23
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php55
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php45
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php41
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php123
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php322
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php87
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/LICENSE19
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php246
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php77
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php122
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php52
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php62
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php238
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php212
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd64
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php94
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php252
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php159
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperPrefixCollection.php108
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperRoute.php64
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php45
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php37
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php378
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php61
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php35
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php39
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php121
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php208
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php43
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/README.md34
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RequestContext.php315
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php36
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Route.php594
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RouteCollection.php271
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RouteCompiler.php233
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php32
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Router.php289
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RouterInterface.php32
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Annotation/RouteTest.php49
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/CompiledRouteTest.php26
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php16
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/BarClass.php19
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooClass.php16
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/CustomXmlFileLoader.php26
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/RedirectableUrlMatcher.php30
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/annotated.php0
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache163
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php310
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.apache7
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php340
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php43
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/empty.yml0
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo.xml0
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo1.xml0
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/incomplete.yml2
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_id.xml8
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_path.xml8
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml13
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_resource_plus_path.yml3
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_type_without_resource.yml3
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.xml11
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.yml1
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid2.yml1
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidkeys.yml3
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidnode.xml8
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidroute.xml13
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/special_route_name.yml2
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.php23
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml21
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml17
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.xml12
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.yml7
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/withdoctype.xml3
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php117
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php635
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTest.php38
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php119
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php53
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php47
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/ClosureLoaderTest.php55
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php55
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php127
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php113
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/ApacheUrlMatcherTest.php137
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/ApacheMatcherDumperTest.php196
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperCollectionTest.php33
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php123
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php261
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php58
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php66
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php383
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCollectionTest.php255
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCompilerTest.php253
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteTest.php192
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/RouterTest.php138
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/composer.json42
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/phpunit.xml.dist29
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/.gitignore4
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/CHANGELOG.md27
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Catalogue/AbstractOperation.php146
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Catalogue/DiffOperation.php49
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Catalogue/MergeOperation.php45
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Catalogue/OperationInterface.php63
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/CsvFileDumper.php63
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/DumperInterface.php31
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/FileDumper.php65
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/IcuResFileDumper.php135
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/IniFileDumper.php45
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/MoFileDumper.php82
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/PhpFileDumper.php40
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/PoFileDumper.php55
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/QtFileDumper.php50
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/XliffFileDumper.php66
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Dumper/YamlFileDumper.php39
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Exception/ExceptionInterface.php23
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Exception/InvalidResourceException.php23
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Exception/NotFoundResourceException.php23
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Extractor/ChainExtractor.php60
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Extractor/ExtractorInterface.php38
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/IdentityTranslator.php74
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Interval.php107
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/LICENSE19
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/ArrayLoader.php70
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/CsvFileLoader.php92
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/IcuDatFileLoader.php54
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/IcuResFileLoader.php84
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/IniFileLoader.php45
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/LoaderInterface.php41
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/MoFileLoader.php179
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/PhpFileLoader.php49
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/PoFileLoader.php178
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/QtFileLoader.php95
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php163
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/YamlFileLoader.php71
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xliff-core-1.2-strict.xsd2223
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xml.xsd309
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/MessageCatalogue.php295
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/MessageCatalogueInterface.php172
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/MessageSelector.php82
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/MetadataAwareInterface.php54
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/PluralizationRules.php219
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/README.md35
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTest.php74
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/DiffOperationTest.php60
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php60
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/CsvFileDumperTest.php33
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/IcuResFileDumperTest.php37
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/IniFileDumperTest.php32
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/MoFileDumperTest.php31
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/PhpFileDumperTest.php32
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/PoFileDumperTest.php31
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/QtFileDumperTest.php32
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php32
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/YamlFileDumperTest.php39
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php61
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/IntervalTest.php48
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/CsvFileLoaderTest.php67
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IcuDatFileLoaderTest.php72
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IcuResFileLoaderTest.php59
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IniFileLoaderTest.php57
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/LocalizedTestCase.php22
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/MoFileLoaderTest.php67
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/PhpFileLoaderTest.php56
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/PoFileLoaderTest.php79
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/QtFileLoaderTest.php66
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php113
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/YamlFileLoaderTest.php81
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/MessageCatalogueTest.php212
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/MessageSelectorTest.php80
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/PluralizationRulesTest.php124
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/TranslatorTest.php306
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty-translation.po3
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.csv0
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.ini0
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.mo0
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.po0
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.yml0
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/encoding.xlf15
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/invalid-xml-resources.xlf23
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/non-valid.xlf11
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/non-valid.yml1
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/plurals.mobin0 -> 74 bytes
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/plurals.po5
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resname.xlf19
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/corrupted/resources.dat1
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/en.resbin0 -> 120 bytes
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/en.txt3
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/fr.resbin0 -> 124 bytes
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/fr.txt3
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/packagelist.txt2
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/resources.datbin0 -> 352 bytes
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/res/en.resbin0 -> 84 bytes
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources-clean.xlf15
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.csv4
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.ini1
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.mobin0 -> 52 bytes
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.php5
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.po2
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.ts10
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.xlf23
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.yml1
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/valid.csv4
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/withdoctype.xlf12
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Translator.php282
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/TranslatorInterface.php69
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/Writer/TranslationWriter.php73
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/composer.json39
-rw-r--r--vendor/symfony/translation/Symfony/Component/Translation/phpunit.xml.dist29
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/.gitignore4
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/CHANGELOG.md29
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/CodeExtension.php232
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/FormExtension.php136
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php88
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/RoutingExtension.php100
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/SecurityExtension.php63
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/TranslationExtension.php118
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/YamlExtension.php67
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRenderer.php41
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngine.php183
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngineInterface.php27
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererInterface.php27
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/LICENSE19
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormEnctypeNode.php31
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormThemeNode.php40
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/RenderBlockNode.php42
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php106
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php33
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransNode.php119
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/Scope.php135
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php106
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php137
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/README.md15
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig390
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig52
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php69
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubFilesystemLoader.php30
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php35
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php209
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php131
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php68
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/RoutingExtensionTest.php60
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php151
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/child_label.html.twig3
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/custom_widgets.html.twig16
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/parent_label.html.twig3
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme.html.twig6
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_extends.html.twig8
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_use.html.twig8
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/FormThemeTest.php85
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php282
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/ScopeTest.php25
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationDefaultDomainNodeVisitorTest.php83
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationNodeVisitorTest.php61
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php77
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TestCase.php22
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php108
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php81
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php61
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransChoiceTokenParser.php89
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php48
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransTokenParser.php89
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Translation/TwigExtractor.php86
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TwigEngine.php126
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/composer.json50
-rw-r--r--vendor/symfony/twig-bridge/Symfony/Bridge/Twig/phpunit.xml.dist30
796 files changed, 87766 insertions, 0 deletions
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/.gitignore b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/.gitignore
new file mode 100644
index 00000000..44de97a3
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/.gitignore
@@ -0,0 +1,4 @@
1vendor/
2composer.lock
3phpunit.xml
4
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/CHANGELOG.md b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/CHANGELOG.md
new file mode 100644
index 00000000..536c5ac7
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/CHANGELOG.md
@@ -0,0 +1,16 @@
1CHANGELOG
2=========
3
42.1.0
5-----
6
7 * added TraceableEventDispatcherInterface
8 * added ContainerAwareEventDispatcher
9 * added a reference to the EventDispatcher on the Event
10 * added a reference to the Event name on the event
11 * added fluid interface to the dispatch() method which now returns the Event
12 object
13 * added GenericEvent event class
14 * added the possibility for subscribers to subscribe several times for the
15 same event
16 * added ImmutableEventDispatcher
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php
new file mode 100644
index 00000000..9448ed43
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php
@@ -0,0 +1,202 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher;
13
14use Symfony\Component\DependencyInjection\ContainerInterface;
15
16/**
17 * Lazily loads listeners and subscribers from the dependency injection
18 * container
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 * @author Jordan Alliot <jordan.alliot@gmail.com>
23 */
24class ContainerAwareEventDispatcher extends EventDispatcher
25{
26 /**
27 * The container from where services are loaded
28 * @var ContainerInterface
29 */
30 private $container;
31
32 /**
33 * The service IDs of the event listeners and subscribers
34 * @var array
35 */
36 private $listenerIds = array();
37
38 /**
39 * The services registered as listeners
40 * @var array
41 */
42 private $listeners = array();
43
44 /**
45 * Constructor.
46 *
47 * @param ContainerInterface $container A ContainerInterface instance
48 */
49 public function __construct(ContainerInterface $container)
50 {
51 $this->container = $container;
52 }
53
54 /**
55 * Adds a service as event listener
56 *
57 * @param string $eventName Event for which the listener is added
58 * @param array $callback The service ID of the listener service & the method
59 * name that has to be called
60 * @param integer $priority The higher this value, the earlier an event listener
61 * will be triggered in the chain.
62 * Defaults to 0.
63 *
64 * @throws \InvalidArgumentException
65 */
66 public function addListenerService($eventName, $callback, $priority = 0)
67 {
68 if (!is_array($callback) || 2 !== count($callback)) {
69 throw new \InvalidArgumentException('Expected an array("service", "method") argument');
70 }
71
72 $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority);
73 }
74
75 public function removeListener($eventName, $listener)
76 {
77 $this->lazyLoad($eventName);
78
79 if (isset($this->listeners[$eventName])) {
80 foreach ($this->listeners[$eventName] as $key => $l) {
81 foreach ($this->listenerIds[$eventName] as $i => $args) {
82 list($serviceId, $method, $priority) = $args;
83 if ($key === $serviceId.'.'.$method) {
84 if ($listener === array($l, $method)) {
85 unset($this->listeners[$eventName][$key]);
86 if (empty($this->listeners[$eventName])) {
87 unset($this->listeners[$eventName]);
88 }
89 unset($this->listenerIds[$eventName][$i]);
90 if (empty($this->listenerIds[$eventName])) {
91 unset($this->listenerIds[$eventName]);
92 }
93 }
94 }
95 }
96 }
97 }
98
99 parent::removeListener($eventName, $listener);
100 }
101
102 /**
103 * @see EventDispatcherInterface::hasListeners
104 */
105 public function hasListeners($eventName = null)
106 {
107 if (null === $eventName) {
108 return (Boolean) count($this->listenerIds) || (Boolean) count($this->listeners);
109 }
110
111 if (isset($this->listenerIds[$eventName])) {
112 return true;
113 }
114
115 return parent::hasListeners($eventName);
116 }
117
118 /**
119 * @see EventDispatcherInterface::getListeners
120 */
121 public function getListeners($eventName = null)
122 {
123 if (null === $eventName) {
124 foreach (array_keys($this->listenerIds) as $serviceEventName) {
125 $this->lazyLoad($serviceEventName);
126 }
127 } else {
128 $this->lazyLoad($eventName);
129 }
130
131 return parent::getListeners($eventName);
132 }
133
134 /**
135 * Adds a service as event subscriber
136 *
137 * @param string $serviceId The service ID of the subscriber service
138 * @param string $class The service's class name (which must implement EventSubscriberInterface)
139 */
140 public function addSubscriberService($serviceId, $class)
141 {
142 foreach ($class::getSubscribedEvents() as $eventName => $params) {
143 if (is_string($params)) {
144 $this->listenerIds[$eventName][] = array($serviceId, $params, 0);
145 } elseif (is_string($params[0])) {
146 $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0);
147 } else {
148 foreach ($params as $listener) {
149 $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0);
150 }
151 }
152 }
153 }
154
155 /**
156 * {@inheritDoc}
157 *
158 * Lazily loads listeners for this event from the dependency injection
159 * container.
160 *
161 * @throws \InvalidArgumentException if the service is not defined
162 */
163 public function dispatch($eventName, Event $event = null)
164 {
165 $this->lazyLoad($eventName);
166
167 return parent::dispatch($eventName, $event);
168 }
169
170 public function getContainer()
171 {
172 return $this->container;
173 }
174
175 /**
176 * Lazily loads listeners for this event from the dependency injection
177 * container.
178 *
179 * @param string $eventName The name of the event to dispatch. The name of
180 * the event is the name of the method that is
181 * invoked on listeners.
182 */
183 protected function lazyLoad($eventName)
184 {
185 if (isset($this->listenerIds[$eventName])) {
186 foreach ($this->listenerIds[$eventName] as $args) {
187 list($serviceId, $method, $priority) = $args;
188 $listener = $this->container->get($serviceId);
189
190 $key = $serviceId.'.'.$method;
191 if (!isset($this->listeners[$eventName][$key])) {
192 $this->addListener($eventName, array($listener, $method), $priority);
193 } elseif ($listener !== $this->listeners[$eventName][$key]) {
194 parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method));
195 $this->addListener($eventName, array($listener, $method), $priority);
196 }
197
198 $this->listeners[$eventName][$key] = $listener;
199 }
200 }
201 }
202}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php
new file mode 100644
index 00000000..a67a9790
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher\Debug;
13
14/**
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17interface TraceableEventDispatcherInterface
18{
19 /**
20 * Gets the called listeners.
21 *
22 * @return array An array of called listeners
23 */
24 public function getCalledListeners();
25
26 /**
27 * Gets the not called listeners.
28 *
29 * @return array An array of not called listeners
30 */
31 public function getNotCalledListeners();
32}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Event.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Event.php
new file mode 100644
index 00000000..42f09eaa
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Event.php
@@ -0,0 +1,121 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher;
13
14/**
15 * Event is the base class for classes containing event data.
16 *
17 * This class contains no event data. It is used by events that do not pass
18 * state information to an event handler when an event is raised.
19 *
20 * You can call the method stopPropagation() to abort the execution of
21 * further listeners in your event listener.
22 *
23 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
24 * @author Jonathan Wage <jonwage@gmail.com>
25 * @author Roman Borschel <roman@code-factory.org>
26 * @author Bernhard Schussek <bschussek@gmail.com>
27 *
28 * @api
29 */
30class Event
31{
32 /**
33 * @var Boolean Whether no further event listeners should be triggered
34 */
35 private $propagationStopped = false;
36
37 /**
38 * @var EventDispatcher Dispatcher that dispatched this event
39 */
40 private $dispatcher;
41
42 /**
43 * @var string This event's name
44 */
45 private $name;
46
47 /**
48 * Returns whether further event listeners should be triggered.
49 *
50 * @see Event::stopPropagation
51 * @return Boolean Whether propagation was already stopped for this event.
52 *
53 * @api
54 */
55 public function isPropagationStopped()
56 {
57 return $this->propagationStopped;
58 }
59
60 /**
61 * Stops the propagation of the event to further event listeners.
62 *
63 * If multiple event listeners are connected to the same event, no
64 * further event listener will be triggered once any trigger calls
65 * stopPropagation().
66 *
67 * @api
68 */
69 public function stopPropagation()
70 {
71 $this->propagationStopped = true;
72 }
73
74 /**
75 * Stores the EventDispatcher that dispatches this Event
76 *
77 * @param EventDispatcherInterface $dispatcher
78 *
79 * @api
80 */
81 public function setDispatcher(EventDispatcherInterface $dispatcher)
82 {
83 $this->dispatcher = $dispatcher;
84 }
85
86 /**
87 * Returns the EventDispatcher that dispatches this Event
88 *
89 * @return EventDispatcherInterface
90 *
91 * @api
92 */
93 public function getDispatcher()
94 {
95 return $this->dispatcher;
96 }
97
98 /**
99 * Gets the event's name.
100 *
101 * @return string
102 *
103 * @api
104 */
105 public function getName()
106 {
107 return $this->name;
108 }
109
110 /**
111 * Sets the event's name property.
112 *
113 * @param string $name The event name.
114 *
115 * @api
116 */
117 public function setName($name)
118 {
119 $this->name = $name;
120 }
121}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php
new file mode 100644
index 00000000..eb1fb594
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php
@@ -0,0 +1,185 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher;
13
14/**
15 * The EventDispatcherInterface is the central point of Symfony's event listener system.
16 *
17 * Listeners are registered on the manager and events are dispatched through the
18 * manager.
19 *
20 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21 * @author Jonathan Wage <jonwage@gmail.com>
22 * @author Roman Borschel <roman@code-factory.org>
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 * @author Fabien Potencier <fabien@symfony.com>
25 * @author Jordi Boggiano <j.boggiano@seld.be>
26 * @author Jordan Alliot <jordan.alliot@gmail.com>
27 *
28 * @api
29 */
30class EventDispatcher implements EventDispatcherInterface
31{
32 private $listeners = array();
33 private $sorted = array();
34
35 /**
36 * @see EventDispatcherInterface::dispatch
37 *
38 * @api
39 */
40 public function dispatch($eventName, Event $event = null)
41 {
42 if (null === $event) {
43 $event = new Event();
44 }
45
46 $event->setDispatcher($this);
47 $event->setName($eventName);
48
49 if (!isset($this->listeners[$eventName])) {
50 return $event;
51 }
52
53 $this->doDispatch($this->getListeners($eventName), $eventName, $event);
54
55 return $event;
56 }
57
58 /**
59 * @see EventDispatcherInterface::getListeners
60 */
61 public function getListeners($eventName = null)
62 {
63 if (null !== $eventName) {
64 if (!isset($this->sorted[$eventName])) {
65 $this->sortListeners($eventName);
66 }
67
68 return $this->sorted[$eventName];
69 }
70
71 foreach (array_keys($this->listeners) as $eventName) {
72 if (!isset($this->sorted[$eventName])) {
73 $this->sortListeners($eventName);
74 }
75 }
76
77 return $this->sorted;
78 }
79
80 /**
81 * @see EventDispatcherInterface::hasListeners
82 */
83 public function hasListeners($eventName = null)
84 {
85 return (Boolean) count($this->getListeners($eventName));
86 }
87
88 /**
89 * @see EventDispatcherInterface::addListener
90 *
91 * @api
92 */
93 public function addListener($eventName, $listener, $priority = 0)
94 {
95 $this->listeners[$eventName][$priority][] = $listener;
96 unset($this->sorted[$eventName]);
97 }
98
99 /**
100 * @see EventDispatcherInterface::removeListener
101 */
102 public function removeListener($eventName, $listener)
103 {
104 if (!isset($this->listeners[$eventName])) {
105 return;
106 }
107
108 foreach ($this->listeners[$eventName] as $priority => $listeners) {
109 if (false !== ($key = array_search($listener, $listeners, true))) {
110 unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]);
111 }
112 }
113 }
114
115 /**
116 * @see EventDispatcherInterface::addSubscriber
117 *
118 * @api
119 */
120 public function addSubscriber(EventSubscriberInterface $subscriber)
121 {
122 foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
123 if (is_string($params)) {
124 $this->addListener($eventName, array($subscriber, $params));
125 } elseif (is_string($params[0])) {
126 $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
127 } else {
128 foreach ($params as $listener) {
129 $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
130 }
131 }
132 }
133 }
134
135 /**
136 * @see EventDispatcherInterface::removeSubscriber
137 */
138 public function removeSubscriber(EventSubscriberInterface $subscriber)
139 {
140 foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
141 if (is_array($params) && is_array($params[0])) {
142 foreach ($params as $listener) {
143 $this->removeListener($eventName, array($subscriber, $listener[0]));
144 }
145 } else {
146 $this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0]));
147 }
148 }
149 }
150
151 /**
152 * Triggers the listeners of an event.
153 *
154 * This method can be overridden to add functionality that is executed
155 * for each listener.
156 *
157 * @param array[callback] $listeners The event listeners.
158 * @param string $eventName The name of the event to dispatch.
159 * @param Event $event The event object to pass to the event handlers/listeners.
160 */
161 protected function doDispatch($listeners, $eventName, Event $event)
162 {
163 foreach ($listeners as $listener) {
164 call_user_func($listener, $event);
165 if ($event->isPropagationStopped()) {
166 break;
167 }
168 }
169 }
170
171 /**
172 * Sorts the internal list of listeners for the given event by priority.
173 *
174 * @param string $eventName The name of the event.
175 */
176 private function sortListeners($eventName)
177 {
178 $this->sorted[$eventName] = array();
179
180 if (isset($this->listeners[$eventName])) {
181 krsort($this->listeners[$eventName]);
182 $this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]);
183 }
184 }
185}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcherInterface.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcherInterface.php
new file mode 100644
index 00000000..7aead23b
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcherInterface.php
@@ -0,0 +1,96 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher;
13
14/**
15 * The EventDispatcherInterface is the central point of Symfony's event listener system.
16 * Listeners are registered on the manager and events are dispatched through the
17 * manager.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 *
21 * @api
22 */
23interface EventDispatcherInterface
24{
25 /**
26 * Dispatches an event to all registered listeners.
27 *
28 * @param string $eventName The name of the event to dispatch. The name of
29 * the event is the name of the method that is
30 * invoked on listeners.
31 * @param Event $event The event to pass to the event handlers/listeners.
32 * If not supplied, an empty Event instance is created.
33 *
34 * @return Event
35 *
36 * @api
37 */
38 public function dispatch($eventName, Event $event = null);
39
40 /**
41 * Adds an event listener that listens on the specified events.
42 *
43 * @param string $eventName The event to listen on
44 * @param callable $listener The listener
45 * @param integer $priority The higher this value, the earlier an event
46 * listener will be triggered in the chain (defaults to 0)
47 *
48 * @api
49 */
50 public function addListener($eventName, $listener, $priority = 0);
51
52 /**
53 * Adds an event subscriber.
54 *
55 * The subscriber is asked for all the events he is
56 * interested in and added as a listener for these events.
57 *
58 * @param EventSubscriberInterface $subscriber The subscriber.
59 *
60 * @api
61 */
62 public function addSubscriber(EventSubscriberInterface $subscriber);
63
64 /**
65 * Removes an event listener from the specified events.
66 *
67 * @param string|array $eventName The event(s) to remove a listener from
68 * @param callable $listener The listener to remove
69 */
70 public function removeListener($eventName, $listener);
71
72 /**
73 * Removes an event subscriber.
74 *
75 * @param EventSubscriberInterface $subscriber The subscriber
76 */
77 public function removeSubscriber(EventSubscriberInterface $subscriber);
78
79 /**
80 * Gets the listeners of a specific event or all listeners.
81 *
82 * @param string $eventName The name of the event
83 *
84 * @return array The event listeners for the specified event, or all event listeners by event name
85 */
86 public function getListeners($eventName = null);
87
88 /**
89 * Checks whether an event has any registered listeners.
90 *
91 * @param string $eventName The name of the event
92 *
93 * @return Boolean true if the specified event has any listeners, false otherwise
94 */
95 public function hasListeners($eventName = null);
96}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventSubscriberInterface.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventSubscriberInterface.php
new file mode 100644
index 00000000..080f892f
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventSubscriberInterface.php
@@ -0,0 +1,50 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher;
13
14/**
15 * An EventSubscriber knows himself what events he is interested in.
16 * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes
17 * {@link getSubscribedEvents} and registers the subscriber as a listener for all
18 * returned events.
19 *
20 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21 * @author Jonathan Wage <jonwage@gmail.com>
22 * @author Roman Borschel <roman@code-factory.org>
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 *
25 * @api
26 */
27interface EventSubscriberInterface
28{
29 /**
30 * Returns an array of event names this subscriber wants to listen to.
31 *
32 * The array keys are event names and the value can be:
33 *
34 * * The method name to call (priority defaults to 0)
35 * * An array composed of the method name to call and the priority
36 * * An array of arrays composed of the method names to call and respective
37 * priorities, or 0 if unset
38 *
39 * For instance:
40 *
41 * * array('eventName' => 'methodName')
42 * * array('eventName' => array('methodName', $priority))
43 * * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
44 *
45 * @return array The event names to listen to
46 *
47 * @api
48 */
49 public static function getSubscribedEvents();
50}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/GenericEvent.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/GenericEvent.php
new file mode 100644
index 00000000..3a5efcfe
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/GenericEvent.php
@@ -0,0 +1,186 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher;
13
14/**
15 * Event encapsulation class.
16 *
17 * Encapsulates events thus decoupling the observer from the subject they encapsulate.
18 *
19 * @author Drak <drak@zikula.org>
20 */
21class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
22{
23 /**
24 * Observer pattern subject.
25 *
26 * @var mixed usually object or callable
27 */
28 protected $subject;
29
30 /**
31 * Array of arguments.
32 *
33 * @var array
34 */
35 protected $arguments;
36
37 /**
38 * Encapsulate an event with $subject and $args.
39 *
40 * @param mixed $subject The subject of the event, usually an object.
41 * @param array $arguments Arguments to store in the event.
42 */
43 public function __construct($subject = null, array $arguments = array())
44 {
45 $this->subject = $subject;
46 $this->arguments = $arguments;
47 }
48
49 /**
50 * Getter for subject property.
51 *
52 * @return mixed $subject The observer subject.
53 */
54 public function getSubject()
55 {
56 return $this->subject;
57 }
58
59 /**
60 * Get argument by key.
61 *
62 * @param string $key Key.
63 *
64 * @throws \InvalidArgumentException If key is not found.
65 *
66 * @return mixed Contents of array key.
67 */
68 public function getArgument($key)
69 {
70 if ($this->hasArgument($key)) {
71 return $this->arguments[$key];
72 }
73
74 throw new \InvalidArgumentException(sprintf('%s not found in %s', $key, $this->getName()));
75 }
76
77 /**
78 * Add argument to event.
79 *
80 * @param string $key Argument name.
81 * @param mixed $value Value.
82 *
83 * @return GenericEvent
84 */
85 public function setArgument($key, $value)
86 {
87 $this->arguments[$key] = $value;
88
89 return $this;
90 }
91
92 /**
93 * Getter for all arguments.
94 *
95 * @return array
96 */
97 public function getArguments()
98 {
99 return $this->arguments;
100 }
101
102 /**
103 * Set args property.
104 *
105 * @param array $args Arguments.
106 *
107 * @return GenericEvent
108 */
109 public function setArguments(array $args = array())
110 {
111 $this->arguments = $args;
112
113 return $this;
114 }
115
116 /**
117 * Has argument.
118 *
119 * @param string $key Key of arguments array.
120 *
121 * @return boolean
122 */
123 public function hasArgument($key)
124 {
125 return array_key_exists($key, $this->arguments);
126 }
127
128 /**
129 * ArrayAccess for argument getter.
130 *
131 * @param string $key Array key.
132 *
133 * @throws \InvalidArgumentException If key does not exist in $this->args.
134 *
135 * @return mixed
136 */
137 public function offsetGet($key)
138 {
139 return $this->getArgument($key);
140 }
141
142 /**
143 * ArrayAccess for argument setter.
144 *
145 * @param string $key Array key to set.
146 * @param mixed $value Value.
147 */
148 public function offsetSet($key, $value)
149 {
150 $this->setArgument($key, $value);
151 }
152
153 /**
154 * ArrayAccess for unset argument.
155 *
156 * @param string $key Array key.
157 */
158 public function offsetUnset($key)
159 {
160 if ($this->hasArgument($key)) {
161 unset($this->arguments[$key]);
162 }
163 }
164
165 /**
166 * ArrayAccess has argument.
167 *
168 * @param string $key Array key.
169 *
170 * @return boolean
171 */
172 public function offsetExists($key)
173 {
174 return $this->hasArgument($key);
175 }
176
177 /**
178 * IteratorAggregate for iterating over the object like an array
179 *
180 * @return \ArrayIterator
181 */
182 public function getIterator()
183 {
184 return new \ArrayIterator($this->arguments);
185 }
186}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php
new file mode 100644
index 00000000..b70b81a8
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php
@@ -0,0 +1,92 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher;
13
14/**
15 * A read-only proxy for an event dispatcher.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class ImmutableEventDispatcher implements EventDispatcherInterface
20{
21 /**
22 * The proxied dispatcher.
23 * @var EventDispatcherInterface
24 */
25 private $dispatcher;
26
27 /**
28 * Creates an unmodifiable proxy for an event dispatcher.
29 *
30 * @param EventDispatcherInterface $dispatcher The proxied event dispatcher.
31 */
32 public function __construct(EventDispatcherInterface $dispatcher)
33 {
34 $this->dispatcher = $dispatcher;
35 }
36
37 /**
38 * {@inheritdoc}
39 */
40 public function dispatch($eventName, Event $event = null)
41 {
42 return $this->dispatcher->dispatch($eventName, $event);
43 }
44
45 /**
46 * {@inheritdoc}
47 */
48 public function addListener($eventName, $listener, $priority = 0)
49 {
50 throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
51 }
52
53 /**
54 * {@inheritdoc}
55 */
56 public function addSubscriber(EventSubscriberInterface $subscriber)
57 {
58 throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
59 }
60
61 /**
62 * {@inheritdoc}
63 */
64 public function removeListener($eventName, $listener)
65 {
66 throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
67 }
68
69 /**
70 * {@inheritdoc}
71 */
72 public function removeSubscriber(EventSubscriberInterface $subscriber)
73 {
74 throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
75 }
76
77 /**
78 * {@inheritdoc}
79 */
80 public function getListeners($eventName = null)
81 {
82 return $this->dispatcher->getListeners($eventName);
83 }
84
85 /**
86 * {@inheritdoc}
87 */
88 public function hasListeners($eventName = null)
89 {
90 return $this->dispatcher->hasListeners($eventName);
91 }
92}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/LICENSE b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/README.md b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/README.md
new file mode 100644
index 00000000..11f6b188
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/README.md
@@ -0,0 +1,25 @@
1EventDispatcher Component
2=========================
3
4EventDispatcher implements a lightweight version of the Observer design
5pattern.
6
7 use Symfony\Component\EventDispatcher\EventDispatcher;
8 use Symfony\Component\EventDispatcher\Event;
9
10 $dispatcher = new EventDispatcher();
11
12 $dispatcher->addListener('event_name', function (Event $event) {
13 // ...
14 });
15
16 $dispatcher->dispatch('event_name');
17
18Resources
19---------
20
21You can run the unit tests with the following command:
22
23 $ cd path/to/Symfony/Component/EventDispatcher/
24 $ composer.phar install --dev
25 $ phpunit
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php
new file mode 100644
index 00000000..71f3ad05
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php
@@ -0,0 +1,257 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher\Tests;
13
14use Symfony\Component\DependencyInjection\Container;
15use Symfony\Component\DependencyInjection\Scope;
16use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
17use Symfony\Component\EventDispatcher\Event;
18use Symfony\Component\EventDispatcher\EventSubscriberInterface;
19
20class ContainerAwareEventDispatcherTest extends \PHPUnit_Framework_TestCase
21{
22 protected function setUp()
23 {
24 if (!class_exists('Symfony\Component\DependencyInjection\Container')) {
25 $this->markTestSkipped('The "DependencyInjection" component is not available');
26 }
27 }
28
29 public function testAddAListenerService()
30 {
31 $event = new Event();
32
33 $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
34
35 $service
36 ->expects($this->once())
37 ->method('onEvent')
38 ->with($event)
39 ;
40
41 $container = new Container();
42 $container->set('service.listener', $service);
43
44 $dispatcher = new ContainerAwareEventDispatcher($container);
45 $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
46
47 $dispatcher->dispatch('onEvent', $event);
48 }
49
50 public function testAddASubscriberService()
51 {
52 $event = new Event();
53
54 $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\SubscriberService');
55
56 $service
57 ->expects($this->once())
58 ->method('onEvent')
59 ->with($event)
60 ;
61
62 $container = new Container();
63 $container->set('service.subscriber', $service);
64
65 $dispatcher = new ContainerAwareEventDispatcher($container);
66 $dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService');
67
68 $dispatcher->dispatch('onEvent', $event);
69 }
70
71 public function testPreventDuplicateListenerService()
72 {
73 $event = new Event();
74
75 $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
76
77 $service
78 ->expects($this->once())
79 ->method('onEvent')
80 ->with($event)
81 ;
82
83 $container = new Container();
84 $container->set('service.listener', $service);
85
86 $dispatcher = new ContainerAwareEventDispatcher($container);
87 $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 5);
88 $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 10);
89
90 $dispatcher->dispatch('onEvent', $event);
91 }
92
93 /**
94 * @expectedException \InvalidArgumentException
95 */
96 public function testTriggerAListenerServiceOutOfScope()
97 {
98 $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
99
100 $scope = new Scope('scope');
101 $container = new Container();
102 $container->addScope($scope);
103 $container->enterScope('scope');
104
105 $container->set('service.listener', $service, 'scope');
106
107 $dispatcher = new ContainerAwareEventDispatcher($container);
108 $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
109
110 $container->leaveScope('scope');
111 $dispatcher->dispatch('onEvent');
112 }
113
114 public function testReEnteringAScope()
115 {
116 $event = new Event();
117
118 $service1 = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
119
120 $service1
121 ->expects($this->exactly(2))
122 ->method('onEvent')
123 ->with($event)
124 ;
125
126 $scope = new Scope('scope');
127 $container = new Container();
128 $container->addScope($scope);
129 $container->enterScope('scope');
130
131 $container->set('service.listener', $service1, 'scope');
132
133 $dispatcher = new ContainerAwareEventDispatcher($container);
134 $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
135 $dispatcher->dispatch('onEvent', $event);
136
137 $service2 = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
138
139 $service2
140 ->expects($this->once())
141 ->method('onEvent')
142 ->with($event)
143 ;
144
145 $container->enterScope('scope');
146 $container->set('service.listener', $service2, 'scope');
147
148 $dispatcher->dispatch('onEvent', $event);
149
150 $container->leaveScope('scope');
151
152 $dispatcher->dispatch('onEvent');
153 }
154
155 public function testHasListenersOnLazyLoad()
156 {
157 $event = new Event();
158
159 $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
160
161 $container = new Container();
162 $container->set('service.listener', $service);
163
164 $dispatcher = new ContainerAwareEventDispatcher($container);
165 $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
166
167 $event->setDispatcher($dispatcher);
168 $event->setName('onEvent');
169
170 $service
171 ->expects($this->once())
172 ->method('onEvent')
173 ->with($event)
174 ;
175
176 $this->assertTrue($dispatcher->hasListeners());
177
178 if ($dispatcher->hasListeners('onEvent')) {
179 $dispatcher->dispatch('onEvent');
180 }
181 }
182
183 public function testGetListenersOnLazyLoad()
184 {
185 $event = new Event();
186
187 $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
188
189 $container = new Container();
190 $container->set('service.listener', $service);
191
192 $dispatcher = new ContainerAwareEventDispatcher($container);
193 $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
194
195 $listeners = $dispatcher->getListeners();
196
197 $this->assertTrue(isset($listeners['onEvent']));
198
199 $this->assertCount(1, $dispatcher->getListeners('onEvent'));
200 }
201
202 public function testRemoveAfterDispatch()
203 {
204 $event = new Event();
205
206 $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
207
208 $container = new Container();
209 $container->set('service.listener', $service);
210
211 $dispatcher = new ContainerAwareEventDispatcher($container);
212 $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
213
214 $dispatcher->dispatch('onEvent', new Event());
215 $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent'));
216 $this->assertFalse($dispatcher->hasListeners('onEvent'));
217 }
218
219 public function testRemoveBeforeDispatch()
220 {
221 $event = new Event();
222
223 $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
224
225 $container = new Container();
226 $container->set('service.listener', $service);
227
228 $dispatcher = new ContainerAwareEventDispatcher($container);
229 $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
230
231 $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent'));
232 $this->assertFalse($dispatcher->hasListeners('onEvent'));
233 }
234}
235
236class Service
237{
238 public function onEvent(Event $e)
239 {
240 }
241}
242
243class SubscriberService implements EventSubscriberInterface
244{
245 public static function getSubscribedEvents()
246 {
247 return array(
248 'onEvent' => 'onEvent',
249 'onEvent' => array('onEvent', 10),
250 'onEvent' => array('onEvent'),
251 );
252 }
253
254 public function onEvent(Event $e)
255 {
256 }
257}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php
new file mode 100644
index 00000000..ad7e4484
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php
@@ -0,0 +1,320 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher\Tests;
13
14use Symfony\Component\EventDispatcher\Event;
15use Symfony\Component\EventDispatcher\EventDispatcher;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
18class EventDispatcherTest extends \PHPUnit_Framework_TestCase
19{
20 /* Some pseudo events */
21 const preFoo = 'pre.foo';
22 const postFoo = 'post.foo';
23 const preBar = 'pre.bar';
24 const postBar = 'post.bar';
25
26 private $dispatcher;
27
28 private $listener;
29
30 protected function setUp()
31 {
32 $this->dispatcher = new EventDispatcher();
33 $this->listener = new TestEventListener();
34 }
35
36 protected function tearDown()
37 {
38 $this->dispatcher = null;
39 $this->listener = null;
40 }
41
42 public function testInitialState()
43 {
44 $this->assertEquals(array(), $this->dispatcher->getListeners());
45 $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
46 $this->assertFalse($this->dispatcher->hasListeners(self::postFoo));
47 }
48
49 public function testAddListener()
50 {
51 $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo'));
52 $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'));
53 $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
54 $this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
55 $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo));
56 $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo));
57 $this->assertCount(2, $this->dispatcher->getListeners());
58 }
59
60 public function testGetListenersSortsByPriority()
61 {
62 $listener1 = new TestEventListener();
63 $listener2 = new TestEventListener();
64 $listener3 = new TestEventListener();
65 $listener1->name = '1';
66 $listener2->name = '2';
67 $listener3->name = '3';
68
69 $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10);
70 $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10);
71 $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo'));
72
73 $expected = array(
74 array($listener2, 'preFoo'),
75 array($listener3, 'preFoo'),
76 array($listener1, 'preFoo'),
77 );
78
79 $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo'));
80 }
81
82 public function testGetAllListenersSortsByPriority()
83 {
84 $listener1 = new TestEventListener();
85 $listener2 = new TestEventListener();
86 $listener3 = new TestEventListener();
87 $listener4 = new TestEventListener();
88 $listener5 = new TestEventListener();
89 $listener6 = new TestEventListener();
90
91 $this->dispatcher->addListener('pre.foo', $listener1, -10);
92 $this->dispatcher->addListener('pre.foo', $listener2);
93 $this->dispatcher->addListener('pre.foo', $listener3, 10);
94 $this->dispatcher->addListener('post.foo', $listener4, -10);
95 $this->dispatcher->addListener('post.foo', $listener5);
96 $this->dispatcher->addListener('post.foo', $listener6, 10);
97
98 $expected = array(
99 'pre.foo' => array($listener3, $listener2, $listener1),
100 'post.foo' => array($listener6, $listener5, $listener4),
101 );
102
103 $this->assertSame($expected, $this->dispatcher->getListeners());
104 }
105
106 public function testDispatch()
107 {
108 $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo'));
109 $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'));
110 $this->dispatcher->dispatch(self::preFoo);
111 $this->assertTrue($this->listener->preFooInvoked);
112 $this->assertFalse($this->listener->postFooInvoked);
113 $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent'));
114 $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo));
115 $event = new Event();
116 $return = $this->dispatcher->dispatch(self::preFoo, $event);
117 $this->assertEquals('pre.foo', $event->getName());
118 $this->assertSame($event, $return);
119 }
120
121 public function testDispatchForClosure()
122 {
123 $invoked = 0;
124 $listener = function () use (&$invoked) {
125 $invoked++;
126 };
127 $this->dispatcher->addListener('pre.foo', $listener);
128 $this->dispatcher->addListener('post.foo', $listener);
129 $this->dispatcher->dispatch(self::preFoo);
130 $this->assertEquals(1, $invoked);
131 }
132
133 public function testStopEventPropagation()
134 {
135 $otherListener = new TestEventListener();
136
137 // postFoo() stops the propagation, so only one listener should
138 // be executed
139 // Manually set priority to enforce $this->listener to be called first
140 $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10);
141 $this->dispatcher->addListener('post.foo', array($otherListener, 'preFoo'));
142 $this->dispatcher->dispatch(self::postFoo);
143 $this->assertTrue($this->listener->postFooInvoked);
144 $this->assertFalse($otherListener->postFooInvoked);
145 }
146
147 public function testDispatchByPriority()
148 {
149 $invoked = array();
150 $listener1 = function () use (&$invoked) {
151 $invoked[] = '1';
152 };
153 $listener2 = function () use (&$invoked) {
154 $invoked[] = '2';
155 };
156 $listener3 = function () use (&$invoked) {
157 $invoked[] = '3';
158 };
159 $this->dispatcher->addListener('pre.foo', $listener1, -10);
160 $this->dispatcher->addListener('pre.foo', $listener2);
161 $this->dispatcher->addListener('pre.foo', $listener3, 10);
162 $this->dispatcher->dispatch(self::preFoo);
163 $this->assertEquals(array('3', '2', '1'), $invoked);
164 }
165
166 public function testRemoveListener()
167 {
168 $this->dispatcher->addListener('pre.bar', $this->listener);
169 $this->assertTrue($this->dispatcher->hasListeners(self::preBar));
170 $this->dispatcher->removeListener('pre.bar', $this->listener);
171 $this->assertFalse($this->dispatcher->hasListeners(self::preBar));
172 $this->dispatcher->removeListener('notExists', $this->listener);
173 }
174
175 public function testAddSubscriber()
176 {
177 $eventSubscriber = new TestEventSubscriber();
178 $this->dispatcher->addSubscriber($eventSubscriber);
179 $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
180 $this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
181 }
182
183 public function testAddSubscriberWithPriorities()
184 {
185 $eventSubscriber = new TestEventSubscriber();
186 $this->dispatcher->addSubscriber($eventSubscriber);
187
188 $eventSubscriber = new TestEventSubscriberWithPriorities();
189 $this->dispatcher->addSubscriber($eventSubscriber);
190
191 $listeners = $this->dispatcher->getListeners('pre.foo');
192 $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
193 $this->assertCount(2, $listeners);
194 $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]);
195 }
196
197 public function testAddSubscriberWithMultipleListeners()
198 {
199 $eventSubscriber = new TestEventSubscriberWithMultipleListeners();
200 $this->dispatcher->addSubscriber($eventSubscriber);
201
202 $listeners = $this->dispatcher->getListeners('pre.foo');
203 $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
204 $this->assertCount(2, $listeners);
205 $this->assertEquals('preFoo2', $listeners[0][1]);
206 }
207
208 public function testRemoveSubscriber()
209 {
210 $eventSubscriber = new TestEventSubscriber();
211 $this->dispatcher->addSubscriber($eventSubscriber);
212 $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
213 $this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
214 $this->dispatcher->removeSubscriber($eventSubscriber);
215 $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
216 $this->assertFalse($this->dispatcher->hasListeners(self::postFoo));
217 }
218
219 public function testRemoveSubscriberWithPriorities()
220 {
221 $eventSubscriber = new TestEventSubscriberWithPriorities();
222 $this->dispatcher->addSubscriber($eventSubscriber);
223 $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
224 $this->dispatcher->removeSubscriber($eventSubscriber);
225 $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
226 }
227
228 public function testRemoveSubscriberWithMultipleListeners()
229 {
230 $eventSubscriber = new TestEventSubscriberWithMultipleListeners();
231 $this->dispatcher->addSubscriber($eventSubscriber);
232 $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
233 $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo));
234 $this->dispatcher->removeSubscriber($eventSubscriber);
235 $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
236 }
237
238 public function testEventReceivesTheDispatcherInstance()
239 {
240 $test = $this;
241 $this->dispatcher->addListener('test', function ($event) use (&$dispatcher) {
242 $dispatcher = $event->getDispatcher();
243 });
244 $this->dispatcher->dispatch('test');
245 $this->assertSame($this->dispatcher, $dispatcher);
246 }
247
248 /**
249 * @see https://bugs.php.net/bug.php?id=62976
250 *
251 * This bug affects:
252 * - The PHP 5.3 branch for versions < 5.3.18
253 * - The PHP 5.4 branch for versions < 5.4.8
254 * - The PHP 5.5 branch is not affected
255 */
256 public function testWorkaroundForPhpBug62976()
257 {
258 $dispatcher = new EventDispatcher();
259 $dispatcher->addListener('bug.62976', new CallableClass());
260 $dispatcher->removeListener('bug.62976', function() {});
261 $this->assertTrue($dispatcher->hasListeners('bug.62976'));
262 }
263}
264
265class CallableClass
266{
267 public function __invoke()
268 {
269 }
270}
271
272class TestEventListener
273{
274 public $preFooInvoked = false;
275 public $postFooInvoked = false;
276
277 /* Listener methods */
278
279 public function preFoo(Event $e)
280 {
281 $this->preFooInvoked = true;
282 }
283
284 public function postFoo(Event $e)
285 {
286 $this->postFooInvoked = true;
287
288 $e->stopPropagation();
289 }
290}
291
292class TestEventSubscriber implements EventSubscriberInterface
293{
294 public static function getSubscribedEvents()
295 {
296 return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo');
297 }
298}
299
300class TestEventSubscriberWithPriorities implements EventSubscriberInterface
301{
302 public static function getSubscribedEvents()
303 {
304 return array(
305 'pre.foo' => array('preFoo', 10),
306 'post.foo' => array('postFoo'),
307 );
308 }
309}
310
311class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface
312{
313 public static function getSubscribedEvents()
314 {
315 return array('pre.foo' => array(
316 array('preFoo1'),
317 array('preFoo2', 10)
318 ));
319 }
320}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventTest.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventTest.php
new file mode 100644
index 00000000..52aa9ad6
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/EventTest.php
@@ -0,0 +1,84 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher\Tests;
13
14use Symfony\Component\EventDispatcher\Event;
15use Symfony\Component\EventDispatcher\EventDispatcher;
16
17/**
18 * Test class for Event.
19 */
20class EventTest extends \PHPUnit_Framework_TestCase
21{
22 /**
23 * @var \Symfony\Component\EventDispatcher\Event
24 */
25 protected $event;
26
27 /**
28 * @var \Symfony\Component\EventDispatcher\EventDispatcher
29 */
30 protected $dispatcher;
31
32 /**
33 * Sets up the fixture, for example, opens a network connection.
34 * This method is called before a test is executed.
35 */
36 protected function setUp()
37 {
38 $this->event = new Event;
39 $this->dispatcher = new EventDispatcher();
40 }
41
42 /**
43 * Tears down the fixture, for example, closes a network connection.
44 * This method is called after a test is executed.
45 */
46 protected function tearDown()
47 {
48 $this->event = null;
49 $this->eventDispatcher = null;
50 }
51
52 public function testIsPropagationStopped()
53 {
54 $this->assertFalse($this->event->isPropagationStopped());
55 }
56
57 public function testStopPropagationAndIsPropagationStopped()
58 {
59 $this->event->stopPropagation();
60 $this->assertTrue($this->event->isPropagationStopped());
61 }
62
63 public function testSetDispatcher()
64 {
65 $this->event->setDispatcher($this->dispatcher);
66 $this->assertSame($this->dispatcher, $this->event->getDispatcher());
67 }
68
69 public function testGetDispatcher()
70 {
71 $this->assertNull($this->event->getDispatcher());
72 }
73
74 public function testGetName()
75 {
76 $this->assertNull($this->event->getName());
77 }
78
79 public function testSetName()
80 {
81 $this->event->setName('foo');
82 $this->assertEquals('foo', $this->event->getName());
83 }
84}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php
new file mode 100644
index 00000000..8dd6f5b4
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php
@@ -0,0 +1,140 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher\Tests;
13
14use Symfony\Component\EventDispatcher\GenericEvent;
15
16/**
17 * Test class for Event.
18 */
19class GenericEventTest extends \PHPUnit_Framework_TestCase
20{
21
22 /**
23 * @var GenericEvent
24 */
25 private $event;
26
27 private $subject;
28
29 /**
30 * Prepares the environment before running a test.
31 */
32 protected function setUp()
33 {
34 parent::setUp();
35
36 $this->subject = new \StdClass();
37 $this->event = new GenericEvent($this->subject, array('name' => 'Event'), 'foo');
38 }
39
40 /**
41 * Cleans up the environment after running a test.
42 */
43 protected function tearDown()
44 {
45 $this->subject = null;
46 $this->event = null;
47
48 parent::tearDown();
49 }
50
51 public function testConstruct()
52 {
53 $this->assertEquals($this->event, new GenericEvent($this->subject, array('name' => 'Event')));
54 }
55
56 /**
57 * Tests Event->getArgs()
58 */
59 public function testGetArguments()
60 {
61 // test getting all
62 $this->assertSame(array('name' => 'Event'), $this->event->getArguments());
63 }
64
65 public function testSetArguments()
66 {
67 $result = $this->event->setArguments(array('foo' => 'bar'));
68 $this->assertAttributeSame(array('foo' => 'bar'), 'arguments', $this->event);
69 $this->assertSame($this->event, $result);
70 }
71
72 public function testSetArgument()
73 {
74 $result = $this->event->setArgument('foo2', 'bar2');
75 $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event);
76 $this->assertEquals($this->event, $result);
77 }
78
79 public function testGetArgument()
80 {
81 // test getting key
82 $this->assertEquals('Event', $this->event->getArgument('name'));
83 }
84
85 /**
86 * @expectedException \InvalidArgumentException
87 */
88 public function testGetArgException()
89 {
90 $this->event->getArgument('nameNotExist');
91 }
92
93 public function testOffsetGet()
94 {
95 // test getting key
96 $this->assertEquals('Event', $this->event['name']);
97
98 // test getting invalid arg
99 $this->setExpectedException('InvalidArgumentException');
100 $this->assertFalse($this->event['nameNotExist']);
101 }
102
103 public function testOffsetSet()
104 {
105 $this->event['foo2'] = 'bar2';
106 $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event);
107 }
108
109 public function testOffsetUnset()
110 {
111 unset($this->event['name']);
112 $this->assertAttributeSame(array(), 'arguments', $this->event);
113 }
114
115 public function testOffsetIsset()
116 {
117 $this->assertTrue(isset($this->event['name']));
118 $this->assertFalse(isset($this->event['nameNotExist']));
119 }
120
121 public function testHasArgument()
122 {
123 $this->assertTrue($this->event->hasArgument('name'));
124 $this->assertFalse($this->event->hasArgument('nameNotExist'));
125 }
126
127 public function testGetSubject()
128 {
129 $this->assertSame($this->subject, $this->event->getSubject());
130 }
131
132 public function testHasIterator()
133 {
134 $data = array();
135 foreach ($this->event as $key => $value) {
136 $data[$key] = $value;
137 }
138 $this->assertEquals(array('name' => 'Event'), $data);
139 }
140}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ImmutableEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ImmutableEventDispatcherTest.php
new file mode 100644
index 00000000..6402f89f
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests/ImmutableEventDispatcherTest.php
@@ -0,0 +1,106 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\EventDispatcher\Tests;
13
14use Symfony\Component\EventDispatcher\Event;
15use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ImmutableEventDispatcherTest extends \PHPUnit_Framework_TestCase
22{
23 /**
24 * @var \PHPUnit_Framework_MockObject_MockObject
25 */
26 private $innerDispatcher;
27
28 /**
29 * @var ImmutableEventDispatcher
30 */
31 private $dispatcher;
32
33 protected function setUp()
34 {
35 $this->innerDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
36 $this->dispatcher = new ImmutableEventDispatcher($this->innerDispatcher);
37 }
38
39 public function testDispatchDelegates()
40 {
41 $event = new Event();
42
43 $this->innerDispatcher->expects($this->once())
44 ->method('dispatch')
45 ->with('event', $event)
46 ->will($this->returnValue('result'));
47
48 $this->assertSame('result', $this->dispatcher->dispatch('event', $event));
49 }
50
51 public function testGetListenersDelegates()
52 {
53 $this->innerDispatcher->expects($this->once())
54 ->method('getListeners')
55 ->with('event')
56 ->will($this->returnValue('result'));
57
58 $this->assertSame('result', $this->dispatcher->getListeners('event'));
59 }
60
61 public function testHasListenersDelegates()
62 {
63 $this->innerDispatcher->expects($this->once())
64 ->method('hasListeners')
65 ->with('event')
66 ->will($this->returnValue('result'));
67
68 $this->assertSame('result', $this->dispatcher->hasListeners('event'));
69 }
70
71 /**
72 * @expectedException \BadMethodCallException
73 */
74 public function testAddListenerDisallowed()
75 {
76 $this->dispatcher->addListener('event', function () { return 'foo'; });
77 }
78
79 /**
80 * @expectedException \BadMethodCallException
81 */
82 public function testAddSubscriberDisallowed()
83 {
84 $subscriber = $this->getMock('Symfony\Component\EventDispatcher\EventSubscriberInterface');
85
86 $this->dispatcher->addSubscriber($subscriber);
87 }
88
89 /**
90 * @expectedException \BadMethodCallException
91 */
92 public function testRemoveListenerDisallowed()
93 {
94 $this->dispatcher->removeListener('event', function () { return 'foo'; });
95 }
96
97 /**
98 * @expectedException \BadMethodCallException
99 */
100 public function testRemoveSubscriberDisallowed()
101 {
102 $subscriber = $this->getMock('Symfony\Component\EventDispatcher\EventSubscriberInterface');
103
104 $this->dispatcher->removeSubscriber($subscriber);
105 }
106}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/composer.json b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/composer.json
new file mode 100644
index 00000000..1db2ecfd
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/composer.json
@@ -0,0 +1,38 @@
1{
2 "name": "symfony/event-dispatcher",
3 "type": "library",
4 "description": "Symfony EventDispatcher Component",
5 "keywords": [],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3"
20 },
21 "require-dev": {
22 "symfony/dependency-injection": "~2.0"
23 },
24 "suggest": {
25 "symfony/dependency-injection": "",
26 "symfony/http-kernel": ""
27 },
28 "autoload": {
29 "psr-0": { "Symfony\\Component\\EventDispatcher\\": "" }
30 },
31 "target-dir": "Symfony/Component/EventDispatcher",
32 "minimum-stability": "dev",
33 "extra": {
34 "branch-alias": {
35 "dev-master": "2.3-dev"
36 }
37 }
38}
diff --git a/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/phpunit.xml.dist b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/phpunit.xml.dist
new file mode 100644
index 00000000..0c3de4f7
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/phpunit.xml.dist
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony EventDispatcher Component Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./Resources</directory>
25 <directory>./Tests</directory>
26 <directory>./vendor</directory>
27 </exclude>
28 </whitelist>
29 </filter>
30</phpunit>
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/.gitignore b/vendor/symfony/filesystem/Symfony/Component/Filesystem/.gitignore
new file mode 100644
index 00000000..44de97a3
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/.gitignore
@@ -0,0 +1,4 @@
1vendor/
2composer.lock
3phpunit.xml
4
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/CHANGELOG.md b/vendor/symfony/filesystem/Symfony/Component/Filesystem/CHANGELOG.md
new file mode 100644
index 00000000..e6aee66a
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/CHANGELOG.md
@@ -0,0 +1,18 @@
1CHANGELOG
2=========
3
42.3.0
5-----
6
7 * added the dumpFile() method to atomically write files
8
92.2.0
10-----
11
12 * added a delete option for the mirror() method
13
142.1.0
15-----
16
17 * 24eb396 : BC Break : mkdir() function now throws exception in case of failure instead of returning Boolean value
18 * created the component
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/ExceptionInterface.php b/vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..bc9748d7
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/ExceptionInterface.php
@@ -0,0 +1,24 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Filesystem\Exception;
13
14/**
15 * Exception interface for all exceptions thrown by the component.
16 *
17 * @author Romain Neutron <imprec@gmail.com>
18 *
19 * @api
20 */
21interface ExceptionInterface
22{
23
24}
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/IOException.php b/vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/IOException.php
new file mode 100644
index 00000000..5b27e661
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/IOException.php
@@ -0,0 +1,24 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Filesystem\Exception;
13
14/**
15 * Exception class thrown when a filesystem operation failure happens
16 *
17 * @author Romain Neutron <imprec@gmail.com>
18 *
19 * @api
20 */
21class IOException extends \RuntimeException implements ExceptionInterface
22{
23
24}
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/Filesystem.php b/vendor/symfony/filesystem/Symfony/Component/Filesystem/Filesystem.php
new file mode 100644
index 00000000..6e015b4b
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/Filesystem.php
@@ -0,0 +1,471 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Filesystem;
13
14use Symfony\Component\Filesystem\Exception\IOException;
15
16/**
17 * Provides basic utility to manipulate the file system.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class Filesystem
22{
23 /**
24 * Copies a file.
25 *
26 * This method only copies the file if the origin file is newer than the target file.
27 *
28 * By default, if the target already exists, it is not overridden.
29 *
30 * @param string $originFile The original filename
31 * @param string $targetFile The target filename
32 * @param boolean $override Whether to override an existing file or not
33 *
34 * @throws IOException When copy fails
35 */
36 public function copy($originFile, $targetFile, $override = false)
37 {
38 if (stream_is_local($originFile) && !is_file($originFile)) {
39 throw new IOException(sprintf('Failed to copy %s because file not exists', $originFile));
40 }
41
42 $this->mkdir(dirname($targetFile));
43
44 if (!$override && is_file($targetFile)) {
45 $doCopy = filemtime($originFile) > filemtime($targetFile);
46 } else {
47 $doCopy = true;
48 }
49
50 if ($doCopy) {
51 // https://bugs.php.net/bug.php?id=64634
52 $source = fopen($originFile, 'r');
53 $target = fopen($targetFile, 'w+');
54 stream_copy_to_stream($source, $target);
55 fclose($source);
56 fclose($target);
57 unset($source, $target);
58
59 if (!is_file($targetFile)) {
60 throw new IOException(sprintf('Failed to copy %s to %s', $originFile, $targetFile));
61 }
62 }
63 }
64
65 /**
66 * Creates a directory recursively.
67 *
68 * @param string|array|\Traversable $dirs The directory path
69 * @param integer $mode The directory mode
70 *
71 * @throws IOException On any directory creation failure
72 */
73 public function mkdir($dirs, $mode = 0777)
74 {
75 foreach ($this->toIterator($dirs) as $dir) {
76 if (is_dir($dir)) {
77 continue;
78 }
79
80 if (true !== @mkdir($dir, $mode, true)) {
81 throw new IOException(sprintf('Failed to create %s', $dir));
82 }
83 }
84 }
85
86 /**
87 * Checks the existence of files or directories.
88 *
89 * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to check
90 *
91 * @return Boolean true if the file exists, false otherwise
92 */
93 public function exists($files)
94 {
95 foreach ($this->toIterator($files) as $file) {
96 if (!file_exists($file)) {
97 return false;
98 }
99 }
100
101 return true;
102 }
103
104 /**
105 * Sets access and modification time of file.
106 *
107 * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to create
108 * @param integer $time The touch time as a unix timestamp
109 * @param integer $atime The access time as a unix timestamp
110 *
111 * @throws IOException When touch fails
112 */
113 public function touch($files, $time = null, $atime = null)
114 {
115 foreach ($this->toIterator($files) as $file) {
116 $touch = $time ? @touch($file, $time, $atime) : @touch($file);
117 if (true !== $touch) {
118 throw new IOException(sprintf('Failed to touch %s', $file));
119 }
120 }
121 }
122
123 /**
124 * Removes files or directories.
125 *
126 * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to remove
127 *
128 * @throws IOException When removal fails
129 */
130 public function remove($files)
131 {
132 $files = iterator_to_array($this->toIterator($files));
133 $files = array_reverse($files);
134 foreach ($files as $file) {
135 if (!file_exists($file) && !is_link($file)) {
136 continue;
137 }
138
139 if (is_dir($file) && !is_link($file)) {
140 $this->remove(new \FilesystemIterator($file));
141
142 if (true !== @rmdir($file)) {
143 throw new IOException(sprintf('Failed to remove directory %s', $file));
144 }
145 } else {
146 // https://bugs.php.net/bug.php?id=52176
147 if (defined('PHP_WINDOWS_VERSION_MAJOR') && is_dir($file)) {
148 if (true !== @rmdir($file)) {
149 throw new IOException(sprintf('Failed to remove file %s', $file));
150 }
151 } else {
152 if (true !== @unlink($file)) {
153 throw new IOException(sprintf('Failed to remove file %s', $file));
154 }
155 }
156 }
157 }
158 }
159
160 /**
161 * Change mode for an array of files or directories.
162 *
163 * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change mode
164 * @param integer $mode The new mode (octal)
165 * @param integer $umask The mode mask (octal)
166 * @param Boolean $recursive Whether change the mod recursively or not
167 *
168 * @throws IOException When the change fail
169 */
170 public function chmod($files, $mode, $umask = 0000, $recursive = false)
171 {
172 foreach ($this->toIterator($files) as $file) {
173 if ($recursive && is_dir($file) && !is_link($file)) {
174 $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
175 }
176 if (true !== @chmod($file, $mode & ~$umask)) {
177 throw new IOException(sprintf('Failed to chmod file %s', $file));
178 }
179 }
180 }
181
182 /**
183 * Change the owner of an array of files or directories
184 *
185 * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change owner
186 * @param string $user The new owner user name
187 * @param Boolean $recursive Whether change the owner recursively or not
188 *
189 * @throws IOException When the change fail
190 */
191 public function chown($files, $user, $recursive = false)
192 {
193 foreach ($this->toIterator($files) as $file) {
194 if ($recursive && is_dir($file) && !is_link($file)) {
195 $this->chown(new \FilesystemIterator($file), $user, true);
196 }
197 if (is_link($file) && function_exists('lchown')) {
198 if (true !== @lchown($file, $user)) {
199 throw new IOException(sprintf('Failed to chown file %s', $file));
200 }
201 } else {
202 if (true !== @chown($file, $user)) {
203 throw new IOException(sprintf('Failed to chown file %s', $file));
204 }
205 }
206 }
207 }
208
209 /**
210 * Change the group of an array of files or directories
211 *
212 * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change group
213 * @param string $group The group name
214 * @param Boolean $recursive Whether change the group recursively or not
215 *
216 * @throws IOException When the change fail
217 */
218 public function chgrp($files, $group, $recursive = false)
219 {
220 foreach ($this->toIterator($files) as $file) {
221 if ($recursive && is_dir($file) && !is_link($file)) {
222 $this->chgrp(new \FilesystemIterator($file), $group, true);
223 }
224 if (is_link($file) && function_exists('lchgrp')) {
225 if (true !== @lchgrp($file, $group)) {
226 throw new IOException(sprintf('Failed to chgrp file %s', $file));
227 }
228 } else {
229 if (true !== @chgrp($file, $group)) {
230 throw new IOException(sprintf('Failed to chgrp file %s', $file));
231 }
232 }
233 }
234 }
235
236 /**
237 * Renames a file or a directory.
238 *
239 * @param string $origin The origin filename or directory
240 * @param string $target The new filename or directory
241 * @param Boolean $overwrite Whether to overwrite the target if it already exists
242 *
243 * @throws IOException When target file or directory already exists
244 * @throws IOException When origin cannot be renamed
245 */
246 public function rename($origin, $target, $overwrite = false)
247 {
248 // we check that target does not exist
249 if (!$overwrite && is_readable($target)) {
250 throw new IOException(sprintf('Cannot rename because the target "%s" already exist.', $target));
251 }
252
253 if (true !== @rename($origin, $target)) {
254 throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target));
255 }
256 }
257
258 /**
259 * Creates a symbolic link or copy a directory.
260 *
261 * @param string $originDir The origin directory path
262 * @param string $targetDir The symbolic link name
263 * @param Boolean $copyOnWindows Whether to copy files if on Windows
264 *
265 * @throws IOException When symlink fails
266 */
267 public function symlink($originDir, $targetDir, $copyOnWindows = false)
268 {
269 if (!function_exists('symlink') && $copyOnWindows) {
270 $this->mirror($originDir, $targetDir);
271
272 return;
273 }
274
275 $this->mkdir(dirname($targetDir));
276
277 $ok = false;
278 if (is_link($targetDir)) {
279 if (readlink($targetDir) != $originDir) {
280 $this->remove($targetDir);
281 } else {
282 $ok = true;
283 }
284 }
285
286 if (!$ok) {
287 if (true !== @symlink($originDir, $targetDir)) {
288 $report = error_get_last();
289 if (is_array($report)) {
290 if (defined('PHP_WINDOWS_VERSION_MAJOR') && false !== strpos($report['message'], 'error code(1314)')) {
291 throw new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?');
292 }
293 }
294 throw new IOException(sprintf('Failed to create symbolic link from %s to %s', $originDir, $targetDir));
295 }
296 }
297 }
298
299 /**
300 * Given an existing path, convert it to a path relative to a given starting path
301 *
302 * @param string $endPath Absolute path of target
303 * @param string $startPath Absolute path where traversal begins
304 *
305 * @return string Path of target relative to starting path
306 */
307 public function makePathRelative($endPath, $startPath)
308 {
309 // Normalize separators on windows
310 if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
311 $endPath = strtr($endPath, '\\', '/');
312 $startPath = strtr($startPath, '\\', '/');
313 }
314
315 // Split the paths into arrays
316 $startPathArr = explode('/', trim($startPath, '/'));
317 $endPathArr = explode('/', trim($endPath, '/'));
318
319 // Find for which directory the common path stops
320 $index = 0;
321 while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
322 $index++;
323 }
324
325 // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels)
326 $depth = count($startPathArr) - $index;
327
328 // Repeated "../" for each level need to reach the common path
329 $traverser = str_repeat('../', $depth);
330
331 $endPathRemainder = implode('/', array_slice($endPathArr, $index));
332
333 // Construct $endPath from traversing to the common path, then to the remaining $endPath
334 $relativePath = $traverser.(strlen($endPathRemainder) > 0 ? $endPathRemainder.'/' : '');
335
336 return (strlen($relativePath) === 0) ? './' : $relativePath;
337 }
338
339 /**
340 * Mirrors a directory to another.
341 *
342 * @param string $originDir The origin directory
343 * @param string $targetDir The target directory
344 * @param \Traversable $iterator A Traversable instance
345 * @param array $options An array of boolean options
346 * Valid options are:
347 * - $options['override'] Whether to override an existing file on copy or not (see copy())
348 * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink())
349 * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false)
350 *
351 * @throws IOException When file type is unknown
352 */
353 public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array())
354 {
355 $targetDir = rtrim($targetDir, '/\\');
356 $originDir = rtrim($originDir, '/\\');
357
358 // Iterate in destination folder to remove obsolete entries
359 if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
360 $deleteIterator = $iterator;
361 if (null === $deleteIterator) {
362 $flags = \FilesystemIterator::SKIP_DOTS;
363 $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
364 }
365 foreach ($deleteIterator as $file) {
366 $origin = str_replace($targetDir, $originDir, $file->getPathname());
367 if (!$this->exists($origin)) {
368 $this->remove($file);
369 }
370 }
371 }
372
373 $copyOnWindows = false;
374 if (isset($options['copy_on_windows']) && !function_exists('symlink')) {
375 $copyOnWindows = $options['copy_on_windows'];
376 }
377
378 if (null === $iterator) {
379 $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
380 $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
381 }
382
383 foreach ($iterator as $file) {
384 $target = str_replace($originDir, $targetDir, $file->getPathname());
385
386 if ($copyOnWindows) {
387 if (is_link($file) || is_file($file)) {
388 $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
389 } elseif (is_dir($file)) {
390 $this->mkdir($target);
391 } else {
392 throw new IOException(sprintf('Unable to guess "%s" file type.', $file));
393 }
394 } else {
395 if (is_link($file)) {
396 $this->symlink($file, $target);
397 } elseif (is_dir($file)) {
398 $this->mkdir($target);
399 } elseif (is_file($file)) {
400 $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
401 } else {
402 throw new IOException(sprintf('Unable to guess "%s" file type.', $file));
403 }
404 }
405 }
406 }
407
408 /**
409 * Returns whether the file path is an absolute path.
410 *
411 * @param string $file A file path
412 *
413 * @return Boolean
414 */
415 public function isAbsolutePath($file)
416 {
417 if (strspn($file, '/\\', 0, 1)
418 || (strlen($file) > 3 && ctype_alpha($file[0])
419 && substr($file, 1, 1) === ':'
420 && (strspn($file, '/\\', 2, 1))
421 )
422 || null !== parse_url($file, PHP_URL_SCHEME)
423 ) {
424 return true;
425 }
426
427 return false;
428 }
429
430 /**
431 * @param mixed $files
432 *
433 * @return \Traversable
434 */
435 private function toIterator($files)
436 {
437 if (!$files instanceof \Traversable) {
438 $files = new \ArrayObject(is_array($files) ? $files : array($files));
439 }
440
441 return $files;
442 }
443
444 /**
445 * Atomically dumps content into a file.
446 *
447 * @param string $filename The file to be written to.
448 * @param string $content The data to write into the file.
449 * @param integer $mode The file mode (octal).
450 * @throws IOException If the file cannot be written to.
451 */
452 public function dumpFile($filename, $content, $mode = 0666)
453 {
454 $dir = dirname($filename);
455
456 if (!is_dir($dir)) {
457 $this->mkdir($dir);
458 } elseif (!is_writable($dir)) {
459 throw new IOException(sprintf('Unable to write in the %s directory\n', $dir));
460 }
461
462 $tmpFile = tempnam($dir, basename($filename));
463
464 if (false === @file_put_contents($tmpFile, $content)) {
465 throw new IOException(sprintf('Failed to write file "%s".', $filename));
466 }
467
468 $this->rename($tmpFile, $filename, true);
469 $this->chmod($filename, $mode);
470 }
471}
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/LICENSE b/vendor/symfony/filesystem/Symfony/Component/Filesystem/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/README.md b/vendor/symfony/filesystem/Symfony/Component/Filesystem/README.md
new file mode 100644
index 00000000..94ac1469
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/README.md
@@ -0,0 +1,45 @@
1Filesystem Component
2====================
3
4Filesystem provides basic utility to manipulate the file system:
5
6```php
7<?php
8
9use Symfony\Component\Filesystem\Filesystem;
10
11$filesystem = new Filesystem();
12
13$filesystem->copy($originFile, $targetFile, $override = false);
14
15$filesystem->mkdir($dirs, $mode = 0777);
16
17$filesystem->touch($files, $time = null, $atime = null);
18
19$filesystem->remove($files);
20
21$filesystem->chmod($files, $mode, $umask = 0000, $recursive = false);
22
23$filesystem->chown($files, $user, $recursive = false);
24
25$filesystem->chgrp($files, $group, $recursive = false);
26
27$filesystem->rename($origin, $target);
28
29$filesystem->symlink($originDir, $targetDir, $copyOnWindows = false);
30
31$filesystem->makePathRelative($endPath, $startPath);
32
33$filesystem->mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array());
34
35$filesystem->isAbsolutePath($file);
36```
37
38Resources
39---------
40
41You can run the unit tests with the following command:
42
43 $ cd path/to/Symfony/Component/Filesystem/
44 $ composer.phar install --dev
45 $ phpunit
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/vendor/symfony/filesystem/Symfony/Component/Filesystem/Tests/FilesystemTest.php
new file mode 100644
index 00000000..02969f30
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/Tests/FilesystemTest.php
@@ -0,0 +1,982 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Filesystem\Tests;
13
14use Symfony\Component\Filesystem\Filesystem;
15
16/**
17 * Test class for Filesystem.
18 */
19class FilesystemTest extends \PHPUnit_Framework_TestCase
20{
21 /**
22 * @var string $workspace
23 */
24 private $workspace = null;
25
26 /**
27 * @var \Symfony\Component\Filesystem\Filesystem $filesystem
28 */
29 private $filesystem = null;
30
31 private static $symlinkOnWindows = null;
32
33 public static function setUpBeforeClass()
34 {
35 if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
36 self::$symlinkOnWindows = true;
37 $originDir = tempnam(sys_get_temp_dir(), 'sl');
38 $targetDir = tempnam(sys_get_temp_dir(), 'sl');
39 if (true !== @symlink($originDir, $targetDir)) {
40 $report = error_get_last();
41 if (is_array($report) && false !== strpos($report['message'], 'error code(1314)')) {
42 self::$symlinkOnWindows = false;
43 }
44 }
45 }
46 }
47
48 public function setUp()
49 {
50 $this->filesystem = new Filesystem();
51 $this->workspace = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.time().rand(0, 1000);
52 mkdir($this->workspace, 0777, true);
53 $this->workspace = realpath($this->workspace);
54 }
55
56 public function tearDown()
57 {
58 $this->clean($this->workspace);
59 }
60
61 /**
62 * @param string $file
63 */
64 private function clean($file)
65 {
66 if (is_dir($file) && !is_link($file)) {
67 $dir = new \FilesystemIterator($file);
68 foreach ($dir as $childFile) {
69 $this->clean($childFile);
70 }
71
72 rmdir($file);
73 } else {
74 unlink($file);
75 }
76 }
77
78 public function testCopyCreatesNewFile()
79 {
80 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
81 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
82
83 file_put_contents($sourceFilePath, 'SOURCE FILE');
84
85 $this->filesystem->copy($sourceFilePath, $targetFilePath);
86
87 $this->assertFileExists($targetFilePath);
88 $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
89 }
90
91 /**
92 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
93 */
94 public function testCopyFails()
95 {
96 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
97 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
98
99 $this->filesystem->copy($sourceFilePath, $targetFilePath);
100 }
101
102 public function testCopyOverridesExistingFileIfModified()
103 {
104 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
105 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
106
107 file_put_contents($sourceFilePath, 'SOURCE FILE');
108 file_put_contents($targetFilePath, 'TARGET FILE');
109 touch($targetFilePath, time() - 1000);
110
111 $this->filesystem->copy($sourceFilePath, $targetFilePath);
112
113 $this->assertFileExists($targetFilePath);
114 $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
115 }
116
117 public function testCopyDoesNotOverrideExistingFileByDefault()
118 {
119 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
120 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
121
122 file_put_contents($sourceFilePath, 'SOURCE FILE');
123 file_put_contents($targetFilePath, 'TARGET FILE');
124
125 // make sure both files have the same modification time
126 $modificationTime = time() - 1000;
127 touch($sourceFilePath, $modificationTime);
128 touch($targetFilePath, $modificationTime);
129
130 $this->filesystem->copy($sourceFilePath, $targetFilePath);
131
132 $this->assertFileExists($targetFilePath);
133 $this->assertEquals('TARGET FILE', file_get_contents($targetFilePath));
134 }
135
136 public function testCopyOverridesExistingFileIfForced()
137 {
138 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
139 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
140
141 file_put_contents($sourceFilePath, 'SOURCE FILE');
142 file_put_contents($targetFilePath, 'TARGET FILE');
143
144 // make sure both files have the same modification time
145 $modificationTime = time() - 1000;
146 touch($sourceFilePath, $modificationTime);
147 touch($targetFilePath, $modificationTime);
148
149 $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
150
151 $this->assertFileExists($targetFilePath);
152 $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
153 }
154
155 public function testCopyCreatesTargetDirectoryIfItDoesNotExist()
156 {
157 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
158 $targetFileDirectory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
159 $targetFilePath = $targetFileDirectory.DIRECTORY_SEPARATOR.'copy_target_file';
160
161 file_put_contents($sourceFilePath, 'SOURCE FILE');
162
163 $this->filesystem->copy($sourceFilePath, $targetFilePath);
164
165 $this->assertTrue(is_dir($targetFileDirectory));
166 $this->assertFileExists($targetFilePath);
167 $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
168 }
169
170 public function testMkdirCreatesDirectoriesRecursively()
171 {
172 $directory = $this->workspace
173 .DIRECTORY_SEPARATOR.'directory'
174 .DIRECTORY_SEPARATOR.'sub_directory';
175
176 $this->filesystem->mkdir($directory);
177
178 $this->assertTrue(is_dir($directory));
179 }
180
181 public function testMkdirCreatesDirectoriesFromArray()
182 {
183 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
184 $directories = array(
185 $basePath.'1', $basePath.'2', $basePath.'3'
186 );
187
188 $this->filesystem->mkdir($directories);
189
190 $this->assertTrue(is_dir($basePath.'1'));
191 $this->assertTrue(is_dir($basePath.'2'));
192 $this->assertTrue(is_dir($basePath.'3'));
193 }
194
195 public function testMkdirCreatesDirectoriesFromTraversableObject()
196 {
197 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
198 $directories = new \ArrayObject(array(
199 $basePath.'1', $basePath.'2', $basePath.'3'
200 ));
201
202 $this->filesystem->mkdir($directories);
203
204 $this->assertTrue(is_dir($basePath.'1'));
205 $this->assertTrue(is_dir($basePath.'2'));
206 $this->assertTrue(is_dir($basePath.'3'));
207 }
208
209 /**
210 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
211 */
212 public function testMkdirCreatesDirectoriesFails()
213 {
214 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
215 $dir = $basePath.'2';
216
217 file_put_contents($dir, '');
218
219 $this->filesystem->mkdir($dir);
220 }
221
222 public function testTouchCreatesEmptyFile()
223 {
224 $file = $this->workspace.DIRECTORY_SEPARATOR.'1';
225
226 $this->filesystem->touch($file);
227
228 $this->assertFileExists($file);
229 }
230
231 /**
232 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
233 */
234 public function testTouchFails()
235 {
236 $file = $this->workspace.DIRECTORY_SEPARATOR.'1'.DIRECTORY_SEPARATOR.'2';
237
238 $this->filesystem->touch($file);
239 }
240
241 public function testTouchCreatesEmptyFilesFromArray()
242 {
243 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
244 $files = array(
245 $basePath.'1', $basePath.'2', $basePath.'3'
246 );
247
248 $this->filesystem->touch($files);
249
250 $this->assertFileExists($basePath.'1');
251 $this->assertFileExists($basePath.'2');
252 $this->assertFileExists($basePath.'3');
253 }
254
255 public function testTouchCreatesEmptyFilesFromTraversableObject()
256 {
257 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
258 $files = new \ArrayObject(array(
259 $basePath.'1', $basePath.'2', $basePath.'3'
260 ));
261
262 $this->filesystem->touch($files);
263
264 $this->assertFileExists($basePath.'1');
265 $this->assertFileExists($basePath.'2');
266 $this->assertFileExists($basePath.'3');
267 }
268
269 public function testRemoveCleansFilesAndDirectoriesIteratively()
270 {
271 $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
272
273 mkdir($basePath);
274 mkdir($basePath.'dir');
275 touch($basePath.'file');
276
277 $this->filesystem->remove($basePath);
278
279 $this->assertTrue(!is_dir($basePath));
280 }
281
282 public function testRemoveCleansArrayOfFilesAndDirectories()
283 {
284 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
285
286 mkdir($basePath.'dir');
287 touch($basePath.'file');
288
289 $files = array(
290 $basePath.'dir', $basePath.'file'
291 );
292
293 $this->filesystem->remove($files);
294
295 $this->assertTrue(!is_dir($basePath.'dir'));
296 $this->assertTrue(!is_file($basePath.'file'));
297 }
298
299 public function testRemoveCleansTraversableObjectOfFilesAndDirectories()
300 {
301 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
302
303 mkdir($basePath.'dir');
304 touch($basePath.'file');
305
306 $files = new \ArrayObject(array(
307 $basePath.'dir', $basePath.'file'
308 ));
309
310 $this->filesystem->remove($files);
311
312 $this->assertTrue(!is_dir($basePath.'dir'));
313 $this->assertTrue(!is_file($basePath.'file'));
314 }
315
316 public function testRemoveIgnoresNonExistingFiles()
317 {
318 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
319
320 mkdir($basePath.'dir');
321
322 $files = array(
323 $basePath.'dir', $basePath.'file'
324 );
325
326 $this->filesystem->remove($files);
327
328 $this->assertTrue(!is_dir($basePath.'dir'));
329 }
330
331 public function testRemoveCleansInvalidLinks()
332 {
333 $this->markAsSkippedIfSymlinkIsMissing();
334
335 $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
336
337 mkdir($basePath);
338 mkdir($basePath.'dir');
339 // create symlink to unexisting file
340 @symlink($basePath.'file', $basePath.'link');
341
342 $this->filesystem->remove($basePath);
343
344 $this->assertTrue(!is_dir($basePath));
345 }
346
347 public function testFilesExists()
348 {
349 $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
350
351 mkdir($basePath);
352 touch($basePath.'file1');
353 mkdir($basePath.'folder');
354
355 $this->assertTrue($this->filesystem->exists($basePath.'file1'));
356 $this->assertTrue($this->filesystem->exists($basePath.'folder'));
357 }
358
359 public function testFilesExistsTraversableObjectOfFilesAndDirectories()
360 {
361 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
362
363 mkdir($basePath.'dir');
364 touch($basePath.'file');
365
366 $files = new \ArrayObject(array(
367 $basePath.'dir', $basePath.'file'
368 ));
369
370 $this->assertTrue($this->filesystem->exists($files));
371 }
372
373 public function testFilesNotExistsTraversableObjectOfFilesAndDirectories()
374 {
375 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
376
377 mkdir($basePath.'dir');
378 touch($basePath.'file');
379 touch($basePath.'file2');
380
381 $files = new \ArrayObject(array(
382 $basePath.'dir', $basePath.'file', $basePath.'file2'
383 ));
384
385 unlink($basePath.'file');
386
387 $this->assertFalse($this->filesystem->exists($files));
388 }
389
390 public function testInvalidFileNotExists()
391 {
392 $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
393
394 $this->assertFalse($this->filesystem->exists($basePath.time()));
395 }
396
397 public function testChmodChangesFileMode()
398 {
399 $this->markAsSkippedIfChmodIsMissing();
400
401 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
402 mkdir($dir);
403 $file = $dir.DIRECTORY_SEPARATOR.'file';
404 touch($file);
405
406 $this->filesystem->chmod($file, 0400);
407 $this->filesystem->chmod($dir, 0753);
408
409 $this->assertEquals(753, $this->getFilePermissions($dir));
410 $this->assertEquals(400, $this->getFilePermissions($file));
411 }
412
413 public function testChmodWrongMod()
414 {
415 $this->markAsSkippedIfChmodIsMissing();
416
417 $dir = $this->workspace.DIRECTORY_SEPARATOR.'file';
418 touch($dir);
419
420 $this->filesystem->chmod($dir, 'Wrongmode');
421 }
422
423 public function testChmodRecursive()
424 {
425 $this->markAsSkippedIfChmodIsMissing();
426
427 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
428 mkdir($dir);
429 $file = $dir.DIRECTORY_SEPARATOR.'file';
430 touch($file);
431
432 $this->filesystem->chmod($file, 0400, 0000, true);
433 $this->filesystem->chmod($dir, 0753, 0000, true);
434
435 $this->assertEquals(753, $this->getFilePermissions($dir));
436 $this->assertEquals(753, $this->getFilePermissions($file));
437 }
438
439 public function testChmodAppliesUmask()
440 {
441 $this->markAsSkippedIfChmodIsMissing();
442
443 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
444 touch($file);
445
446 $this->filesystem->chmod($file, 0770, 0022);
447 $this->assertEquals(750, $this->getFilePermissions($file));
448 }
449
450 public function testChmodChangesModeOfArrayOfFiles()
451 {
452 $this->markAsSkippedIfChmodIsMissing();
453
454 $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
455 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
456 $files = array($directory, $file);
457
458 mkdir($directory);
459 touch($file);
460
461 $this->filesystem->chmod($files, 0753);
462
463 $this->assertEquals(753, $this->getFilePermissions($file));
464 $this->assertEquals(753, $this->getFilePermissions($directory));
465 }
466
467 public function testChmodChangesModeOfTraversableFileObject()
468 {
469 $this->markAsSkippedIfChmodIsMissing();
470
471 $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
472 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
473 $files = new \ArrayObject(array($directory, $file));
474
475 mkdir($directory);
476 touch($file);
477
478 $this->filesystem->chmod($files, 0753);
479
480 $this->assertEquals(753, $this->getFilePermissions($file));
481 $this->assertEquals(753, $this->getFilePermissions($directory));
482 }
483
484 public function testChown()
485 {
486 $this->markAsSkippedIfPosixIsMissing();
487
488 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
489 mkdir($dir);
490
491 $this->filesystem->chown($dir, $this->getFileOwner($dir));
492 }
493
494 public function testChownRecursive()
495 {
496 $this->markAsSkippedIfPosixIsMissing();
497
498 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
499 mkdir($dir);
500 $file = $dir.DIRECTORY_SEPARATOR.'file';
501 touch($file);
502
503 $this->filesystem->chown($dir, $this->getFileOwner($dir), true);
504 }
505
506 public function testChownSymlink()
507 {
508 $this->markAsSkippedIfSymlinkIsMissing();
509
510 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
511 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
512
513 touch($file);
514
515 $this->filesystem->symlink($file, $link);
516
517 $this->filesystem->chown($link, $this->getFileOwner($link));
518 }
519
520 /**
521 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
522 */
523 public function testChownSymlinkFails()
524 {
525 $this->markAsSkippedIfSymlinkIsMissing();
526
527 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
528 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
529
530 touch($file);
531
532 $this->filesystem->symlink($file, $link);
533
534 $this->filesystem->chown($link, 'user'.time().mt_rand(1000, 9999));
535 }
536
537 /**
538 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
539 */
540 public function testChownFail()
541 {
542 $this->markAsSkippedIfPosixIsMissing();
543
544 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
545 mkdir($dir);
546
547 $this->filesystem->chown($dir, 'user'.time().mt_rand(1000, 9999));
548 }
549
550 public function testChgrp()
551 {
552 $this->markAsSkippedIfPosixIsMissing();
553
554 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
555 mkdir($dir);
556
557 $this->filesystem->chgrp($dir, $this->getFileGroup($dir));
558 }
559
560 public function testChgrpRecursive()
561 {
562 $this->markAsSkippedIfPosixIsMissing();
563
564 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
565 mkdir($dir);
566 $file = $dir.DIRECTORY_SEPARATOR.'file';
567 touch($file);
568
569 $this->filesystem->chgrp($dir, $this->getFileGroup($dir), true);
570 }
571
572 public function testChgrpSymlink()
573 {
574 $this->markAsSkippedIfSymlinkIsMissing();
575
576 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
577 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
578
579 touch($file);
580
581 $this->filesystem->symlink($file, $link);
582
583 $this->filesystem->chgrp($link, $this->getFileGroup($link));
584 }
585
586 /**
587 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
588 */
589 public function testChgrpSymlinkFails()
590 {
591 $this->markAsSkippedIfSymlinkIsMissing();
592
593 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
594 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
595
596 touch($file);
597
598 $this->filesystem->symlink($file, $link);
599
600 $this->filesystem->chgrp($link, 'user'.time().mt_rand(1000, 9999));
601 }
602
603 /**
604 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
605 */
606 public function testChgrpFail()
607 {
608 $this->markAsSkippedIfPosixIsMissing();
609
610 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
611 mkdir($dir);
612
613 $this->filesystem->chgrp($dir, 'user'.time().mt_rand(1000, 9999));
614 }
615
616 public function testRename()
617 {
618 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
619 $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
620 touch($file);
621
622 $this->filesystem->rename($file, $newPath);
623
624 $this->assertFileNotExists($file);
625 $this->assertFileExists($newPath);
626 }
627
628 /**
629 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
630 */
631 public function testRenameThrowsExceptionIfTargetAlreadyExists()
632 {
633 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
634 $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
635
636 touch($file);
637 touch($newPath);
638
639 $this->filesystem->rename($file, $newPath);
640 }
641
642 public function testRenameOverwritesTheTargetIfItAlreadyExists()
643 {
644 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
645 $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
646
647 touch($file);
648 touch($newPath);
649
650 $this->filesystem->rename($file, $newPath, true);
651
652 $this->assertFileNotExists($file);
653 $this->assertFileExists($newPath);
654 }
655
656 /**
657 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
658 */
659 public function testRenameThrowsExceptionOnError()
660 {
661 $file = $this->workspace.DIRECTORY_SEPARATOR.uniqid();
662 $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
663
664 $this->filesystem->rename($file, $newPath);
665 }
666
667 public function testSymlink()
668 {
669 $this->markAsSkippedIfSymlinkIsMissing();
670
671 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
672 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
673
674 touch($file);
675
676 $this->filesystem->symlink($file, $link);
677
678 $this->assertTrue(is_link($link));
679 $this->assertEquals($file, readlink($link));
680 }
681
682 /**
683 * @depends testSymlink
684 */
685 public function testRemoveSymlink()
686 {
687 $this->markAsSkippedIfSymlinkIsMissing();
688
689 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
690
691 $this->filesystem->remove($link);
692
693 $this->assertTrue(!is_link($link));
694 }
695
696 public function testSymlinkIsOverwrittenIfPointsToDifferentTarget()
697 {
698 $this->markAsSkippedIfSymlinkIsMissing();
699
700 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
701 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
702
703 touch($file);
704 symlink($this->workspace, $link);
705
706 $this->filesystem->symlink($file, $link);
707
708 $this->assertTrue(is_link($link));
709 $this->assertEquals($file, readlink($link));
710 }
711
712 public function testSymlinkIsNotOverwrittenIfAlreadyCreated()
713 {
714 $this->markAsSkippedIfSymlinkIsMissing();
715
716 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
717 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
718
719 touch($file);
720 symlink($file, $link);
721
722 $this->filesystem->symlink($file, $link);
723
724 $this->assertTrue(is_link($link));
725 $this->assertEquals($file, readlink($link));
726 }
727
728 public function testSymlinkCreatesTargetDirectoryIfItDoesNotExist()
729 {
730 $this->markAsSkippedIfSymlinkIsMissing();
731
732 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
733 $link1 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'link';
734 $link2 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'subdir'.DIRECTORY_SEPARATOR.'link';
735
736 touch($file);
737
738 $this->filesystem->symlink($file, $link1);
739 $this->filesystem->symlink($file, $link2);
740
741 $this->assertTrue(is_link($link1));
742 $this->assertEquals($file, readlink($link1));
743 $this->assertTrue(is_link($link2));
744 $this->assertEquals($file, readlink($link2));
745 }
746
747 /**
748 * @dataProvider providePathsForMakePathRelative
749 */
750 public function testMakePathRelative($endPath, $startPath, $expectedPath)
751 {
752 $path = $this->filesystem->makePathRelative($endPath, $startPath);
753
754 $this->assertEquals($expectedPath, $path);
755 }
756
757 /**
758 * @return array
759 */
760 public function providePathsForMakePathRelative()
761 {
762 $paths = array(
763 array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component', '../'),
764 array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component/', '../'),
765 array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component', '../'),
766 array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component/', '../'),
767 array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'),
768 array('/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'),
769 array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'),
770 array('/aa/bb', '/aa/bb', './'),
771 array('/aa/bb', '/aa/bb/', './'),
772 array('/aa/bb/', '/aa/bb', './'),
773 array('/aa/bb/', '/aa/bb/', './'),
774 array('/aa/bb/cc', '/aa/bb/cc/dd', '../'),
775 array('/aa/bb/cc', '/aa/bb/cc/dd/', '../'),
776 array('/aa/bb/cc/', '/aa/bb/cc/dd', '../'),
777 array('/aa/bb/cc/', '/aa/bb/cc/dd/', '../'),
778 array('/aa/bb/cc', '/aa', 'bb/cc/'),
779 array('/aa/bb/cc', '/aa/', 'bb/cc/'),
780 array('/aa/bb/cc/', '/aa', 'bb/cc/'),
781 array('/aa/bb/cc/', '/aa/', 'bb/cc/'),
782 array('/a/aab/bb', '/a/aa', '../aab/bb/'),
783 array('/a/aab/bb', '/a/aa/', '../aab/bb/'),
784 array('/a/aab/bb/', '/a/aa', '../aab/bb/'),
785 array('/a/aab/bb/', '/a/aa/', '../aab/bb/'),
786 );
787
788 if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
789 $paths[] = array('c:\var\lib/symfony/src/Symfony/', 'c:/var/lib/symfony/', 'src/Symfony/');
790 }
791
792 return $paths;
793 }
794
795 public function testMirrorCopiesFilesAndDirectoriesRecursively()
796 {
797 $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
798 $directory = $sourcePath.'directory'.DIRECTORY_SEPARATOR;
799 $file1 = $directory.'file1';
800 $file2 = $sourcePath.'file2';
801
802 mkdir($sourcePath);
803 mkdir($directory);
804 file_put_contents($file1, 'FILE1');
805 file_put_contents($file2, 'FILE2');
806
807 $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
808
809 $this->filesystem->mirror($sourcePath, $targetPath);
810
811 $this->assertTrue(is_dir($targetPath));
812 $this->assertTrue(is_dir($targetPath.'directory'));
813 $this->assertFileEquals($file1, $targetPath.'directory'.DIRECTORY_SEPARATOR.'file1');
814 $this->assertFileEquals($file2, $targetPath.'file2');
815
816 $this->filesystem->remove($file1);
817
818 $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => false));
819 $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
820
821 $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
822 $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
823
824 file_put_contents($file1, 'FILE1');
825
826 $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
827 $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
828
829 $this->filesystem->remove($directory);
830 $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
831 $this->assertFalse($this->filesystem->exists($targetPath.'directory'));
832 $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
833 }
834
835 public function testMirrorCopiesLinks()
836 {
837 $this->markAsSkippedIfSymlinkIsMissing();
838
839 $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
840
841 mkdir($sourcePath);
842 file_put_contents($sourcePath.'file1', 'FILE1');
843 symlink($sourcePath.'file1', $sourcePath.'link1');
844
845 $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
846
847 $this->filesystem->mirror($sourcePath, $targetPath);
848
849 $this->assertTrue(is_dir($targetPath));
850 $this->assertFileEquals($sourcePath.'file1', $targetPath.DIRECTORY_SEPARATOR.'link1');
851 $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
852 }
853
854 public function testMirrorCopiesLinkedDirectoryContents()
855 {
856 $this->markAsSkippedIfSymlinkIsMissing();
857
858 $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
859
860 mkdir($sourcePath.'nested/', 0777, true);
861 file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
862 // Note: We symlink directory, not file
863 symlink($sourcePath.'nested', $sourcePath.'link1');
864
865 $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
866
867 $this->filesystem->mirror($sourcePath, $targetPath);
868
869 $this->assertTrue(is_dir($targetPath));
870 $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.DIRECTORY_SEPARATOR.'link1/file1.txt');
871 $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
872 }
873
874 /**
875 * @dataProvider providePathsForIsAbsolutePath
876 */
877 public function testIsAbsolutePath($path, $expectedResult)
878 {
879 $result = $this->filesystem->isAbsolutePath($path);
880
881 $this->assertEquals($expectedResult, $result);
882 }
883
884 /**
885 * @return array
886 */
887 public function providePathsForIsAbsolutePath()
888 {
889 return array(
890 array('/var/lib', true),
891 array('c:\\\\var\\lib', true),
892 array('\\var\\lib', true),
893 array('var/lib', false),
894 array('../var/lib', false),
895 array('', false),
896 array(null, false)
897 );
898 }
899
900 public function testDumpFile()
901 {
902 $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
903
904 $this->filesystem->dumpFile($filename, 'bar', 0753);
905
906 $this->assertFileExists($filename);
907 $this->assertSame('bar', file_get_contents($filename));
908
909 // skip mode check on windows
910 if (!defined('PHP_WINDOWS_VERSION_MAJOR')) {
911 $this->assertEquals(753, $this->getFilePermissions($filename));
912 }
913 }
914
915 public function testDumpFileOverwritesAnExistingFile()
916 {
917 $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo.txt';
918 file_put_contents($filename, 'FOO BAR');
919
920 $this->filesystem->dumpFile($filename, 'bar');
921
922 $this->assertFileExists($filename);
923 $this->assertSame('bar', file_get_contents($filename));
924 }
925
926 /**
927 * Returns file permissions as three digits (i.e. 755)
928 *
929 * @param string $filePath
930 *
931 * @return integer
932 */
933 private function getFilePermissions($filePath)
934 {
935 return (int) substr(sprintf('%o', fileperms($filePath)), -3);
936 }
937
938 private function getFileOwner($filepath)
939 {
940 $this->markAsSkippedIfPosixIsMissing();
941
942 $infos = stat($filepath);
943 if ($datas = posix_getpwuid($infos['uid'])) {
944 return $datas['name'];
945 }
946 }
947
948 private function getFileGroup($filepath)
949 {
950 $this->markAsSkippedIfPosixIsMissing();
951
952 $infos = stat($filepath);
953 if ($datas = posix_getgrgid($infos['gid'])) {
954 return $datas['name'];
955 }
956 }
957
958 private function markAsSkippedIfSymlinkIsMissing()
959 {
960 if (!function_exists('symlink')) {
961 $this->markTestSkipped('symlink is not supported');
962 }
963
964 if (defined('PHP_WINDOWS_VERSION_MAJOR') && false === self::$symlinkOnWindows) {
965 $this->markTestSkipped('symlink requires "Create symbolic links" privilege on windows');
966 }
967 }
968
969 private function markAsSkippedIfChmodIsMissing()
970 {
971 if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
972 $this->markTestSkipped('chmod is not supported on windows');
973 }
974 }
975
976 private function markAsSkippedIfPosixIsMissing()
977 {
978 if (defined('PHP_WINDOWS_VERSION_MAJOR') || !function_exists('posix_isatty')) {
979 $this->markTestSkipped('Posix is not supported');
980 }
981 }
982}
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/composer.json b/vendor/symfony/filesystem/Symfony/Component/Filesystem/composer.json
new file mode 100644
index 00000000..167dd506
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/composer.json
@@ -0,0 +1,31 @@
1{
2 "name": "symfony/filesystem",
3 "type": "library",
4 "description": "Symfony Filesystem Component",
5 "keywords": [],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3"
20 },
21 "autoload": {
22 "psr-0": { "Symfony\\Component\\Filesystem\\": "" }
23 },
24 "target-dir": "Symfony/Component/Filesystem",
25 "minimum-stability": "dev",
26 "extra": {
27 "branch-alias": {
28 "dev-master": "2.3-dev"
29 }
30 }
31}
diff --git a/vendor/symfony/filesystem/Symfony/Component/Filesystem/phpunit.xml.dist b/vendor/symfony/filesystem/Symfony/Component/Filesystem/phpunit.xml.dist
new file mode 100644
index 00000000..ef0bf954
--- /dev/null
+++ b/vendor/symfony/filesystem/Symfony/Component/Filesystem/phpunit.xml.dist
@@ -0,0 +1,28 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony Filesystem Component Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./Tests</directory>
25 </exclude>
26 </whitelist>
27 </filter>
28</phpunit>
diff --git a/vendor/symfony/form/Symfony/Component/Form/.gitignore b/vendor/symfony/form/Symfony/Component/Form/.gitignore
new file mode 100644
index 00000000..44de97a3
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/.gitignore
@@ -0,0 +1,4 @@
1vendor/
2composer.lock
3phpunit.xml
4
diff --git a/vendor/symfony/form/Symfony/Component/Form/AbstractExtension.php b/vendor/symfony/form/Symfony/Component/Form/AbstractExtension.php
new file mode 100644
index 00000000..4db77b9b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/AbstractExtension.php
@@ -0,0 +1,195 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\InvalidArgumentException;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20abstract class AbstractExtension implements FormExtensionInterface
21{
22 /**
23 * The types provided by this extension
24 * @var FormTypeInterface[] An array of FormTypeInterface
25 */
26 private $types;
27
28 /**
29 * The type extensions provided by this extension
30 * @var FormTypeExtensionInterface[] An array of FormTypeExtensionInterface
31 */
32 private $typeExtensions;
33
34 /**
35 * The type guesser provided by this extension
36 * @var FormTypeGuesserInterface
37 */
38 private $typeGuesser;
39
40 /**
41 * Whether the type guesser has been loaded
42 * @var Boolean
43 */
44 private $typeGuesserLoaded = false;
45
46 /**
47 * {@inheritdoc}
48 */
49 public function getType($name)
50 {
51 if (null === $this->types) {
52 $this->initTypes();
53 }
54
55 if (!isset($this->types[$name])) {
56 throw new InvalidArgumentException(sprintf('The type "%s" can not be loaded by this extension', $name));
57 }
58
59 return $this->types[$name];
60 }
61
62 /**
63 * {@inheritdoc}
64 */
65 public function hasType($name)
66 {
67 if (null === $this->types) {
68 $this->initTypes();
69 }
70
71 return isset($this->types[$name]);
72 }
73
74 /**
75 * {@inheritdoc}
76 */
77 public function getTypeExtensions($name)
78 {
79 if (null === $this->typeExtensions) {
80 $this->initTypeExtensions();
81 }
82
83 return isset($this->typeExtensions[$name])
84 ? $this->typeExtensions[$name]
85 : array();
86 }
87
88 /**
89 * {@inheritdoc}
90 */
91 public function hasTypeExtensions($name)
92 {
93 if (null === $this->typeExtensions) {
94 $this->initTypeExtensions();
95 }
96
97 return isset($this->typeExtensions[$name]) && count($this->typeExtensions[$name]) > 0;
98 }
99
100 /**
101 * {@inheritdoc}
102 */
103 public function getTypeGuesser()
104 {
105 if (!$this->typeGuesserLoaded) {
106 $this->initTypeGuesser();
107 }
108
109 return $this->typeGuesser;
110 }
111
112 /**
113 * Registers the types.
114 *
115 * @return FormTypeInterface[] An array of FormTypeInterface instances
116 */
117 protected function loadTypes()
118 {
119 return array();
120 }
121
122 /**
123 * Registers the type extensions.
124 *
125 * @return FormTypeExtensionInterface[] An array of FormTypeExtensionInterface instances
126 */
127 protected function loadTypeExtensions()
128 {
129 return array();
130 }
131
132 /**
133 * Registers the type guesser.
134 *
135 * @return FormTypeGuesserInterface|null A type guesser
136 */
137 protected function loadTypeGuesser()
138 {
139 return null;
140 }
141
142 /**
143 * Initializes the types.
144 *
145 * @throws UnexpectedTypeException if any registered type is not an instance of FormTypeInterface
146 */
147 private function initTypes()
148 {
149 $this->types = array();
150
151 foreach ($this->loadTypes() as $type) {
152 if (!$type instanceof FormTypeInterface) {
153 throw new UnexpectedTypeException($type, 'Symfony\Component\Form\FormTypeInterface');
154 }
155
156 $this->types[$type->getName()] = $type;
157 }
158 }
159
160 /**
161 * Initializes the type extensions.
162 *
163 * @throws UnexpectedTypeException if any registered type extension is not
164 * an instance of FormTypeExtensionInterface
165 */
166 private function initTypeExtensions()
167 {
168 $this->typeExtensions = array();
169
170 foreach ($this->loadTypeExtensions() as $extension) {
171 if (!$extension instanceof FormTypeExtensionInterface) {
172 throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface');
173 }
174
175 $type = $extension->getExtendedType();
176
177 $this->typeExtensions[$type][] = $extension;
178 }
179 }
180
181 /**
182 * Initializes the type guesser.
183 *
184 * @throws UnexpectedTypeException if the type guesser is not an instance of FormTypeGuesserInterface
185 */
186 private function initTypeGuesser()
187 {
188 $this->typeGuesserLoaded = true;
189
190 $this->typeGuesser = $this->loadTypeGuesser();
191 if (null !== $this->typeGuesser && !$this->typeGuesser instanceof FormTypeGuesserInterface) {
192 throw new UnexpectedTypeException($this->typeGuesser, 'Symfony\Component\Form\FormTypeGuesserInterface');
193 }
194 }
195}
diff --git a/vendor/symfony/form/Symfony/Component/Form/AbstractRendererEngine.php b/vendor/symfony/form/Symfony/Component/Form/AbstractRendererEngine.php
new file mode 100644
index 00000000..347be10d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/AbstractRendererEngine.php
@@ -0,0 +1,206 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * Default implementation of {@link FormRendererEngineInterface}.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19abstract class AbstractRendererEngine implements FormRendererEngineInterface
20{
21 /**
22 * The variable in {@link FormView} used as cache key.
23 */
24 const CACHE_KEY_VAR = 'cache_key';
25
26 /**
27 * @var array
28 */
29 protected $defaultThemes;
30
31 /**
32 * @var array
33 */
34 protected $themes = array();
35
36 /**
37 * @var array
38 */
39 protected $resources = array();
40
41 /**
42 * @var array
43 */
44 private $resourceHierarchyLevels = array();
45
46 /**
47 * Creates a new renderer engine.
48 *
49 * @param array $defaultThemes The default themes. The type of these
50 * themes is open to the implementation.
51 */
52 public function __construct(array $defaultThemes = array())
53 {
54 $this->defaultThemes = $defaultThemes;
55 }
56
57 /**
58 * {@inheritdoc}
59 */
60 public function setTheme(FormView $view, $themes)
61 {
62 $cacheKey = $view->vars[self::CACHE_KEY_VAR];
63
64 // Do not cast, as casting turns objects into arrays of properties
65 $this->themes[$cacheKey] = is_array($themes) ? $themes : array($themes);
66
67 // Unset instead of resetting to an empty array, in order to allow
68 // implementations (like TwigRendererEngine) to check whether $cacheKey
69 // is set at all.
70 unset($this->resources[$cacheKey]);
71 unset($this->resourceHierarchyLevels[$cacheKey]);
72 }
73
74 /**
75 * {@inheritdoc}
76 */
77 public function getResourceForBlockName(FormView $view, $blockName)
78 {
79 $cacheKey = $view->vars[self::CACHE_KEY_VAR];
80
81 if (!isset($this->resources[$cacheKey][$blockName])) {
82 $this->loadResourceForBlockName($cacheKey, $view, $blockName);
83 }
84
85 return $this->resources[$cacheKey][$blockName];
86 }
87
88 /**
89 * {@inheritdoc}
90 */
91 public function getResourceForBlockNameHierarchy(FormView $view, array $blockNameHierarchy, $hierarchyLevel)
92 {
93 $cacheKey = $view->vars[self::CACHE_KEY_VAR];
94 $blockName = $blockNameHierarchy[$hierarchyLevel];
95
96 if (!isset($this->resources[$cacheKey][$blockName])) {
97 $this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $hierarchyLevel);
98 }
99
100 return $this->resources[$cacheKey][$blockName];
101 }
102
103 /**
104 * {@inheritdoc}
105 */
106 public function getResourceHierarchyLevel(FormView $view, array $blockNameHierarchy, $hierarchyLevel)
107 {
108 $cacheKey = $view->vars[self::CACHE_KEY_VAR];
109 $blockName = $blockNameHierarchy[$hierarchyLevel];
110
111 if (!isset($this->resources[$cacheKey][$blockName])) {
112 $this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $hierarchyLevel);
113 }
114
115 // If $block was previously rendered loaded with loadTemplateForBlock(), the template
116 // is cached but the hierarchy level is not. In this case, we know that the block
117 // exists at this very hierarchy level, so we can just set it.
118 if (!isset($this->resourceHierarchyLevels[$cacheKey][$blockName])) {
119 $this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel;
120 }
121
122 return $this->resourceHierarchyLevels[$cacheKey][$blockName];
123 }
124
125 /**
126 * Loads the cache with the resource for a given block name.
127 *
128 * @see getResourceForBlock()
129 *
130 * @param string $cacheKey The cache key of the form view.
131 * @param FormView $view The form view for finding the applying themes.
132 * @param string $blockName The name of the block to load.
133 *
134 * @return Boolean True if the resource could be loaded, false otherwise.
135 */
136 abstract protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName);
137
138 /**
139 * Loads the cache with the resource for a specific level of a block hierarchy.
140 *
141 * @see getResourceForBlockHierarchy()
142 *
143 * @param string $cacheKey The cache key used for storing the
144 * resource.
145 * @param FormView $view The form view for finding the applying
146 * themes.
147 * @param array $blockNameHierarchy The block hierarchy, with the most
148 * specific block name at the end.
149 * @param integer $hierarchyLevel The level in the block hierarchy that
150 * should be loaded.
151 *
152 * @return Boolean True if the resource could be loaded, false otherwise.
153 */
154 private function loadResourceForBlockNameHierarchy($cacheKey, FormView $view, array $blockNameHierarchy, $hierarchyLevel)
155 {
156 $blockName = $blockNameHierarchy[$hierarchyLevel];
157
158 // Try to find a template for that block
159 if ($this->loadResourceForBlockName($cacheKey, $view, $blockName)) {
160 // If loadTemplateForBlock() returns true, it was able to populate the
161 // cache. The only missing thing is to set the hierarchy level at which
162 // the template was found.
163 $this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel;
164
165 return true;
166 }
167
168 if ($hierarchyLevel > 0) {
169 $parentLevel = $hierarchyLevel - 1;
170 $parentBlockName = $blockNameHierarchy[$parentLevel];
171
172 // The next two if statements contain slightly duplicated code. This is by intention
173 // and tries to avoid execution of unnecessary checks in order to increase performance.
174
175 if (isset($this->resources[$cacheKey][$parentBlockName])) {
176 // It may happen that the parent block is already loaded, but its level is not.
177 // In this case, the parent block must have been loaded by loadResourceForBlock(),
178 // which does not check the hierarchy of the block. Subsequently the block must have
179 // been found directly on the parent level.
180 if (!isset($this->resourceHierarchyLevels[$cacheKey][$parentBlockName])) {
181 $this->resourceHierarchyLevels[$cacheKey][$parentBlockName] = $parentLevel;
182 }
183
184 // Cache the shortcuts for further accesses
185 $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName];
186 $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName];
187
188 return true;
189 }
190
191 if ($this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $parentLevel)) {
192 // Cache the shortcuts for further accesses
193 $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName];
194 $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName];
195
196 return true;
197 }
198 }
199
200 // Cache the result for further accesses
201 $this->resources[$cacheKey][$blockName] = false;
202 $this->resourceHierarchyLevels[$cacheKey][$blockName] = false;
203
204 return false;
205 }
206}
diff --git a/vendor/symfony/form/Symfony/Component/Form/AbstractType.php b/vendor/symfony/form/Symfony/Component/Form/AbstractType.php
new file mode 100644
index 00000000..6f7f5da6
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/AbstractType.php
@@ -0,0 +1,56 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\OptionsResolver\OptionsResolverInterface;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19abstract class AbstractType implements FormTypeInterface
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 }
27
28 /**
29 * {@inheritdoc}
30 */
31 public function buildView(FormView $view, FormInterface $form, array $options)
32 {
33 }
34
35 /**
36 * {@inheritdoc}
37 */
38 public function finishView(FormView $view, FormInterface $form, array $options)
39 {
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function setDefaultOptions(OptionsResolverInterface $resolver)
46 {
47 }
48
49 /**
50 * {@inheritdoc}
51 */
52 public function getParent()
53 {
54 return 'form';
55 }
56}
diff --git a/vendor/symfony/form/Symfony/Component/Form/AbstractTypeExtension.php b/vendor/symfony/form/Symfony/Component/Form/AbstractTypeExtension.php
new file mode 100644
index 00000000..351c8009
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/AbstractTypeExtension.php
@@ -0,0 +1,48 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\OptionsResolver\OptionsResolverInterface;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19abstract class AbstractTypeExtension implements FormTypeExtensionInterface
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 }
27
28 /**
29 * {@inheritdoc}
30 */
31 public function buildView(FormView $view, FormInterface $form, array $options)
32 {
33 }
34
35 /**
36 * {@inheritdoc}
37 */
38 public function finishView(FormView $view, FormInterface $form, array $options)
39 {
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function setDefaultOptions(OptionsResolverInterface $resolver)
46 {
47 }
48}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Button.php b/vendor/symfony/form/Symfony/Component/Form/Button.php
new file mode 100644
index 00000000..6e12ba16
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Button.php
@@ -0,0 +1,436 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\AlreadySubmittedException;
15use Symfony\Component\Form\Exception\BadMethodCallException;
16
17/**
18 * A form button.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class Button implements \IteratorAggregate, FormInterface
23{
24 /**
25 * @var FormInterface
26 */
27 private $parent;
28
29 /**
30 * @var FormConfigInterface
31 */
32 private $config;
33
34 /**
35 * @var Boolean
36 */
37 private $submitted = false;
38
39 /**
40 * Creates a new button from a form configuration.
41 *
42 * @param FormConfigInterface $config The button's configuration.
43 */
44 public function __construct(FormConfigInterface $config)
45 {
46 $this->config = $config;
47 }
48
49 /**
50 * Unsupported method.
51 *
52 * @param mixed $offset
53 *
54 * @return Boolean Always returns false.
55 */
56 public function offsetExists($offset)
57 {
58 return false;
59 }
60
61 /**
62 * Unsupported method.
63 *
64 * This method should not be invoked.
65 *
66 * @param mixed $offset
67 *
68 * @throws BadMethodCallException
69 */
70 public function offsetGet($offset)
71 {
72 throw new BadMethodCallException('Buttons cannot have children.');
73 }
74
75 /**
76 * Unsupported method.
77 *
78 * This method should not be invoked.
79 *
80 * @param mixed $offset
81 * @param mixed $value
82 *
83 * @throws BadMethodCallException
84 */
85 public function offsetSet($offset, $value)
86 {
87 throw new BadMethodCallException('Buttons cannot have children.');
88 }
89
90 /**
91 * Unsupported method.
92 *
93 * This method should not be invoked.
94 *
95 * @param mixed $offset
96 *
97 * @throws BadMethodCallException
98 */
99 public function offsetUnset($offset)
100 {
101 throw new BadMethodCallException('Buttons cannot have children.');
102 }
103
104 /**
105 * {@inheritdoc}
106 */
107 public function setParent(FormInterface $parent = null)
108 {
109 $this->parent = $parent;
110 }
111
112 /**
113 * {@inheritdoc}
114 */
115 public function getParent()
116 {
117 return $this->parent;
118 }
119
120 /**
121 * Unsupported method.
122 *
123 * This method should not be invoked.
124 *
125 * @param int|string|FormInterface $child
126 * @param null $type
127 * @param array $options
128 *
129 * @throws BadMethodCallException
130 */
131 public function add($child, $type = null, array $options = array())
132 {
133 throw new BadMethodCallException('Buttons cannot have children.');
134 }
135
136 /**
137 * Unsupported method.
138 *
139 * This method should not be invoked.
140 *
141 * @param string $name
142 *
143 * @throws BadMethodCallException
144 */
145 public function get($name)
146 {
147 throw new BadMethodCallException('Buttons cannot have children.');
148 }
149
150 /**
151 * Unsupported method.
152 *
153 * @param string $name
154 *
155 * @return Boolean Always returns false.
156 */
157 public function has($name)
158 {
159 return false;
160 }
161
162 /**
163 * Unsupported method.
164 *
165 * This method should not be invoked.
166 *
167 * @param string $name
168 *
169 * @throws BadMethodCallException
170 */
171 public function remove($name)
172 {
173 throw new BadMethodCallException('Buttons cannot have children.');
174 }
175
176 /**
177 * {@inheritdoc}
178 */
179 public function all()
180 {
181 return array();
182 }
183
184 /**
185 * {@inheritdoc}
186 */
187 public function getErrors()
188 {
189 return array();
190 }
191
192 /**
193 * Unsupported method.
194 *
195 * This method should not be invoked.
196 *
197 * @param string $modelData
198 *
199 * @throws BadMethodCallException
200 */
201 public function setData($modelData)
202 {
203 throw new BadMethodCallException('Buttons cannot have data.');
204 }
205
206 /**
207 * Unsupported method.
208 *
209 * @return null Always returns null.
210 */
211 public function getData()
212 {
213 return null;
214 }
215
216 /**
217 * Unsupported method.
218 *
219 * @return null Always returns null.
220 */
221 public function getNormData()
222 {
223 return null;
224 }
225
226 /**
227 * Unsupported method.
228 *
229 * @return null Always returns null.
230 */
231 public function getViewData()
232 {
233 return null;
234 }
235
236 /**
237 * Unsupported method.
238 *
239 * @return array Always returns an empty array.
240 */
241 public function getExtraData()
242 {
243 return array();
244 }
245
246 /**
247 * Returns the button's configuration.
248 *
249 * @return FormConfigInterface The configuration.
250 */
251 public function getConfig()
252 {
253 return $this->config;
254 }
255
256 /**
257 * Returns whether the button is submitted.
258 *
259 * @return Boolean true if the button was submitted.
260 */
261 public function isSubmitted()
262 {
263 return $this->submitted;
264 }
265
266 /**
267 * Returns the name by which the button is identified in forms.
268 *
269 * @return string The name of the button.
270 */
271 public function getName()
272 {
273 return $this->config->getName();
274 }
275
276 /**
277 * Unsupported method.
278 *
279 * @return null Always returns null.
280 */
281 public function getPropertyPath()
282 {
283 return null;
284 }
285
286 /**
287 * Unsupported method.
288 *
289 * @param FormError $error
290 *
291 * @throws BadMethodCallException
292 */
293 public function addError(FormError $error)
294 {
295 throw new BadMethodCallException('Buttons cannot have errors.');
296 }
297
298 /**
299 * Unsupported method.
300 *
301 * @return Boolean Always returns true.
302 */
303 public function isValid()
304 {
305 return true;
306 }
307
308 /**
309 * Unsupported method.
310 *
311 * @return Boolean Always returns false.
312 */
313 public function isRequired()
314 {
315 return false;
316 }
317
318 /**
319 * {@inheritdoc}
320 */
321 public function isDisabled()
322 {
323 return $this->config->getDisabled();
324 }
325
326 /**
327 * Unsupported method.
328 *
329 * @return Boolean Always returns true.
330 */
331 public function isEmpty()
332 {
333 return true;
334 }
335
336 /**
337 * Unsupported method.
338 *
339 * @return Boolean Always returns true.
340 */
341 public function isSynchronized()
342 {
343 return true;
344 }
345
346 /**
347 * Unsupported method.
348 *
349 * @throws BadMethodCallException
350 */
351 public function initialize()
352 {
353 throw new BadMethodCallException('Buttons cannot be initialized. Call initialize() on the root form instead.');
354 }
355
356 /**
357 * Unsupported method.
358 *
359 * @param mixed $request
360 *
361 * @throws BadMethodCallException
362 */
363 public function handleRequest($request = null)
364 {
365 throw new BadMethodCallException('Buttons cannot handle requests. Call handleRequest() on the root form instead.');
366 }
367
368 /**
369 * Submits data to the button.
370 *
371 * @param null|string $submittedData The data.
372 * @param Boolean $clearMissing Not used.
373 *
374 * @return Button The button instance
375 *
376 * @throws Exception\AlreadySubmittedException If the button has already been submitted.
377 */
378 public function submit($submittedData, $clearMissing = true)
379 {
380 if ($this->submitted) {
381 throw new AlreadySubmittedException('A form can only be submitted once');
382 }
383
384 $this->submitted = true;
385
386 return $this;
387 }
388
389 /**
390 * {@inheritdoc}
391 */
392 public function getRoot()
393 {
394 return $this->parent ? $this->parent->getRoot() : $this;
395 }
396
397 /**
398 * {@inheritdoc}
399 */
400 public function isRoot()
401 {
402 return null === $this->parent;
403 }
404
405 /**
406 * {@inheritdoc}
407 */
408 public function createView(FormView $parent = null)
409 {
410 if (null === $parent && $this->parent) {
411 $parent = $this->parent->createView();
412 }
413
414 return $this->config->getType()->createView($this, $parent);
415 }
416
417 /**
418 * Unsupported method.
419 *
420 * @return integer Always returns 0.
421 */
422 public function count()
423 {
424 return 0;
425 }
426
427 /**
428 * Unsupported method.
429 *
430 * @return \EmptyIterator Always returns an empty iterator.
431 */
432 public function getIterator()
433 {
434 return new \EmptyIterator();
435 }
436}
diff --git a/vendor/symfony/form/Symfony/Component/Form/ButtonBuilder.php b/vendor/symfony/form/Symfony/Component/Form/ButtonBuilder.php
new file mode 100644
index 00000000..3addedbd
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/ButtonBuilder.php
@@ -0,0 +1,864 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15use Symfony\Component\Form\Exception\InvalidArgumentException;
16use Symfony\Component\Form\Exception\BadMethodCallException;
17
18/**
19 * A builder for {@link Button} instances.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
24{
25 /**
26 * @var Boolean
27 */
28 protected $locked = false;
29
30 /**
31 * @var Boolean
32 */
33 private $disabled;
34
35 /**
36 * @var ResolvedFormTypeInterface
37 */
38 private $type;
39
40 /**
41 * @var string
42 */
43 private $name;
44
45 /**
46 * @var array
47 */
48 private $attributes = array();
49
50 /**
51 * @var array
52 */
53 private $options;
54
55 /**
56 * Creates a new button builder.
57 *
58 * @param string $name The name of the button.
59 * @param array $options The button's options.
60 *
61 * @throws InvalidArgumentException If the name is empty.
62 */
63 public function __construct($name, array $options)
64 {
65 if (empty($name) && 0 != $name) {
66 throw new InvalidArgumentException('Buttons cannot have empty names.');
67 }
68
69 $this->name = (string) $name;
70 $this->options = $options;
71 }
72
73 /**
74 * Unsupported method.
75 *
76 * This method should not be invoked.
77 *
78 * @param string|integer|FormBuilderInterface $child
79 * @param string|FormTypeInterface $type
80 * @param array $options
81 *
82 * @throws BadMethodCallException
83 */
84 public function add($child, $type = null, array $options = array())
85 {
86 throw new BadMethodCallException('Buttons cannot have children.');
87 }
88
89 /**
90 * Unsupported method.
91 *
92 * This method should not be invoked.
93 *
94 * @param string $name
95 * @param string|FormTypeInterface $type
96 * @param array $options
97 *
98 * @throws BadMethodCallException
99 */
100 public function create($name, $type = null, array $options = array())
101 {
102 throw new BadMethodCallException('Buttons cannot have children.');
103 }
104
105 /**
106 * Unsupported method.
107 *
108 * This method should not be invoked.
109 *
110 * @param string $name
111 *
112 * @throws BadMethodCallException
113 */
114 public function get($name)
115 {
116 throw new BadMethodCallException('Buttons cannot have children.');
117 }
118
119 /**
120 * Unsupported method.
121 *
122 * This method should not be invoked.
123 *
124 * @param string $name
125 *
126 * @throws BadMethodCallException
127 */
128 public function remove($name)
129 {
130 throw new BadMethodCallException('Buttons cannot have children.');
131 }
132
133 /**
134 * Unsupported method.
135 *
136 * @param string $name
137 *
138 * @return Boolean Always returns false.
139 */
140 public function has($name)
141 {
142 return false;
143 }
144
145 /**
146 * Returns the children.
147 *
148 * @return array Always returns an empty array.
149 */
150 public function all()
151 {
152 return array();
153 }
154
155 /**
156 * Creates the button.
157 *
158 * @return Button The button
159 */
160 public function getForm()
161 {
162 return new Button($this->getFormConfig());
163 }
164
165 /**
166 * Unsupported method.
167 *
168 * This method should not be invoked.
169 *
170 * @param string $eventName
171 * @param callable $listener
172 * @param integer $priority
173 *
174 * @throws BadMethodCallException
175 */
176 public function addEventListener($eventName, $listener, $priority = 0)
177 {
178 throw new BadMethodCallException('Buttons do not support event listeners.');
179 }
180
181 /**
182 * Unsupported method.
183 *
184 * This method should not be invoked.
185 *
186 * @param EventSubscriberInterface $subscriber
187 *
188 * @throws BadMethodCallException
189 */
190 public function addEventSubscriber(EventSubscriberInterface $subscriber)
191 {
192 throw new BadMethodCallException('Buttons do not support event subscribers.');
193 }
194
195 /**
196 * Unsupported method.
197 *
198 * This method should not be invoked.
199 *
200 * @param DataTransformerInterface $viewTransformer
201 * @param Boolean $forcePrepend
202 *
203 * @throws BadMethodCallException
204 */
205 public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false)
206 {
207 throw new BadMethodCallException('Buttons do not support data transformers.');
208 }
209
210 /**
211 * Unsupported method.
212 *
213 * This method should not be invoked.
214 *
215 * @throws BadMethodCallException
216 */
217 public function resetViewTransformers()
218 {
219 throw new BadMethodCallException('Buttons do not support data transformers.');
220 }
221
222 /**
223 * Unsupported method.
224 *
225 * This method should not be invoked.
226 *
227 * @param DataTransformerInterface $modelTransformer
228 * @param Boolean $forceAppend
229 *
230 * @throws BadMethodCallException
231 */
232 public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false)
233 {
234 throw new BadMethodCallException('Buttons do not support data transformers.');
235 }
236
237 /**
238 * Unsupported method.
239 *
240 * This method should not be invoked.
241 *
242 * @throws BadMethodCallException
243 */
244 public function resetModelTransformers()
245 {
246 throw new BadMethodCallException('Buttons do not support data transformers.');
247 }
248
249 /**
250 * {@inheritdoc}
251 */
252 public function setAttribute($name, $value)
253 {
254 $this->attributes[$name] = $value;
255 }
256
257 /**
258 * {@inheritdoc}
259 */
260 public function setAttributes(array $attributes)
261 {
262 $this->attributes = $attributes;
263 }
264
265 /**
266 * Unsupported method.
267 *
268 * This method should not be invoked.
269 *
270 * @param DataMapperInterface $dataMapper
271 *
272 * @throws BadMethodCallException
273 */
274 public function setDataMapper(DataMapperInterface $dataMapper = null)
275 {
276 throw new BadMethodCallException('Buttons do not support data mappers.');
277 }
278
279 /**
280 * Set whether the button is disabled.
281 *
282 * @param Boolean $disabled Whether the button is disabled
283 *
284 * @return ButtonBuilder The button builder.
285 */
286 public function setDisabled($disabled)
287 {
288 $this->disabled = $disabled;
289 }
290
291 /**
292 * Unsupported method.
293 *
294 * This method should not be invoked.
295 *
296 * @param mixed $emptyData
297 *
298 * @throws BadMethodCallException
299 */
300 public function setEmptyData($emptyData)
301 {
302 throw new BadMethodCallException('Buttons do not support empty data.');
303 }
304
305 /**
306 * Unsupported method.
307 *
308 * This method should not be invoked.
309 *
310 * @param Boolean $errorBubbling
311 *
312 * @throws BadMethodCallException
313 */
314 public function setErrorBubbling($errorBubbling)
315 {
316 throw new BadMethodCallException('Buttons do not support error bubbling.');
317 }
318
319 /**
320 * Unsupported method.
321 *
322 * This method should not be invoked.
323 *
324 * @param Boolean $required
325 *
326 * @throws BadMethodCallException
327 */
328 public function setRequired($required)
329 {
330 throw new BadMethodCallException('Buttons cannot be required.');
331 }
332
333 /**
334 * Unsupported method.
335 *
336 * This method should not be invoked.
337 *
338 * @param null $propertyPath
339 *
340 * @throws BadMethodCallException
341 */
342 public function setPropertyPath($propertyPath)
343 {
344 throw new BadMethodCallException('Buttons do not support property paths.');
345 }
346
347 /**
348 * Unsupported method.
349 *
350 * This method should not be invoked.
351 *
352 * @param Boolean $mapped
353 *
354 * @throws BadMethodCallException
355 */
356 public function setMapped($mapped)
357 {
358 throw new BadMethodCallException('Buttons do not support data mapping.');
359 }
360
361 /**
362 * Unsupported method.
363 *
364 * This method should not be invoked.
365 *
366 * @param Boolean $byReference
367 *
368 * @throws BadMethodCallException
369 */
370 public function setByReference($byReference)
371 {
372 throw new BadMethodCallException('Buttons do not support data mapping.');
373 }
374
375 /**
376 * Unsupported method.
377 *
378 * This method should not be invoked.
379 *
380 * @param Boolean $virtual
381 *
382 * @throws BadMethodCallException
383 */
384 public function setVirtual($virtual)
385 {
386 throw new BadMethodCallException('Buttons cannot be virtual.');
387 }
388
389 /**
390 * Unsupported method.
391 *
392 * This method should not be invoked.
393 *
394 * @param Boolean $compound
395 *
396 * @throws BadMethodCallException
397 */
398 public function setCompound($compound)
399 {
400 throw new BadMethodCallException('Buttons cannot be compound.');
401 }
402
403 /**
404 * Sets the type of the button.
405 *
406 * @param ResolvedFormTypeInterface $type The type of the button.
407 *
408 * @return ButtonBuilder The button builder.
409 */
410 public function setType(ResolvedFormTypeInterface $type)
411 {
412 $this->type = $type;
413 }
414
415 /**
416 * Unsupported method.
417 *
418 * This method should not be invoked.
419 *
420 * @param array $data
421 *
422 * @throws BadMethodCallException
423 */
424 public function setData($data)
425 {
426 throw new BadMethodCallException('Buttons do not support data.');
427 }
428
429 /**
430 * Unsupported method.
431 *
432 * This method should not be invoked.
433 *
434 * @param Boolean $locked
435 *
436 * @throws BadMethodCallException
437 */
438 public function setDataLocked($locked)
439 {
440 throw new BadMethodCallException('Buttons do not support data locking.');
441 }
442
443 /**
444 * Unsupported method.
445 *
446 * This method should not be invoked.
447 *
448 * @param FormFactoryInterface $formFactory
449 *
450 * @return void
451 *
452 * @throws BadMethodCallException
453 */
454 public function setFormFactory(FormFactoryInterface $formFactory)
455 {
456 throw new BadMethodCallException('Buttons do not support form factories.');
457 }
458
459 /**
460 * Unsupported method.
461 *
462 * @param string $action
463 *
464 * @throws BadMethodCallException
465 */
466 public function setAction($action)
467 {
468 throw new BadMethodCallException('Buttons do not support actions.');
469 }
470
471 /**
472 * Unsupported method.
473 *
474 * @param string $method
475 *
476 * @throws BadMethodCallException
477 */
478 public function setMethod($method)
479 {
480 throw new BadMethodCallException('Buttons do not support methods.');
481 }
482
483 /**
484 * Unsupported method.
485 *
486 * @param RequestHandlerInterface $requestHandler
487 *
488 * @throws BadMethodCallException
489 */
490 public function setRequestHandler(RequestHandlerInterface $requestHandler)
491 {
492 throw new BadMethodCallException('Buttons do not support form processors.');
493 }
494
495 /**
496 * Unsupported method.
497 *
498 * @param Boolean $initialize
499 *
500 * @throws BadMethodCallException
501 */
502 public function setAutoInitialize($initialize)
503 {
504 if (true === $initialize) {
505 throw new BadMethodCallException('Buttons do not support automatic initialization.');
506 }
507
508 return $this;
509 }
510
511 /**
512 * Unsupported method.
513 *
514 * @param Boolean $inheritData
515 *
516 * @throws BadMethodCallException
517 */
518 public function setInheritData($inheritData)
519 {
520 throw new BadMethodCallException('Buttons do not support data inheritance.');
521 }
522
523 /**
524 * Builds and returns the button configuration.
525 *
526 * @return FormConfigInterface
527 */
528 public function getFormConfig()
529 {
530 // This method should be idempotent, so clone the builder
531 $config = clone $this;
532 $config->locked = true;
533
534 return $config;
535 }
536
537 /**
538 * Unsupported method.
539 *
540 * @return null Always returns null.
541 */
542 public function getEventDispatcher()
543 {
544 return null;
545 }
546
547 /**
548 * {@inheritdoc}
549 */
550 public function getName()
551 {
552 return $this->name;
553 }
554
555 /**
556 * Unsupported method.
557 *
558 * @return null Always returns null.
559 */
560 public function getPropertyPath()
561 {
562 return null;
563 }
564
565 /**
566 * Unsupported method.
567 *
568 * @return Boolean Always returns false.
569 */
570 public function getMapped()
571 {
572 return false;
573 }
574
575 /**
576 * Unsupported method.
577 *
578 * @return Boolean Always returns false.
579 */
580 public function getByReference()
581 {
582 return false;
583 }
584
585 /**
586 * Unsupported method.
587 *
588 * @return Boolean Always returns false.
589 */
590 public function getVirtual()
591 {
592 return false;
593 }
594
595 /**
596 * Unsupported method.
597 *
598 * @return Boolean Always returns false.
599 */
600 public function getCompound()
601 {
602 return false;
603 }
604
605 /**
606 * Returns the form type used to construct the button.
607 *
608 * @return ResolvedFormTypeInterface The button's type.
609 */
610 public function getType()
611 {
612 return $this->type;
613 }
614
615 /**
616 * Unsupported method.
617 *
618 * @return array Always returns an empty array.
619 */
620 public function getViewTransformers()
621 {
622 return array();
623 }
624
625 /**
626 * Unsupported method.
627 *
628 * @return array Always returns an empty array.
629 */
630 public function getModelTransformers()
631 {
632 return array();
633 }
634
635 /**
636 * Unsupported method.
637 *
638 * @return null Always returns null.
639 */
640 public function getDataMapper()
641 {
642 return null;
643 }
644
645 /**
646 * Unsupported method.
647 *
648 * @return Boolean Always returns false.
649 */
650 public function getRequired()
651 {
652 return false;
653 }
654
655 /**
656 * Returns whether the button is disabled.
657 *
658 * @return Boolean Whether the button is disabled.
659 */
660 public function getDisabled()
661 {
662 return $this->disabled;
663 }
664
665 /**
666 * Unsupported method.
667 *
668 * @return Boolean Always returns false.
669 */
670 public function getErrorBubbling()
671 {
672 return false;
673 }
674
675 /**
676 * Unsupported method.
677 *
678 * @return null Always returns null.
679 */
680 public function getEmptyData()
681 {
682 return null;
683 }
684
685 /**
686 * Returns additional attributes of the button.
687 *
688 * @return array An array of key-value combinations.
689 */
690 public function getAttributes()
691 {
692 return $this->attributes;
693 }
694
695 /**
696 * Returns whether the attribute with the given name exists.
697 *
698 * @param string $name The attribute name.
699 *
700 * @return Boolean Whether the attribute exists.
701 */
702 public function hasAttribute($name)
703 {
704 return array_key_exists($name, $this->attributes);
705 }
706
707 /**
708 * Returns the value of the given attribute.
709 *
710 * @param string $name The attribute name.
711 * @param mixed $default The value returned if the attribute does not exist.
712 *
713 * @return mixed The attribute value.
714 */
715 public function getAttribute($name, $default = null)
716 {
717 return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
718 }
719
720 /**
721 * Unsupported method.
722 *
723 * @return null Always returns null.
724 */
725 public function getData()
726 {
727 return null;
728 }
729
730 /**
731 * Unsupported method.
732 *
733 * @return null Always returns null.
734 */
735 public function getDataClass()
736 {
737 return null;
738 }
739
740 /**
741 * Unsupported method.
742 *
743 * @return Boolean Always returns false.
744 */
745 public function getDataLocked()
746 {
747 return false;
748 }
749
750 /**
751 * Unsupported method.
752 *
753 * @return null Always returns null.
754 */
755 public function getFormFactory()
756 {
757 return null;
758 }
759
760 /**
761 * Unsupported method.
762 *
763 * @return null Always returns null.
764 */
765 public function getAction()
766 {
767 return null;
768 }
769
770 /**
771 * Unsupported method.
772 *
773 * @return null Always returns null.
774 */
775 public function getMethod()
776 {
777 return null;
778 }
779
780 /**
781 * Unsupported method.
782 *
783 * @return null Always returns null.
784 */
785 public function getRequestHandler()
786 {
787 return null;
788 }
789
790 /**
791 * Unsupported method.
792 *
793 * @return Boolean Always returns false.
794 */
795 public function getAutoInitialize()
796 {
797 return false;
798 }
799
800 /**
801 * Unsupported method.
802 *
803 * @return Boolean Always returns false.
804 */
805 public function getInheritData()
806 {
807 return false;
808 }
809
810 /**
811 * Returns all options passed during the construction of the button.
812 *
813 * @return array The passed options.
814 */
815 public function getOptions()
816 {
817 return $this->options;
818 }
819
820 /**
821 * Returns whether a specific option exists.
822 *
823 * @param string $name The option name,
824 *
825 * @return Boolean Whether the option exists.
826 */
827 public function hasOption($name)
828 {
829 return array_key_exists($name, $this->options);
830 }
831
832 /**
833 * Returns the value of a specific option.
834 *
835 * @param string $name The option name.
836 * @param mixed $default The value returned if the option does not exist.
837 *
838 * @return mixed The option value.
839 */
840 public function getOption($name, $default = null)
841 {
842 return array_key_exists($name, $this->options) ? $this->options[$name] : $default;
843 }
844
845 /**
846 * Unsupported method.
847 *
848 * @return integer Always returns 0.
849 */
850 public function count()
851 {
852 return 0;
853 }
854
855 /**
856 * Unsupported method.
857 *
858 * @return \EmptyIterator Always returns an empty iterator.
859 */
860 public function getIterator()
861 {
862 return new \EmptyIterator();
863 }
864}
diff --git a/vendor/symfony/form/Symfony/Component/Form/ButtonTypeInterface.php b/vendor/symfony/form/Symfony/Component/Form/ButtonTypeInterface.php
new file mode 100644
index 00000000..dd5117c4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/ButtonTypeInterface.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * A type that should be converted into a {@link Button} instance.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface ButtonTypeInterface extends FormTypeInterface
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/CHANGELOG.md b/vendor/symfony/form/Symfony/Component/Form/CHANGELOG.md
new file mode 100644
index 00000000..a696c7be
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/CHANGELOG.md
@@ -0,0 +1,238 @@
1CHANGELOG
2=========
3
4
52.3.0
6------
7
8 * deprecated FormPerformanceTestCase and FormIntegrationTestCase in the Symfony\Component\Form\Tests namespace and moved them to the Symfony\Component\Form\Test namespace
9 * deprecated TypeTestCase in the Symfony\Component\Form\Tests\Extension\Core\Type namespace and moved it to the Symfony\Component\Form\Test namespace
10 * changed FormRenderer::humanize() to humanize also camel cased field name
11 * added RequestHandlerInterface and FormInterface::handleRequest()
12 * deprecated passing a Request instance to FormInterface::bind()
13 * added options "method" and "action" to FormType
14 * deprecated option "virtual" in favor "inherit_data"
15 * deprecated VirtualFormAwareIterator in favor of InheritDataAwareIterator
16 * [BC BREAK] removed the "array" type hint from DataMapperInterface
17 * improved forms inheriting their parent data to actually return that data from getData(), getNormData() and getViewData()
18 * added component-level exceptions for various SPL exceptions
19 changed all uses of the deprecated Exception class to use more specialized exceptions instead
20 removed NotInitializedException, NotValidException, TypeDefinitionException, TypeLoaderException, CreationException
21 * added events PRE_SUBMIT, SUBMIT and POST_SUBMIT
22 * deprecated events PRE_BIND, BIND and POST_BIND
23 * [BC BREAK] renamed bind() and isBound() in FormInterface to submit() and isSubmitted()
24 * added methods submit() and isSubmitted() to Form
25 * deprecated bind() and isBound() in Form
26 * deprecated AlreadyBoundException in favor of AlreadySubmittedException
27 * added support for PATCH requests
28 * [BC BREAK] added initialize() to FormInterface
29 * [BC BREAK] added getAutoInitialize() to FormConfigInterface
30 * [BC BREAK] added setAutoInitialize() to FormConfigBuilderInterface
31 * [BC BREAK] initialization for Form instances added to a form tree must be manually disabled
32 * PRE_SET_DATA is now guaranteed to be called after children were added by the form builder,
33 unless FormInterface::setData() is called manually
34 * fixed CSRF error message to be translated
35 * custom CSRF error messages can now be set through the "csrf_message" option
36 * fixed: expanded single-choice fields now show a radio button for the empty value
37
382.2.0
39-----
40
41 * TrimListener now removes unicode whitespaces
42 * deprecated getParent(), setParent() and hasParent() in FormBuilderInterface
43 * FormInterface::add() now accepts a FormInterface instance OR a field's name, type and options
44 * removed special characters between the choice or text fields of DateType unless
45 the option "format" is set to a custom value
46 * deprecated FormException and introduced ExceptionInterface instead
47 * [BC BREAK] FormException is now an interface
48 * protected FormBuilder methods from being called when it is turned into a FormConfigInterface with getFormConfig()
49 * [BC BREAK] inserted argument `$message` in the constructor of `FormError`
50 * the PropertyPath class and related classes were moved to a dedicated
51 PropertyAccess component. During the move, InvalidPropertyException was
52 renamed to NoSuchPropertyException. FormUtil was split: FormUtil::singularify()
53 can now be found in Symfony\Component\PropertyAccess\StringUtil. The methods
54 getValue() and setValue() from PropertyPath were extracted into a new class
55 PropertyAccessor.
56 * added an optional PropertyAccessorInterface parameter to FormType,
57 ObjectChoiceList and PropertyPathMapper
58 * [BC BREAK] PropertyPathMapper and FormType now have a constructor
59 * [BC BREAK] setting the option "validation_groups" to ``false`` now disables validation
60 instead of assuming group "Default"
61
622.1.0
63-----
64
65 * [BC BREAK] ``read_only`` field attribute now renders as ``readonly="readonly"``, use ``disabled`` instead
66 * [BC BREAK] child forms now aren't validated anymore by default
67 * made validation of form children configurable (new option: cascade_validation)
68 * added support for validation groups as callbacks
69 * made the translation catalogue configurable via the "translation_domain" option
70 * added Form::getErrorsAsString() to help debugging forms
71 * allowed setting different options for RepeatedType fields (like the label)
72 * added support for empty form name at root level, this enables rendering forms
73 without form name prefix in field names
74 * [BC BREAK] form and field names must start with a letter, digit or underscore
75 and only contain letters, digits, underscores, hyphens and colons
76 * [BC BREAK] changed default name of the prototype in the "collection" type
77 from "$$name$$" to "\__name\__". No dollars are appended/prepended to custom
78 names anymore.
79 * [BC BREAK] improved ChoiceListInterface
80 * [BC BREAK] added SimpleChoiceList and LazyChoiceList as replacement of
81 ArrayChoiceList
82 * added ChoiceList and ObjectChoiceList to use objects as choices
83 * [BC BREAK] removed EntitiesToArrayTransformer and EntityToIdTransformer.
84 The former has been replaced by CollectionToArrayTransformer in combination
85 with EntityChoiceList, the latter is not required in the core anymore.
86 * [BC BREAK] renamed
87 * ArrayToBooleanChoicesTransformer to ChoicesToBooleanArrayTransformer
88 * ScalarToBooleanChoicesTransformer to ChoiceToBooleanArrayTransformer
89 * ArrayToChoicesTransformer to ChoicesToValuesTransformer
90 * ScalarToChoiceTransformer to ChoiceToValueTransformer
91 to be consistent with the naming in ChoiceListInterface.
92 They were merged into ChoiceList and have no public equivalent anymore.
93 * choice fields now throw a FormException if neither the "choices" nor the
94 "choice_list" option is set
95 * the radio type is now a child of the checkbox type
96 * the collection, choice (with multiple selection) and entity (with multiple
97 selection) types now make use of addXxx() and removeXxx() methods in your
98 model if you set "by_reference" to false. For a custom, non-recognized
99 singular form, set the "property_path" option like this: "plural|singular"
100 * forms now don't create an empty object anymore if they are completely
101 empty and not required. The empty value for such forms is null.
102 * added constant Guess::VERY_HIGH_CONFIDENCE
103 * [BC BREAK] The methods `add`, `remove`, `setParent`, `bind` and `setData`
104 in class Form now throw an exception if the form is already bound
105 * fields of constrained classes without a NotBlank or NotNull constraint are
106 set to not required now, as stated in the docs
107 * fixed TimeType and DateTimeType to not display seconds when "widget" is
108 "single_text" unless "with_seconds" is set to true
109 * checkboxes of in an expanded multiple-choice field don't include the choice
110 in their name anymore. Their names terminate with "[]" now.
111 * deprecated FormValidatorInterface and substituted its implementations
112 by event subscribers
113 * simplified CSRF protection and removed the csrf type
114 * deprecated FieldType and merged it into FormType
115 * added new option "compound" that lets you switch between field and form behavior
116 * [BC BREAK] renamed theme blocks
117 * "field_*" to "form_*"
118 * "field_widget" to "form_widget_simple"
119 * "widget_choice_options" to "choice_widget_options"
120 * "generic_label" to "form_label"
121 * added theme blocks "form_widget_compound", "choice_widget_expanded" and
122 "choice_widget_collapsed" to make theming more modular
123 * ValidatorTypeGuesser now guesses "collection" for array type constraint
124 * added method `guessPattern` to FormTypeGuesserInterface to guess which pattern to use in the HTML5 attribute "pattern"
125 * deprecated method `guessMinLength` in favor of `guessPattern`
126 * labels don't display field attributes anymore. Label attributes can be
127 passed in the "label_attr" option/variable
128 * added option "mapped" which should be used instead of setting "property_path" to false
129 * [BC BREAK] "data_class" now *must* be set if a form maps to an object and should be left empty otherwise
130 * improved error mapping on forms
131 * dot (".") rules are now allowed to map errors assigned to a form to
132 one of its children
133 * errors are not mapped to unsynchronized forms anymore
134 * [BC BREAK] changed Form constructor to accept a single `FormConfigInterface` object
135 * [BC BREAK] changed argument order in the FormBuilder constructor
136 * added Form method `getViewData`
137 * deprecated Form methods
138 * `getTypes`
139 * `getErrorBubbling`
140 * `getNormTransformers`
141 * `getClientTransformers`
142 * `getAttribute`
143 * `hasAttribute`
144 * `getClientData`
145 * added FormBuilder methods
146 * `getTypes`
147 * `addViewTransformer`
148 * `getViewTransformers`
149 * `resetViewTransformers`
150 * `addModelTransformer`
151 * `getModelTransformers`
152 * `resetModelTransformers`
153 * deprecated FormBuilder methods
154 * `prependClientTransformer`
155 * `appendClientTransformer`
156 * `getClientTransformers`
157 * `resetClientTransformers`
158 * `prependNormTransformer`
159 * `appendNormTransformer`
160 * `getNormTransformers`
161 * `resetNormTransformers`
162 * deprecated the option "validation_constraint" in favor of the new
163 option "constraints"
164 * removed superfluous methods from DataMapperInterface
165 * `mapFormToData`
166 * `mapDataToForm`
167 * added `setDefaultOptions` to FormTypeInterface and FormTypeExtensionInterface
168 which accepts an OptionsResolverInterface instance
169 * deprecated the methods `getDefaultOptions` and `getAllowedOptionValues`
170 in FormTypeInterface and FormTypeExtensionInterface
171 * options passed during construction can now be accessed from FormConfigInterface
172 * added FormBuilderInterface and FormConfigEditorInterface
173 * [BC BREAK] the method `buildForm` in FormTypeInterface and FormTypeExtensionInterface
174 now receives a FormBuilderInterface instead of a FormBuilder instance
175 * [BC BREAK] the method `buildViewBottomUp` was renamed to `finishView` in
176 FormTypeInterface and FormTypeExtensionInterface
177 * [BC BREAK] the options array is now passed as last argument of the
178 methods
179 * `buildView`
180 * `finishView`
181 in FormTypeInterface and FormTypeExtensionInterface
182 * [BC BREAK] no options are passed to `getParent` of FormTypeInterface anymore
183 * deprecated DataEvent and FilterDataEvent in favor of the new FormEvent which is
184 now passed to all events thrown by the component
185 * FormEvents::BIND now replaces FormEvents::BIND_NORM_DATA
186 * FormEvents::PRE_SET_DATA now replaces FormEvents::SET_DATA
187 * FormEvents::PRE_BIND now replaces FormEvents::BIND_CLIENT_DATA
188 * deprecated FormEvents::SET_DATA, FormEvents::BIND_CLIENT_DATA and
189 FormEvents::BIND_NORM_DATA
190 * [BC BREAK] reversed the order of the first two arguments to `createNamed`
191 and `createNamedBuilder` in `FormFactoryInterface`
192 * deprecated `getChildren` in Form and FormBuilder in favor of `all`
193 * deprecated `hasChildren` in Form and FormBuilder in favor of `count`
194 * FormBuilder now implements \IteratorAggregate
195 * [BC BREAK] compound forms now always need a data mapper
196 * FormBuilder now maintains the order when explicitly adding form builders as children
197 * ChoiceType now doesn't add the empty value anymore if the choices already contain an empty element
198 * DateType, TimeType and DateTimeType now show empty values again if not required
199 * [BC BREAK] fixed rendering of errors for DateType, BirthdayType and similar ones
200 * [BC BREAK] fixed: form constraints are only validated if they belong to the validated group
201 * deprecated `bindRequest` in `Form` and replaced it by a listener to FormEvents::PRE_BIND
202 * fixed: the "data" option supersedes default values from the model
203 * changed DateType to refer to the "format" option for calculating the year and day choices instead
204 of padding them automatically
205 * [BC BREAK] DateType defaults to the format "yyyy-MM-dd" now if the widget is
206 "single_text", in order to support the HTML 5 date field out of the box
207 * added the option "format" to DateTimeType
208 * [BC BREAK] DateTimeType now outputs RFC 3339 dates by default, as generated and
209 consumed by HTML5 browsers, if the widget is "single_text"
210 * deprecated the options "data_timezone" and "user_timezone" in DateType, DateTimeType and TimeType
211 and renamed them to "model_timezone" and "view_timezone"
212 * fixed: TransformationFailedExceptions thrown in the model transformer are now caught by the form
213 * added FormRegistryInterface, ResolvedFormTypeInterface and ResolvedFormTypeFactoryInterface
214 * deprecated FormFactory methods
215 * `addType`
216 * `hasType`
217 * `getType`
218 * [BC BREAK] FormFactory now expects a FormRegistryInterface and a ResolvedFormTypeFactoryInterface as constructor argument
219 * [BC BREAK] The method `createBuilder` in FormTypeInterface is not supported anymore for performance reasons
220 * [BC BREAK] Removed `setTypes` from FormBuilder
221 * deprecated AbstractType methods
222 * `getExtensions`
223 * `setExtensions`
224 * ChoiceType now caches its created choice lists to improve performance
225 * [BC BREAK] Rows of a collection field cannot be themed individually anymore. All rows in the collection
226 field now have the same block names, which contains "entry" where it previously contained the row index.
227 * [BC BREAK] When registering a type through the DI extension, the tag alias has to match the actual type name.
228 * added FormRendererInterface, FormRendererEngineInterface and implementations of these interfaces
229 * [BC BREAK] removed the following methods from FormUtil:
230 * `toArrayKey`
231 * `toArrayKeys`
232 * `isChoiceGroup`
233 * `isChoiceSelected`
234 * [BC BREAK] renamed method `renderBlock` in FormHelper to `block` and changed its signature
235 * made FormView properties public and deprecated their accessor methods
236 * made the normalized data of a form accessible in the template through the variable "form.vars.data"
237 * made the original data of a choice accessible in the template through the property "choice.data"
238 * added convenience class Forms and FormFactoryBuilderInterface
diff --git a/vendor/symfony/form/Symfony/Component/Form/CallbackTransformer.php b/vendor/symfony/form/Symfony/Component/Form/CallbackTransformer.php
new file mode 100644
index 00000000..1dfe8900
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/CallbackTransformer.php
@@ -0,0 +1,70 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14class CallbackTransformer implements DataTransformerInterface
15{
16 /**
17 * The callback used for forward transform
18 * @var \Closure
19 */
20 private $transform;
21
22 /**
23 * The callback used for reverse transform
24 * @var \Closure
25 */
26 private $reverseTransform;
27
28 /**
29 * Constructor.
30 *
31 * @param \Closure $transform The forward transform callback
32 * @param \Closure $reverseTransform The reverse transform callback
33 */
34 public function __construct(\Closure $transform, \Closure $reverseTransform)
35 {
36 $this->transform = $transform;
37 $this->reverseTransform = $reverseTransform;
38 }
39
40 /**
41 * Transforms a value from the original representation to a transformed representation.
42 *
43 * @param mixed $data The value in the original representation
44 *
45 * @return mixed The value in the transformed representation
46 *
47 * @throws UnexpectedTypeException when the argument is not a string
48 * @throws TransformationFailedException when the transformation fails
49 */
50 public function transform($data)
51 {
52 return call_user_func($this->transform, $data);
53 }
54
55 /**
56 * Transforms a value from the transformed representation to its original
57 * representation.
58 *
59 * @param mixed $data The value in the transformed representation
60 *
61 * @return mixed The value in the original representation
62 *
63 * @throws UnexpectedTypeException when the argument is not of the expected type
64 * @throws TransformationFailedException when the transformation fails
65 */
66 public function reverseTransform($data)
67 {
68 return call_user_func($this->reverseTransform, $data);
69 }
70}
diff --git a/vendor/symfony/form/Symfony/Component/Form/ClickableInterface.php b/vendor/symfony/form/Symfony/Component/Form/ClickableInterface.php
new file mode 100644
index 00000000..893f02df
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/ClickableInterface.php
@@ -0,0 +1,27 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * A clickable form element.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface ClickableInterface
20{
21 /**
22 * Returns whether this element was clicked.
23 *
24 * @return Boolean Whether this element was clicked.
25 */
26 public function isClicked();
27}
diff --git a/vendor/symfony/form/Symfony/Component/Form/DataMapperInterface.php b/vendor/symfony/form/Symfony/Component/Form/DataMapperInterface.php
new file mode 100644
index 00000000..6e031682
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/DataMapperInterface.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17interface DataMapperInterface
18{
19 /**
20 * Maps properties of some data to a list of forms.
21 *
22 * @param mixed $data Structured data.
23 * @param FormInterface[] $forms A list of {@link FormInterface} instances.
24 *
25 * @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported.
26 */
27 public function mapDataToForms($data, $forms);
28
29 /**
30 * Maps the data of a list of forms into the properties of some data.
31 *
32 * @param FormInterface[] $forms A list of {@link FormInterface} instances.
33 * @param mixed $data Structured data.
34 *
35 * @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported.
36 */
37 public function mapFormsToData($forms, &$data);
38}
diff --git a/vendor/symfony/form/Symfony/Component/Form/DataTransformerInterface.php b/vendor/symfony/form/Symfony/Component/Form/DataTransformerInterface.php
new file mode 100644
index 00000000..6567da25
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/DataTransformerInterface.php
@@ -0,0 +1,77 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16/**
17 * Transforms a value between different representations.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21interface DataTransformerInterface
22{
23 /**
24 * Transforms a value from the original representation to a transformed representation.
25 *
26 * This method is called on two occasions inside a form field:
27 *
28 * 1. When the form field is initialized with the data attached from the datasource (object or array).
29 * 2. When data from a request is submitted using {@link Form::submit()} to transform the new input data
30 * back into the renderable format. For example if you have a date field and submit '2009-10-10'
31 * you might accept this value because its easily parsed, but the transformer still writes back
32 * "2009/10/10" onto the form field (for further displaying or other purposes).
33 *
34 * This method must be able to deal with empty values. Usually this will
35 * be NULL, but depending on your implementation other empty values are
36 * possible as well (such as empty strings). The reasoning behind this is
37 * that value transformers must be chainable. If the transform() method
38 * of the first value transformer outputs NULL, the second value transformer
39 * must be able to process that value.
40 *
41 * By convention, transform() should return an empty string if NULL is
42 * passed.
43 *
44 * @param mixed $value The value in the original representation
45 *
46 * @return mixed The value in the transformed representation
47 *
48 * @throws TransformationFailedException When the transformation fails.
49 */
50 public function transform($value);
51
52 /**
53 * Transforms a value from the transformed representation to its original
54 * representation.
55 *
56 * This method is called when {@link Form::submit()} is called to transform the requests tainted data
57 * into an acceptable format for your data processing/model layer.
58 *
59 * This method must be able to deal with empty values. Usually this will
60 * be an empty string, but depending on your implementation other empty
61 * values are possible as well (such as empty strings). The reasoning behind
62 * this is that value transformers must be chainable. If the
63 * reverseTransform() method of the first value transformer outputs an
64 * empty string, the second value transformer must be able to process that
65 * value.
66 *
67 * By convention, reverseTransform() should return NULL if an empty string
68 * is passed.
69 *
70 * @param mixed $value The value in the transformed representation
71 *
72 * @return mixed The value in the original representation
73 *
74 * @throws TransformationFailedException When the transformation fails.
75 */
76 public function reverseTransform($value);
77}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/AlreadyBoundException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/AlreadyBoundException.php
new file mode 100644
index 00000000..7ef0ca02
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/AlreadyBoundException.php
@@ -0,0 +1,22 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14/**
15 * Alias of {@link AlreadySubmittedException}.
16 *
17 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
18 * {@link AlreadySubmittedException} instead.
19 */
20class AlreadyBoundException extends LogicException
21{
22}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/AlreadySubmittedException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/AlreadySubmittedException.php
new file mode 100644
index 00000000..7be21249
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/AlreadySubmittedException.php
@@ -0,0 +1,22 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14/**
15 * Thrown when an operation is called that is not acceptable after submitting
16 * a form.
17 *
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class AlreadySubmittedException extends AlreadyBoundException
21{
22}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/BadMethodCallException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/BadMethodCallException.php
new file mode 100644
index 00000000..27649dd0
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/BadMethodCallException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14/**
15 * Base BadMethodCallException for the Form component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/ErrorMappingException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/ErrorMappingException.php
new file mode 100644
index 00000000..a6968492
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/ErrorMappingException.php
@@ -0,0 +1,16 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14class ErrorMappingException extends RuntimeException
15{
16}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/ExceptionInterface.php b/vendor/symfony/form/Symfony/Component/Form/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..d455932e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/ExceptionInterface.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14/**
15 * Base ExceptionInterface for the Form component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface ExceptionInterface
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/InvalidArgumentException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/InvalidArgumentException.php
new file mode 100644
index 00000000..a270e0ce
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/InvalidArgumentException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14/**
15 * Base InvalidArgumentException for the Form component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/InvalidConfigurationException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/InvalidConfigurationException.php
new file mode 100644
index 00000000..daa0c42f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/InvalidConfigurationException.php
@@ -0,0 +1,16 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14class InvalidConfigurationException extends InvalidArgumentException
15{
16}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/LogicException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/LogicException.php
new file mode 100644
index 00000000..84878021
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/LogicException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14/**
15 * Base LogicException for Form component.
16 *
17 * @author Alexander Kotynia <aleksander.kot@gmail.com>
18 */
19class LogicException extends \LogicException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/OutOfBoundsException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/OutOfBoundsException.php
new file mode 100644
index 00000000..44d31166
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/OutOfBoundsException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14/**
15 * Base OutOfBoundsException for Form component.
16 *
17 * @author Alexander Kotynia <aleksander.kot@gmail.com>
18 */
19class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/RuntimeException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/RuntimeException.php
new file mode 100644
index 00000000..0af48a4a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/RuntimeException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14/**
15 * Base RuntimeException for the Form component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class RuntimeException extends \RuntimeException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/StringCastException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/StringCastException.php
new file mode 100644
index 00000000..f9b51d60
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/StringCastException.php
@@ -0,0 +1,16 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14class StringCastException extends RuntimeException
15{
16}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/TransformationFailedException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/TransformationFailedException.php
new file mode 100644
index 00000000..d32896e6
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/TransformationFailedException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14/**
15 * Indicates a value transformation error.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class TransformationFailedException extends RuntimeException
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Exception/UnexpectedTypeException.php b/vendor/symfony/form/Symfony/Component/Form/Exception/UnexpectedTypeException.php
new file mode 100644
index 00000000..474e244b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Exception/UnexpectedTypeException.php
@@ -0,0 +1,20 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Exception;
13
14class UnexpectedTypeException extends InvalidArgumentException
15{
16 public function __construct($value, $expectedType)
17 {
18 parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
19 }
20}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php
new file mode 100644
index 00000000..f9d381cd
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php
@@ -0,0 +1,510 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\ChoiceList;
13
14use Symfony\Component\Form\FormConfigBuilder;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16use Symfony\Component\Form\Exception\InvalidConfigurationException;
17use Symfony\Component\Form\Exception\InvalidArgumentException;
18use Symfony\Component\Form\Extension\Core\View\ChoiceView;
19
20/**
21 * A choice list for choices of arbitrary data types.
22 *
23 * Choices and labels are passed in two arrays. The indices of the choices
24 * and the labels should match. Choices may also be given as hierarchy of
25 * unlimited depth by creating nested arrays. The title of the sub-hierarchy
26 * can be stored in the array key pointing to the nested array. The topmost
27 * level of the hierarchy may also be a \Traversable.
28 *
29 * <code>
30 * $choices = array(true, false);
31 * $labels = array('Agree', 'Disagree');
32 * $choiceList = new ChoiceList($choices, $labels);
33 * </code>
34 *
35 * @author Bernhard Schussek <bschussek@gmail.com>
36 */
37class ChoiceList implements ChoiceListInterface
38{
39 /**
40 * The choices with their indices as keys.
41 *
42 * @var array
43 */
44 private $choices = array();
45
46 /**
47 * The choice values with the indices of the matching choices as keys.
48 *
49 * @var array
50 */
51 private $values = array();
52
53 /**
54 * The preferred view objects as hierarchy containing also the choice groups
55 * with the indices of the matching choices as bottom-level keys.
56 *
57 * @var array
58 */
59 private $preferredViews = array();
60
61 /**
62 * The non-preferred view objects as hierarchy containing also the choice
63 * groups with the indices of the matching choices as bottom-level keys.
64 *
65 * @var array
66 */
67 private $remainingViews = array();
68
69 /**
70 * Creates a new choice list.
71 *
72 * @param array|\Traversable $choices The array of choices. Choices may also be given
73 * as hierarchy of unlimited depth. Hierarchies are
74 * created by creating nested arrays. The title of
75 * the sub-hierarchy can be stored in the array
76 * key pointing to the nested array. The topmost
77 * level of the hierarchy may also be a \Traversable.
78 * @param array $labels The array of labels. The structure of this array
79 * should match the structure of $choices.
80 * @param array $preferredChoices A flat array of choices that should be
81 * presented to the user with priority.
82 *
83 * @throws UnexpectedTypeException If the choices are not an array or \Traversable.
84 */
85 public function __construct($choices, array $labels, array $preferredChoices = array())
86 {
87 if (!is_array($choices) && !$choices instanceof \Traversable) {
88 throw new UnexpectedTypeException($choices, 'array or \Traversable');
89 }
90
91 $this->initialize($choices, $labels, $preferredChoices);
92 }
93
94 /**
95 * Initializes the list with choices.
96 *
97 * Safe to be called multiple times. The list is cleared on every call.
98 *
99 * @param array|\Traversable $choices The choices to write into the list.
100 * @param array $labels The labels belonging to the choices.
101 * @param array $preferredChoices The choices to display with priority.
102 */
103 protected function initialize($choices, array $labels, array $preferredChoices)
104 {
105 $this->choices = array();
106 $this->values = array();
107 $this->preferredViews = array();
108 $this->remainingViews = array();
109
110 $this->addChoices(
111 $this->preferredViews,
112 $this->remainingViews,
113 $choices,
114 $labels,
115 $preferredChoices
116 );
117 }
118
119 /**
120 * {@inheritdoc}
121 */
122 public function getChoices()
123 {
124 return $this->choices;
125 }
126
127 /**
128 * {@inheritdoc}
129 */
130 public function getValues()
131 {
132 return $this->values;
133 }
134
135 /**
136 * {@inheritdoc}
137 */
138 public function getPreferredViews()
139 {
140 return $this->preferredViews;
141 }
142
143 /**
144 * {@inheritdoc}
145 */
146 public function getRemainingViews()
147 {
148 return $this->remainingViews;
149 }
150
151 /**
152 * {@inheritdoc}
153 */
154 public function getChoicesForValues(array $values)
155 {
156 $values = $this->fixValues($values);
157 $choices = array();
158
159 foreach ($values as $j => $givenValue) {
160 foreach ($this->values as $i => $value) {
161 if ($value === $givenValue) {
162 $choices[] = $this->choices[$i];
163 unset($values[$j]);
164
165 if (0 === count($values)) {
166 break 2;
167 }
168 }
169 }
170 }
171
172 return $choices;
173 }
174
175 /**
176 * {@inheritdoc}
177 */
178 public function getValuesForChoices(array $choices)
179 {
180 $choices = $this->fixChoices($choices);
181 $values = array();
182
183 foreach ($this->choices as $i => $choice) {
184 foreach ($choices as $j => $givenChoice) {
185 if ($choice === $givenChoice) {
186 $values[] = $this->values[$i];
187 unset($choices[$j]);
188
189 if (0 === count($choices)) {
190 break 2;
191 }
192 }
193 }
194 }
195
196 return $values;
197 }
198
199 /**
200 * {@inheritdoc}
201 */
202 public function getIndicesForChoices(array $choices)
203 {
204 $choices = $this->fixChoices($choices);
205 $indices = array();
206
207 foreach ($this->choices as $i => $choice) {
208 foreach ($choices as $j => $givenChoice) {
209 if ($choice === $givenChoice) {
210 $indices[] = $i;
211 unset($choices[$j]);
212
213 if (0 === count($choices)) {
214 break 2;
215 }
216 }
217 }
218 }
219
220 return $indices;
221 }
222
223 /**
224 * {@inheritdoc}
225 */
226 public function getIndicesForValues(array $values)
227 {
228 $values = $this->fixValues($values);
229 $indices = array();
230
231 foreach ($this->values as $i => $value) {
232 foreach ($values as $j => $givenValue) {
233 if ($value === $givenValue) {
234 $indices[] = $i;
235 unset($values[$j]);
236
237 if (0 === count($values)) {
238 break 2;
239 }
240 }
241 }
242 }
243
244 return $indices;
245 }
246
247 /**
248 * Recursively adds the given choices to the list.
249 *
250 * @param array $bucketForPreferred The bucket where to store the preferred
251 * view objects.
252 * @param array $bucketForRemaining The bucket where to store the
253 * non-preferred view objects.
254 * @param array|\Traversable $choices The list of choices.
255 * @param array $labels The labels corresponding to the choices.
256 * @param array $preferredChoices The preferred choices.
257 *
258 * @throws InvalidArgumentException If the structures of the choices and labels array do not match.
259 * @throws InvalidConfigurationException If no valid value or index could be created for a choice.
260 */
261 protected function addChoices(array &$bucketForPreferred, array &$bucketForRemaining, $choices, array $labels, array $preferredChoices)
262 {
263 // Add choices to the nested buckets
264 foreach ($choices as $group => $choice) {
265 if (!array_key_exists($group, $labels)) {
266 throw new InvalidArgumentException('The structures of the choices and labels array do not match.');
267 }
268
269 if (is_array($choice)) {
270 // Don't do the work if the array is empty
271 if (count($choice) > 0) {
272 $this->addChoiceGroup(
273 $group,
274 $bucketForPreferred,
275 $bucketForRemaining,
276 $choice,
277 $labels[$group],
278 $preferredChoices
279 );
280 }
281 } else {
282 $this->addChoice(
283 $bucketForPreferred,
284 $bucketForRemaining,
285 $choice,
286 $labels[$group],
287 $preferredChoices
288 );
289 }
290 }
291 }
292
293 /**
294 * Recursively adds a choice group.
295 *
296 * @param string $group The name of the group.
297 * @param array $bucketForPreferred The bucket where to store the preferred
298 * view objects.
299 * @param array $bucketForRemaining The bucket where to store the
300 * non-preferred view objects.
301 * @param array $choices The list of choices in the group.
302 * @param array $labels The labels corresponding to the choices in the group.
303 * @param array $preferredChoices The preferred choices.
304 *
305 * @throws InvalidConfigurationException If no valid value or index could be created for a choice.
306 */
307 protected function addChoiceGroup($group, array &$bucketForPreferred, array &$bucketForRemaining, array $choices, array $labels, array $preferredChoices)
308 {
309 // If this is a choice group, create a new level in the choice
310 // key hierarchy
311 $bucketForPreferred[$group] = array();
312 $bucketForRemaining[$group] = array();
313
314 $this->addChoices(
315 $bucketForPreferred[$group],
316 $bucketForRemaining[$group],
317 $choices,
318 $labels,
319 $preferredChoices
320 );
321
322 // Remove child levels if empty
323 if (empty($bucketForPreferred[$group])) {
324 unset($bucketForPreferred[$group]);
325 }
326 if (empty($bucketForRemaining[$group])) {
327 unset($bucketForRemaining[$group]);
328 }
329 }
330
331 /**
332 * Adds a new choice.
333 *
334 * @param array $bucketForPreferred The bucket where to store the preferred
335 * view objects.
336 * @param array $bucketForRemaining The bucket where to store the
337 * non-preferred view objects.
338 * @param mixed $choice The choice to add.
339 * @param string $label The label for the choice.
340 * @param array $preferredChoices The preferred choices.
341 *
342 * @throws InvalidConfigurationException If no valid value or index could be created.
343 */
344 protected function addChoice(array &$bucketForPreferred, array &$bucketForRemaining, $choice, $label, array $preferredChoices)
345 {
346 $index = $this->createIndex($choice);
347
348 if ('' === $index || null === $index || !FormConfigBuilder::isValidName((string) $index)) {
349 throw new InvalidConfigurationException(sprintf('The index "%s" created by the choice list is invalid. It should be a valid, non-empty Form name.', $index));
350 }
351
352 $value = $this->createValue($choice);
353
354 if (!is_string($value)) {
355 throw new InvalidConfigurationException(sprintf('The value created by the choice list is of type "%s", but should be a string.', gettype($value)));
356 }
357
358 $view = new ChoiceView($choice, $value, $label);
359
360 $this->choices[$index] = $this->fixChoice($choice);
361 $this->values[$index] = $value;
362
363 if ($this->isPreferred($choice, $preferredChoices)) {
364 $bucketForPreferred[$index] = $view;
365 } else {
366 $bucketForRemaining[$index] = $view;
367 }
368 }
369
370 /**
371 * Returns whether the given choice should be preferred judging by the
372 * given array of preferred choices.
373 *
374 * Extension point to optimize performance by changing the structure of the
375 * $preferredChoices array.
376 *
377 * @param mixed $choice The choice to test.
378 * @param array $preferredChoices An array of preferred choices.
379 *
380 * @return Boolean Whether the choice is preferred.
381 */
382 protected function isPreferred($choice, array $preferredChoices)
383 {
384 return false !== array_search($choice, $preferredChoices, true);
385 }
386
387 /**
388 * Creates a new unique index for this choice.
389 *
390 * Extension point to change the indexing strategy.
391 *
392 * @param mixed $choice The choice to create an index for
393 *
394 * @return integer|string A unique index containing only ASCII letters,
395 * digits and underscores.
396 */
397 protected function createIndex($choice)
398 {
399 return count($this->choices);
400 }
401
402 /**
403 * Creates a new unique value for this choice.
404 *
405 * By default, an integer is generated since it cannot be guaranteed that
406 * all values in the list are convertible to (unique) strings. Subclasses
407 * can override this behaviour if they can guarantee this property.
408 *
409 * @param mixed $choice The choice to create a value for
410 *
411 * @return string A unique string.
412 */
413 protected function createValue($choice)
414 {
415 return (string) count($this->values);
416 }
417
418 /**
419 * Fixes the data type of the given choice value to avoid comparison
420 * problems.
421 *
422 * @param mixed $value The choice value.
423 *
424 * @return string The value as string.
425 */
426 protected function fixValue($value)
427 {
428 return (string) $value;
429 }
430
431 /**
432 * Fixes the data types of the given choice values to avoid comparison
433 * problems.
434 *
435 * @param array $values The choice values.
436 *
437 * @return array The values as strings.
438 */
439 protected function fixValues(array $values)
440 {
441 foreach ($values as $i => $value) {
442 $values[$i] = $this->fixValue($value);
443 }
444
445 return $values;
446 }
447
448 /**
449 * Fixes the data type of the given choice index to avoid comparison
450 * problems.
451 *
452 * @param mixed $index The choice index.
453 *
454 * @return integer|string The index as PHP array key.
455 */
456 protected function fixIndex($index)
457 {
458 if (is_bool($index) || (string) (int) $index === (string) $index) {
459 return (int) $index;
460 }
461
462 return (string) $index;
463 }
464
465 /**
466 * Fixes the data types of the given choice indices to avoid comparison
467 * problems.
468 *
469 * @param array $indices The choice indices.
470 *
471 * @return array The indices as strings.
472 */
473 protected function fixIndices(array $indices)
474 {
475 foreach ($indices as $i => $index) {
476 $indices[$i] = $this->fixIndex($index);
477 }
478
479 return $indices;
480 }
481
482 /**
483 * Fixes the data type of the given choice to avoid comparison problems.
484 *
485 * Extension point. In this implementation, choices are guaranteed to
486 * always maintain their type and thus can be typesafely compared.
487 *
488 * @param mixed $choice The choice.
489 *
490 * @return mixed The fixed choice.
491 */
492 protected function fixChoice($choice)
493 {
494 return $choice;
495 }
496
497 /**
498 * Fixes the data type of the given choices to avoid comparison problems.
499 *
500 * @param array $choices The choices.
501 *
502 * @return array The fixed choices.
503 *
504 * @see fixChoice
505 */
506 protected function fixChoices(array $choices)
507 {
508 return $choices;
509 }
510}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceListInterface.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceListInterface.php
new file mode 100644
index 00000000..099ace82
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceListInterface.php
@@ -0,0 +1,149 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\ChoiceList;
13
14/**
15 * Contains choices that can be selected in a form field.
16 *
17 * Each choice has three different properties:
18 *
19 * - Choice: The choice that should be returned to the application by the
20 * choice field. Can be any scalar value or an object, but no
21 * array.
22 * - Label: A text representing the choice that is displayed to the user.
23 * - Value: A uniquely identifying value that can contain arbitrary
24 * characters, but no arrays or objects. This value is displayed
25 * in the HTML "value" attribute.
26 *
27 * @author Bernhard Schussek <bschussek@gmail.com>
28 */
29interface ChoiceListInterface
30{
31 /**
32 * Returns the list of choices
33 *
34 * @return array The choices with their indices as keys
35 */
36 public function getChoices();
37
38 /**
39 * Returns the values for the choices
40 *
41 * @return array The values with the corresponding choice indices as keys
42 */
43 public function getValues();
44
45 /**
46 * Returns the choice views of the preferred choices as nested array with
47 * the choice groups as top-level keys.
48 *
49 * Example:
50 *
51 * <source>
52 * array(
53 * 'Group 1' => array(
54 * 10 => ChoiceView object,
55 * 20 => ChoiceView object,
56 * ),
57 * 'Group 2' => array(
58 * 30 => ChoiceView object,
59 * ),
60 * )
61 * </source>
62 *
63 * @return array A nested array containing the views with the corresponding
64 * choice indices as keys on the lowest levels and the choice
65 * group names in the keys of the higher levels
66 */
67 public function getPreferredViews();
68
69 /**
70 * Returns the choice views of the choices that are not preferred as nested
71 * array with the choice groups as top-level keys.
72 *
73 * Example:
74 *
75 * <source>
76 * array(
77 * 'Group 1' => array(
78 * 10 => ChoiceView object,
79 * 20 => ChoiceView object,
80 * ),
81 * 'Group 2' => array(
82 * 30 => ChoiceView object,
83 * ),
84 * )
85 * </source>
86 *
87 * @return array A nested array containing the views with the corresponding
88 * choice indices as keys on the lowest levels and the choice
89 * group names in the keys of the higher levels
90 *
91 * @see getPreferredValues
92 */
93 public function getRemainingViews();
94
95 /**
96 * Returns the choices corresponding to the given values.
97 *
98 * The choices can have any data type.
99 *
100 * @param array $values An array of choice values. Not existing values in
101 * this array are ignored
102 *
103 * @return array An array of choices with ascending, 0-based numeric keys
104 */
105 public function getChoicesForValues(array $values);
106
107 /**
108 * Returns the values corresponding to the given choices.
109 *
110 * The values must be strings.
111 *
112 * @param array $choices An array of choices. Not existing choices in this
113 * array are ignored
114 *
115 * @return array An array of choice values with ascending, 0-based numeric
116 * keys
117 */
118 public function getValuesForChoices(array $choices);
119
120 /**
121 * Returns the indices corresponding to the given choices.
122 *
123 * The indices must be positive integers or strings accepted by
124 * {@link FormConfigBuilder::validateName()}.
125 *
126 * The index "placeholder" is internally reserved.
127 *
128 * @param array $choices An array of choices. Not existing choices in this
129 * array are ignored
130 *
131 * @return array An array of indices with ascending, 0-based numeric keys
132 */
133 public function getIndicesForChoices(array $choices);
134
135 /**
136 * Returns the indices corresponding to the given values.
137 *
138 * The indices must be positive integers or strings accepted by
139 * {@link FormConfigBuilder::validateName()}.
140 *
141 * The index "placeholder" is internally reserved.
142 *
143 * @param array $values An array of choice values. Not existing values in
144 * this array are ignored
145 *
146 * @return array An array of indices with ascending, 0-based numeric keys
147 */
148 public function getIndicesForValues(array $values);
149}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/LazyChoiceList.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/LazyChoiceList.php
new file mode 100644
index 00000000..996f900c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/LazyChoiceList.php
@@ -0,0 +1,149 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\ChoiceList;
13
14use Symfony\Component\Form\Exception\InvalidArgumentException;
15
16/**
17 * A choice list that is loaded lazily
18 *
19 * This list loads itself as soon as any of the getters is accessed for the
20 * first time. You should implement loadChoiceList() in your child classes,
21 * which should return a ChoiceListInterface instance.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25abstract class LazyChoiceList implements ChoiceListInterface
26{
27 /**
28 * The loaded choice list
29 *
30 * @var ChoiceListInterface
31 */
32 private $choiceList;
33
34 /**
35 * {@inheritdoc}
36 */
37 public function getChoices()
38 {
39 if (!$this->choiceList) {
40 $this->load();
41 }
42
43 return $this->choiceList->getChoices();
44 }
45
46 /**
47 * {@inheritdoc}
48 */
49 public function getValues()
50 {
51 if (!$this->choiceList) {
52 $this->load();
53 }
54
55 return $this->choiceList->getValues();
56 }
57
58 /**
59 * {@inheritdoc}
60 */
61 public function getPreferredViews()
62 {
63 if (!$this->choiceList) {
64 $this->load();
65 }
66
67 return $this->choiceList->getPreferredViews();
68 }
69
70 /**
71 * {@inheritdoc}
72 */
73 public function getRemainingViews()
74 {
75 if (!$this->choiceList) {
76 $this->load();
77 }
78
79 return $this->choiceList->getRemainingViews();
80 }
81
82 /**
83 * {@inheritdoc}
84 */
85 public function getChoicesForValues(array $values)
86 {
87 if (!$this->choiceList) {
88 $this->load();
89 }
90
91 return $this->choiceList->getChoicesForValues($values);
92 }
93
94 /**
95 * {@inheritdoc}
96 */
97 public function getValuesForChoices(array $choices)
98 {
99 if (!$this->choiceList) {
100 $this->load();
101 }
102
103 return $this->choiceList->getValuesForChoices($choices);
104 }
105
106 /**
107 * {@inheritdoc}
108 */
109 public function getIndicesForChoices(array $choices)
110 {
111 if (!$this->choiceList) {
112 $this->load();
113 }
114
115 return $this->choiceList->getIndicesForChoices($choices);
116 }
117
118 /**
119 * {@inheritdoc}
120 */
121 public function getIndicesForValues(array $values)
122 {
123 if (!$this->choiceList) {
124 $this->load();
125 }
126
127 return $this->choiceList->getIndicesForValues($values);
128 }
129
130 /**
131 * Loads the choice list
132 *
133 * Should be implemented by child classes.
134 *
135 * @return ChoiceListInterface The loaded choice list
136 */
137 abstract protected function loadChoiceList();
138
139 private function load()
140 {
141 $choiceList = $this->loadChoiceList();
142
143 if (!$choiceList instanceof ChoiceListInterface) {
144 throw new InvalidArgumentException(sprintf('loadChoiceList() should return a ChoiceListInterface instance. Got %s', gettype($choiceList)));
145 }
146
147 $this->choiceList = $choiceList;
148 }
149}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php
new file mode 100644
index 00000000..0a153883
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php
@@ -0,0 +1,184 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5*
6* (c) Fabien Potencier <fabien@symfony.com>
7*
8* For the full copyright and license information, please view the LICENSE
9* file that was distributed with this source code.
10*/
11
12namespace Symfony\Component\Form\Extension\Core\ChoiceList;
13
14use Symfony\Component\Form\Exception\StringCastException;
15use Symfony\Component\Form\Exception\InvalidArgumentException;
16use Symfony\Component\PropertyAccess\PropertyPath;
17use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
18use Symfony\Component\PropertyAccess\PropertyAccess;
19use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
20
21/**
22 * A choice list for object choices.
23 *
24 * Supports generation of choice labels, choice groups and choice values
25 * by calling getters of the object (or associated objects).
26 *
27 * <code>
28 * $choices = array($user1, $user2);
29 *
30 * // call getName() to determine the choice labels
31 * $choiceList = new ObjectChoiceList($choices, 'name');
32 * </code>
33 *
34 * @author Bernhard Schussek <bschussek@gmail.com>
35 */
36class ObjectChoiceList extends ChoiceList
37{
38 /**
39 * @var PropertyAccessorInterface
40 */
41 private $propertyAccessor;
42
43 /**
44 * The property path used to obtain the choice label.
45 *
46 * @var PropertyPath
47 */
48 private $labelPath;
49
50 /**
51 * The property path used for object grouping.
52 *
53 * @var PropertyPath
54 */
55 private $groupPath;
56
57 /**
58 * The property path used to obtain the choice value.
59 *
60 * @var PropertyPath
61 */
62 private $valuePath;
63
64 /**
65 * Creates a new object choice list.
66 *
67 * @param array|\Traversable $choices The array of choices. Choices may also be given
68 * as hierarchy of unlimited depth by creating nested
69 * arrays. The title of the sub-hierarchy can be
70 * stored in the array key pointing to the nested
71 * array. The topmost level of the hierarchy may also
72 * be a \Traversable.
73 * @param string $labelPath A property path pointing to the property used
74 * for the choice labels. The value is obtained
75 * by calling the getter on the object. If the
76 * path is NULL, the object's __toString() method
77 * is used instead.
78 * @param array $preferredChoices A flat array of choices that should be
79 * presented to the user with priority.
80 * @param string $groupPath A property path pointing to the property used
81 * to group the choices. Only allowed if
82 * the choices are given as flat array.
83 * @param string $valuePath A property path pointing to the property used
84 * for the choice values. If not given, integers
85 * are generated instead.
86 * @param PropertyAccessorInterface $propertyAccessor The reflection graph for reading property paths.
87 */
88 public function __construct($choices, $labelPath = null, array $preferredChoices = array(), $groupPath = null, $valuePath = null, PropertyAccessorInterface $propertyAccessor = null)
89 {
90 $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor();
91 $this->labelPath = null !== $labelPath ? new PropertyPath($labelPath) : null;
92 $this->groupPath = null !== $groupPath ? new PropertyPath($groupPath) : null;
93 $this->valuePath = null !== $valuePath ? new PropertyPath($valuePath) : null;
94
95 parent::__construct($choices, array(), $preferredChoices);
96 }
97
98 /**
99 * Initializes the list with choices.
100 *
101 * Safe to be called multiple times. The list is cleared on every call.
102 *
103 * @param array|\Traversable $choices The choices to write into the list.
104 * @param array $labels Ignored.
105 * @param array $preferredChoices The choices to display with priority.
106 *
107 * @throws InvalidArgumentException When passing a hierarchy of choices and using
108 * the "groupPath" option at the same time.
109 */
110 protected function initialize($choices, array $labels, array $preferredChoices)
111 {
112 if (null !== $this->groupPath) {
113 $groupedChoices = array();
114
115 foreach ($choices as $i => $choice) {
116 if (is_array($choice)) {
117 throw new InvalidArgumentException('You should pass a plain object array (without groups) when using the "groupPath" option.');
118 }
119
120 try {
121 $group = $this->propertyAccessor->getValue($choice, $this->groupPath);
122 } catch (NoSuchPropertyException $e) {
123 // Don't group items whose group property does not exist
124 // see https://github.com/symfony/symfony/commit/d9b7abb7c7a0f28e0ce970afc5e305dce5dccddf
125 $group = null;
126 }
127
128 if (null === $group) {
129 $groupedChoices[$i] = $choice;
130 } else {
131 if (!isset($groupedChoices[$group])) {
132 $groupedChoices[$group] = array();
133 }
134
135 $groupedChoices[$group][$i] = $choice;
136 }
137 }
138
139 $choices = $groupedChoices;
140 }
141
142 $labels = array();
143
144 $this->extractLabels($choices, $labels);
145
146 parent::initialize($choices, $labels, $preferredChoices);
147 }
148
149 /**
150 * Creates a new unique value for this choice.
151 *
152 * If a property path for the value was given at object creation,
153 * the getter behind that path is now called to obtain a new value.
154 * Otherwise a new integer is generated.
155 *
156 * @param mixed $choice The choice to create a value for
157 *
158 * @return integer|string A unique value without character limitations.
159 */
160 protected function createValue($choice)
161 {
162 if ($this->valuePath) {
163 return (string) $this->propertyAccessor->getValue($choice, $this->valuePath);
164 }
165
166 return parent::createValue($choice);
167 }
168
169 private function extractLabels($choices, array &$labels)
170 {
171 foreach ($choices as $i => $choice) {
172 if (is_array($choice)) {
173 $labels[$i] = array();
174 $this->extractLabels($choice, $labels[$i]);
175 } elseif ($this->labelPath) {
176 $labels[$i] = $this->propertyAccessor->getValue($choice, $this->labelPath);
177 } elseif (method_exists($choice, '__toString')) {
178 $labels[$i] = (string) $choice;
179 } else {
180 throw new StringCastException(sprintf('A "__toString()" method was not found on the objects of type "%s" passed to the choice field. To read a custom getter instead, set the argument $labelPath to the desired property path.', get_class($choice)));
181 }
182 }
183 }
184}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/SimpleChoiceList.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/SimpleChoiceList.php
new file mode 100644
index 00000000..914dbe5f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/ChoiceList/SimpleChoiceList.php
@@ -0,0 +1,164 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\ChoiceList;
13
14/**
15 * A choice list for choices of type string or integer.
16 *
17 * Choices and their associated labels can be passed in a single array. Since
18 * choices are passed as array keys, only strings or integer choices are
19 * allowed. Choices may also be given as hierarchy of unlimited depth by
20 * creating nested arrays. The title of the sub-hierarchy can be stored in the
21 * array key pointing to the nested array.
22 *
23 * <code>
24 * $choiceList = new SimpleChoiceList(array(
25 * 'creditcard' => 'Credit card payment',
26 * 'cash' => 'Cash payment',
27 * ));
28 * </code>
29 *
30 * @author Bernhard Schussek <bschussek@gmail.com>
31 */
32class SimpleChoiceList extends ChoiceList
33{
34 /**
35 * Creates a new simple choice list.
36 *
37 * @param array $choices The array of choices with the choices as keys and
38 * the labels as values. Choices may also be given
39 * as hierarchy of unlimited depth by creating nested
40 * arrays. The title of the sub-hierarchy is stored
41 * in the array key pointing to the nested array.
42 * @param array $preferredChoices A flat array of choices that should be
43 * presented to the user with priority.
44 */
45 public function __construct(array $choices, array $preferredChoices = array())
46 {
47 // Flip preferred choices to speed up lookup
48 parent::__construct($choices, $choices, array_flip($preferredChoices));
49 }
50
51 /**
52 * {@inheritdoc}
53 */
54 public function getChoicesForValues(array $values)
55 {
56 $values = $this->fixValues($values);
57
58 // The values are identical to the choices, so we can just return them
59 // to improve performance a little bit
60 return $this->fixChoices(array_intersect($values, $this->getValues()));
61 }
62
63 /**
64 * {@inheritdoc}
65 */
66 public function getValuesForChoices(array $choices)
67 {
68 $choices = $this->fixChoices($choices);
69
70 // The choices are identical to the values, so we can just return them
71 // to improve performance a little bit
72 return $this->fixValues(array_intersect($choices, $this->getValues()));
73 }
74
75 /**
76 * Recursively adds the given choices to the list.
77 *
78 * Takes care of splitting the single $choices array passed in the
79 * constructor into choices and labels.
80 *
81 * @param array $bucketForPreferred The bucket where to store the preferred
82 * view objects.
83 * @param array $bucketForRemaining The bucket where to store the
84 * non-preferred view objects.
85 * @param array|\Traversable $choices The list of choices.
86 * @param array $labels Ignored.
87 * @param array $preferredChoices The preferred choices.
88 */
89 protected function addChoices(array &$bucketForPreferred, array &$bucketForRemaining, $choices, array $labels, array $preferredChoices)
90 {
91 // Add choices to the nested buckets
92 foreach ($choices as $choice => $label) {
93 if (is_array($label)) {
94 // Don't do the work if the array is empty
95 if (count($label) > 0) {
96 $this->addChoiceGroup(
97 $choice,
98 $bucketForPreferred,
99 $bucketForRemaining,
100 $label,
101 $label,
102 $preferredChoices
103 );
104 }
105 } else {
106 $this->addChoice(
107 $bucketForPreferred,
108 $bucketForRemaining,
109 $choice,
110 $label,
111 $preferredChoices
112 );
113 }
114 }
115 }
116
117 /**
118 * Returns whether the given choice should be preferred judging by the
119 * given array of preferred choices.
120 *
121 * Optimized for performance by treating the preferred choices as array
122 * where choices are stored in the keys.
123 *
124 * @param mixed $choice The choice to test.
125 * @param array $preferredChoices An array of preferred choices.
126 *
127 * @return Boolean Whether the choice is preferred.
128 */
129 protected function isPreferred($choice, array $preferredChoices)
130 {
131 // Optimize performance over the default implementation
132 return isset($preferredChoices[$choice]);
133 }
134
135 /**
136 * Converts the choice to a valid PHP array key.
137 *
138 * @param mixed $choice The choice.
139 *
140 * @return string|integer A valid PHP array key.
141 */
142 protected function fixChoice($choice)
143 {
144 return $this->fixIndex($choice);
145 }
146
147 /**
148 * {@inheritdoc}
149 */
150 protected function fixChoices(array $choices)
151 {
152 return $this->fixIndices($choices);
153 }
154
155 /**
156 * {@inheritdoc}
157 */
158 protected function createValue($choice)
159 {
160 // Choices are guaranteed to be unique and scalar, so we can simply
161 // convert them to strings
162 return (string) $choice;
163 }
164}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/CoreExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/CoreExtension.php
new file mode 100644
index 00000000..bbcac4ba
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/CoreExtension.php
@@ -0,0 +1,59 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core;
13
14use Symfony\Component\Form\AbstractExtension;
15use Symfony\Component\PropertyAccess\PropertyAccess;
16
17/**
18 * Represents the main form extension, which loads the core functionality.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class CoreExtension extends AbstractExtension
23{
24 protected function loadTypes()
25 {
26 return array(
27 new Type\FormType(PropertyAccess::getPropertyAccessor()),
28 new Type\BirthdayType(),
29 new Type\CheckboxType(),
30 new Type\ChoiceType(),
31 new Type\CollectionType(),
32 new Type\CountryType(),
33 new Type\DateType(),
34 new Type\DateTimeType(),
35 new Type\EmailType(),
36 new Type\HiddenType(),
37 new Type\IntegerType(),
38 new Type\LanguageType(),
39 new Type\LocaleType(),
40 new Type\MoneyType(),
41 new Type\NumberType(),
42 new Type\PasswordType(),
43 new Type\PercentType(),
44 new Type\RadioType(),
45 new Type\RepeatedType(),
46 new Type\SearchType(),
47 new Type\TextareaType(),
48 new Type\TextType(),
49 new Type\TimeType(),
50 new Type\TimezoneType(),
51 new Type\UrlType(),
52 new Type\FileType(),
53 new Type\ButtonType(),
54 new Type\SubmitType(),
55 new Type\ResetType(),
56 new Type\CurrencyType(),
57 );
58 }
59}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php
new file mode 100644
index 00000000..d8bd9c71
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php
@@ -0,0 +1,92 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataMapper;
13
14use Symfony\Component\Form\DataMapperInterface;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16use Symfony\Component\PropertyAccess\PropertyAccess;
17use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
18
19/**
20 * A data mapper using property paths to read/write data.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class PropertyPathMapper implements DataMapperInterface
25{
26 /**
27 * @var PropertyAccessorInterface
28 */
29 private $propertyAccessor;
30
31 /**
32 * Creates a new property path mapper.
33 *
34 * @param PropertyAccessorInterface $propertyAccessor
35 */
36 public function __construct(PropertyAccessorInterface $propertyAccessor = null)
37 {
38 $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor();
39 }
40
41 /**
42 * {@inheritdoc}
43 */
44 public function mapDataToForms($data, $forms)
45 {
46 if (null === $data || array() === $data) {
47 return;
48 }
49
50 if (!is_array($data) && !is_object($data)) {
51 throw new UnexpectedTypeException($data, 'object, array or empty');
52 }
53
54 foreach ($forms as $form) {
55 $propertyPath = $form->getPropertyPath();
56 $config = $form->getConfig();
57
58 if (null !== $propertyPath && $config->getMapped()) {
59 $form->setData($this->propertyAccessor->getValue($data, $propertyPath));
60 }
61 }
62 }
63
64 /**
65 * {@inheritdoc}
66 */
67 public function mapFormsToData($forms, &$data)
68 {
69 if (null === $data) {
70 return;
71 }
72
73 if (!is_array($data) && !is_object($data)) {
74 throw new UnexpectedTypeException($data, 'object, array or empty');
75 }
76
77 foreach ($forms as $form) {
78 $propertyPath = $form->getPropertyPath();
79 $config = $form->getConfig();
80
81 // Write-back is disabled if the form is not synchronized (transformation failed)
82 // and if the form is disabled (modification not allowed)
83 if (null !== $propertyPath && $config->getMapped() && $form->isSynchronized() && !$form->isDisabled()) {
84 // If the data is identical to the value in $data, we are
85 // dealing with a reference
86 if (!is_object($data) || !$config->getByReference() || $form->getData() !== $this->propertyAccessor->getValue($data, $propertyPath)) {
87 $this->propertyAccessor->setValue($data, $propertyPath, $form->getData());
88 }
89 }
90 }
91 }
92}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php
new file mode 100644
index 00000000..fc080f25
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php
@@ -0,0 +1,86 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class ArrayToPartsTransformer implements DataTransformerInterface
21{
22 private $partMapping;
23
24 public function __construct(array $partMapping)
25 {
26 $this->partMapping = $partMapping;
27 }
28
29 public function transform($array)
30 {
31 if (null === $array) {
32 $array = array();
33 }
34
35 if (!is_array($array) ) {
36 throw new TransformationFailedException('Expected an array.');
37 }
38
39 $result = array();
40
41 foreach ($this->partMapping as $partKey => $originalKeys) {
42 if (empty($array)) {
43 $result[$partKey] = null;
44 } else {
45 $result[$partKey] = array_intersect_key($array, array_flip($originalKeys));
46 }
47 }
48
49 return $result;
50 }
51
52 public function reverseTransform($array)
53 {
54 if (!is_array($array) ) {
55 throw new TransformationFailedException('Expected an array.');
56 }
57
58 $result = array();
59 $emptyKeys = array();
60
61 foreach ($this->partMapping as $partKey => $originalKeys) {
62 if (!empty($array[$partKey])) {
63 foreach ($originalKeys as $originalKey) {
64 if (isset($array[$partKey][$originalKey])) {
65 $result[$originalKey] = $array[$partKey][$originalKey];
66 }
67 }
68 } else {
69 $emptyKeys[] = $partKey;
70 }
71 }
72
73 if (count($emptyKeys) > 0) {
74 if (count($emptyKeys) === count($this->partMapping)) {
75 // All parts empty
76 return null;
77 }
78
79 throw new TransformationFailedException(
80 sprintf('The keys "%s" should not be empty', implode('", "', $emptyKeys)
81 ));
82 }
83
84 return $result;
85 }
86}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php
new file mode 100644
index 00000000..e4e8932e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php
@@ -0,0 +1,52 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17abstract class BaseDateTimeTransformer implements DataTransformerInterface
18{
19 protected static $formats = array(
20 \IntlDateFormatter::NONE,
21 \IntlDateFormatter::FULL,
22 \IntlDateFormatter::LONG,
23 \IntlDateFormatter::MEDIUM,
24 \IntlDateFormatter::SHORT,
25 );
26
27 protected $inputTimezone;
28
29 protected $outputTimezone;
30
31 /**
32 * Constructor.
33 *
34 * @param string $inputTimezone The name of the input timezone
35 * @param string $outputTimezone The name of the output timezone
36 *
37 * @throws UnexpectedTypeException if a timezone is not a string
38 */
39 public function __construct($inputTimezone = null, $outputTimezone = null)
40 {
41 if (!is_string($inputTimezone) && null !== $inputTimezone) {
42 throw new UnexpectedTypeException($inputTimezone, 'string');
43 }
44
45 if (!is_string($outputTimezone) && null !== $outputTimezone) {
46 throw new UnexpectedTypeException($outputTimezone, 'string');
47 }
48
49 $this->inputTimezone = $inputTimezone ?: date_default_timezone_get();
50 $this->outputTimezone = $outputTimezone ?: date_default_timezone_get();
51 }
52}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BooleanToStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BooleanToStringTransformer.php
new file mode 100644
index 00000000..95e7332d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/BooleanToStringTransformer.php
@@ -0,0 +1,85 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * Transforms between a Boolean and a string.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
22 */
23class BooleanToStringTransformer implements DataTransformerInterface
24{
25 /**
26 * The value emitted upon transform if the input is true
27 * @var string
28 */
29 private $trueValue;
30
31 /**
32 * Sets the value emitted upon transform if the input is true.
33 *
34 * @param string $trueValue
35 */
36 public function __construct($trueValue)
37 {
38 $this->trueValue = $trueValue;
39 }
40
41 /**
42 * Transforms a Boolean into a string.
43 *
44 * @param Boolean $value Boolean value.
45 *
46 * @return string String value.
47 *
48 * @throws TransformationFailedException If the given value is not a Boolean.
49 */
50 public function transform($value)
51 {
52 if (null === $value) {
53 return null;
54 }
55
56 if (!is_bool($value)) {
57 throw new TransformationFailedException('Expected a Boolean.');
58 }
59
60 return true === $value ? $this->trueValue : null;
61 }
62
63 /**
64 * Transforms a string into a Boolean.
65 *
66 * @param string $value String value.
67 *
68 * @return Boolean Boolean value.
69 *
70 * @throws TransformationFailedException If the given value is not a string.
71 */
72 public function reverseTransform($value)
73 {
74 if (null === $value) {
75 return false;
76 }
77
78 if (!is_string($value)) {
79 throw new TransformationFailedException('Expected a string.');
80 }
81
82 return true;
83 }
84
85}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToBooleanArrayTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToBooleanArrayTransformer.php
new file mode 100644
index 00000000..79b3f7ac
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToBooleanArrayTransformer.php
@@ -0,0 +1,118 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
15use Symfony\Component\Form\DataTransformerInterface;
16use Symfony\Component\Form\Exception\TransformationFailedException;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ChoiceToBooleanArrayTransformer implements DataTransformerInterface
22{
23 private $choiceList;
24
25 private $placeholderPresent;
26
27 /**
28 * Constructor.
29 *
30 * @param ChoiceListInterface $choiceList
31 * @param Boolean $placeholderPresent
32 */
33 public function __construct(ChoiceListInterface $choiceList, $placeholderPresent)
34 {
35 $this->choiceList = $choiceList;
36 $this->placeholderPresent = $placeholderPresent;
37 }
38
39 /**
40 * Transforms a single choice to a format appropriate for the nested
41 * checkboxes/radio buttons.
42 *
43 * The result is an array with the options as keys and true/false as values,
44 * depending on whether a given option is selected. If this field is rendered
45 * as select tag, the value is not modified.
46 *
47 * @param mixed $choice An array if "multiple" is set to true, a scalar
48 * value otherwise.
49 *
50 * @return mixed An array
51 *
52 * @throws TransformationFailedException If the given value is not scalar or
53 * if the choices can not be retrieved.
54 */
55 public function transform($choice)
56 {
57 try {
58 $values = $this->choiceList->getValues();
59 } catch (\Exception $e) {
60 throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
61 }
62
63 $index = current($this->choiceList->getIndicesForChoices(array($choice)));
64
65 foreach ($values as $i => $value) {
66 $values[$i] = $i === $index;
67 }
68
69 if ($this->placeholderPresent) {
70 $values['placeholder'] = false === $index;
71 }
72
73 return $values;
74 }
75
76 /**
77 * Transforms a checkbox/radio button array to a single choice.
78 *
79 * The input value is an array with the choices as keys and true/false as
80 * values, depending on whether a given choice is selected. The output
81 * is the selected choice.
82 *
83 * @param array $values An array of values
84 *
85 * @return mixed A scalar value
86 *
87 * @throws TransformationFailedException If the given value is not an array,
88 * if the recuperation of the choices
89 * fails or if some choice can't be
90 * found.
91 */
92 public function reverseTransform($values)
93 {
94 if (!is_array($values)) {
95 throw new TransformationFailedException('Expected an array.');
96 }
97
98 try {
99 $choices = $this->choiceList->getChoices();
100 } catch (\Exception $e) {
101 throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
102 }
103
104 foreach ($values as $i => $selected) {
105 if ($selected) {
106 if (isset($choices[$i])) {
107 return $choices[$i] === '' ? null : $choices[$i];
108 } elseif ($this->placeholderPresent && 'placeholder' === $i) {
109 return null;
110 } else {
111 throw new TransformationFailedException(sprintf('The choice "%s" does not exist', $i));
112 }
113 }
114 }
115
116 return null;
117 }
118}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php
new file mode 100644
index 00000000..5a818558
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php
@@ -0,0 +1,62 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ChoiceToValueTransformer implements DataTransformerInterface
22{
23 private $choiceList;
24
25 /**
26 * Constructor.
27 *
28 * @param ChoiceListInterface $choiceList
29 */
30 public function __construct(ChoiceListInterface $choiceList)
31 {
32 $this->choiceList = $choiceList;
33 }
34
35 public function transform($choice)
36 {
37 return (string) current($this->choiceList->getValuesForChoices(array($choice)));
38 }
39
40 public function reverseTransform($value)
41 {
42 if (null !== $value && !is_scalar($value)) {
43 throw new TransformationFailedException('Expected a scalar.');
44 }
45
46 // These are now valid ChoiceList values, so we can return null
47 // right away
48 if ('' === $value || null === $value) {
49 return null;
50 }
51
52 $choices = $this->choiceList->getChoicesForValues(array($value));
53
54 if (1 !== count($choices)) {
55 throw new TransformationFailedException(sprintf('The choice "%s" does not exist or is not unique', $value));
56 }
57
58 $choice = current($choices);
59
60 return '' === $choice ? null : $choice;
61 }
62}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToBooleanArrayTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToBooleanArrayTransformer.php
new file mode 100644
index 00000000..a13c0d4d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToBooleanArrayTransformer.php
@@ -0,0 +1,117 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
15use Symfony\Component\Form\DataTransformerInterface;
16use Symfony\Component\Form\Exception\TransformationFailedException;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ChoicesToBooleanArrayTransformer implements DataTransformerInterface
22{
23 private $choiceList;
24
25 public function __construct(ChoiceListInterface $choiceList)
26 {
27 $this->choiceList = $choiceList;
28 }
29
30 /**
31 * Transforms an array of choices to a format appropriate for the nested
32 * checkboxes/radio buttons.
33 *
34 * The result is an array with the options as keys and true/false as values,
35 * depending on whether a given option is selected. If this field is rendered
36 * as select tag, the value is not modified.
37 *
38 * @param mixed $array An array
39 *
40 * @return mixed An array
41 *
42 * @throws TransformationFailedException If the given value is not an array
43 * or if the choices can not be retrieved.
44 */
45 public function transform($array)
46 {
47 if (null === $array) {
48 return array();
49 }
50
51 if (!is_array($array)) {
52 throw new TransformationFailedException('Expected an array.');
53 }
54
55 try {
56 $values = $this->choiceList->getValues();
57 } catch (\Exception $e) {
58 throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
59 }
60
61 $indexMap = array_flip($this->choiceList->getIndicesForChoices($array));
62
63 foreach ($values as $i => $value) {
64 $values[$i] = isset($indexMap[$i]);
65 }
66
67 return $values;
68 }
69
70 /**
71 * Transforms a checkbox/radio button array to an array of choices.
72 *
73 * The input value is an array with the choices as keys and true/false as
74 * values, depending on whether a given choice is selected. The output
75 * is an array with the selected choices.
76 *
77 * @param mixed $values An array
78 *
79 * @return mixed An array
80 *
81 * @throws TransformationFailedException If the given value is not an array,
82 * if the recuperation of the choices
83 * fails or if some choice can't be
84 * found.
85 */
86 public function reverseTransform($values)
87 {
88 if (!is_array($values)) {
89 throw new TransformationFailedException('Expected an array.');
90 }
91
92 try {
93 $choices = $this->choiceList->getChoices();
94 } catch (\Exception $e) {
95 throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
96 }
97
98 $result = array();
99 $unknown = array();
100
101 foreach ($values as $i => $selected) {
102 if ($selected) {
103 if (isset($choices[$i])) {
104 $result[] = $choices[$i];
105 } else {
106 $unknown[] = $i;
107 }
108 }
109 }
110
111 if (count($unknown) > 0) {
112 throw new TransformationFailedException(sprintf('The choices "%s" were not found', implode('", "', $unknown)));
113 }
114
115 return $result;
116 }
117}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php
new file mode 100644
index 00000000..4492865e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php
@@ -0,0 +1,83 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16use Symfony\Component\Form\DataTransformerInterface;
17use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
18
19/**
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class ChoicesToValuesTransformer implements DataTransformerInterface
23{
24 private $choiceList;
25
26 /**
27 * Constructor.
28 *
29 * @param ChoiceListInterface $choiceList
30 */
31 public function __construct(ChoiceListInterface $choiceList)
32 {
33 $this->choiceList = $choiceList;
34 }
35
36 /**
37 * @param array $array
38 *
39 * @return array
40 *
41 * @throws TransformationFailedException If the given value is not an array.
42 */
43 public function transform($array)
44 {
45 if (null === $array) {
46 return array();
47 }
48
49 if (!is_array($array)) {
50 throw new TransformationFailedException('Expected an array.');
51 }
52
53 return $this->choiceList->getValuesForChoices($array);
54 }
55
56 /**
57 * @param array $array
58 *
59 * @return array
60 *
61 * @throws TransformationFailedException If the given value is not an array
62 * or if no matching choice could be
63 * found for some given value.
64 */
65 public function reverseTransform($array)
66 {
67 if (null === $array) {
68 return array();
69 }
70
71 if (!is_array($array)) {
72 throw new TransformationFailedException('Expected an array.');
73 }
74
75 $choices = $this->choiceList->getChoicesForValues($array);
76
77 if (count($choices) !== count($array)) {
78 throw new TransformationFailedException('Could not find all matching choices for the given values');
79 }
80
81 return $choices;
82 }
83}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php
new file mode 100644
index 00000000..9cc185e1
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php
@@ -0,0 +1,86 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * Passes a value through multiple value transformers
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class DataTransformerChain implements DataTransformerInterface
23{
24 /**
25 * The value transformers
26 * @var DataTransformerInterface[]
27 */
28 protected $transformers;
29
30 /**
31 * Uses the given value transformers to transform values
32 *
33 * @param array $transformers
34 */
35 public function __construct(array $transformers)
36 {
37 $this->transformers = $transformers;
38 }
39
40 /**
41 * Passes the value through the transform() method of all nested transformers
42 *
43 * The transformers receive the value in the same order as they were passed
44 * to the constructor. Each transformer receives the result of the previous
45 * transformer as input. The output of the last transformer is returned
46 * by this method.
47 *
48 * @param mixed $value The original value
49 *
50 * @return mixed The transformed value
51 *
52 * @throws TransformationFailedException
53 */
54 public function transform($value)
55 {
56 foreach ($this->transformers as $transformer) {
57 $value = $transformer->transform($value);
58 }
59
60 return $value;
61 }
62
63 /**
64 * Passes the value through the reverseTransform() method of all nested
65 * transformers
66 *
67 * The transformers receive the value in the reverse order as they were passed
68 * to the constructor. Each transformer receives the result of the previous
69 * transformer as input. The output of the last transformer is returned
70 * by this method.
71 *
72 * @param mixed $value The transformed value
73 *
74 * @return mixed The reverse-transformed value
75 *
76 * @throws TransformationFailedException
77 */
78 public function reverseTransform($value)
79 {
80 for ($i = count($this->transformers) - 1; $i >= 0; --$i) {
81 $value = $this->transformers[$i]->reverseTransform($value);
82 }
83
84 return $value;
85 }
86}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php
new file mode 100644
index 00000000..34af2820
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php
@@ -0,0 +1,184 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17/**
18 * Transforms between a normalized time and a localized time string/array.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
22 */
23class DateTimeToArrayTransformer extends BaseDateTimeTransformer
24{
25 private $pad;
26
27 private $fields;
28
29 /**
30 * Constructor.
31 *
32 * @param string $inputTimezone The input timezone
33 * @param string $outputTimezone The output timezone
34 * @param array $fields The date fields
35 * @param Boolean $pad Whether to use padding
36 *
37 * @throws UnexpectedTypeException if a timezone is not a string
38 */
39 public function __construct($inputTimezone = null, $outputTimezone = null, array $fields = null, $pad = false)
40 {
41 parent::__construct($inputTimezone, $outputTimezone);
42
43 if (null === $fields) {
44 $fields = array('year', 'month', 'day', 'hour', 'minute', 'second');
45 }
46
47 $this->fields = $fields;
48 $this->pad = (Boolean) $pad;
49 }
50
51 /**
52 * Transforms a normalized date into a localized date.
53 *
54 * @param \DateTime $dateTime Normalized date.
55 *
56 * @return array Localized date.
57 *
58 * @throws TransformationFailedException If the given value is not an
59 * instance of \DateTime or if the
60 * output timezone is not supported.
61 */
62 public function transform($dateTime)
63 {
64 if (null === $dateTime) {
65 return array_intersect_key(array(
66 'year' => '',
67 'month' => '',
68 'day' => '',
69 'hour' => '',
70 'minute' => '',
71 'second' => '',
72 ), array_flip($this->fields));
73 }
74
75 if (!$dateTime instanceof \DateTime) {
76 throw new TransformationFailedException('Expected a \DateTime.');
77 }
78
79 $dateTime = clone $dateTime;
80 if ($this->inputTimezone !== $this->outputTimezone) {
81 try {
82 $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
83 } catch (\Exception $e) {
84 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
85 }
86 }
87
88 $result = array_intersect_key(array(
89 'year' => $dateTime->format('Y'),
90 'month' => $dateTime->format('m'),
91 'day' => $dateTime->format('d'),
92 'hour' => $dateTime->format('H'),
93 'minute' => $dateTime->format('i'),
94 'second' => $dateTime->format('s'),
95 ), array_flip($this->fields));
96
97 if (!$this->pad) {
98 foreach ($result as &$entry) {
99 // remove leading zeros
100 $entry = (string) (int) $entry;
101 }
102 }
103
104 return $result;
105 }
106
107 /**
108 * Transforms a localized date into a normalized date.
109 *
110 * @param array $value Localized date
111 *
112 * @return \DateTime Normalized date
113 *
114 * @throws TransformationFailedException If the given value is not an array,
115 * if the value could not be transformed
116 * or if the input timezone is not
117 * supported.
118 */
119 public function reverseTransform($value)
120 {
121 if (null === $value) {
122 return null;
123 }
124
125 if (!is_array($value)) {
126 throw new TransformationFailedException('Expected an array.');
127 }
128
129 if ('' === implode('', $value)) {
130 return null;
131 }
132
133 $emptyFields = array();
134
135 foreach ($this->fields as $field) {
136 if (!isset($value[$field])) {
137 $emptyFields[] = $field;
138 }
139 }
140
141 if (count($emptyFields) > 0) {
142 throw new TransformationFailedException(
143 sprintf('The fields "%s" should not be empty', implode('", "', $emptyFields)
144 ));
145 }
146
147 if (isset($value['month']) && !ctype_digit($value['month']) && !is_int($value['month'])) {
148 throw new TransformationFailedException('This month is invalid');
149 }
150
151 if (isset($value['day']) && !ctype_digit($value['day']) && !is_int($value['day'])) {
152 throw new TransformationFailedException('This day is invalid');
153 }
154
155 if (isset($value['year']) && !ctype_digit($value['year']) && !is_int($value['year'])) {
156 throw new TransformationFailedException('This year is invalid');
157 }
158
159 if (!empty($value['month']) && !empty($value['day']) && !empty($value['year']) && false === checkdate($value['month'], $value['day'], $value['year'])) {
160 throw new TransformationFailedException('This is an invalid date');
161 }
162
163 try {
164 $dateTime = new \DateTime(sprintf(
165 '%s-%s-%s %s:%s:%s %s',
166 empty($value['year']) ? '1970' : $value['year'],
167 empty($value['month']) ? '1' : $value['month'],
168 empty($value['day']) ? '1' : $value['day'],
169 empty($value['hour']) ? '0' : $value['hour'],
170 empty($value['minute']) ? '0' : $value['minute'],
171 empty($value['second']) ? '0' : $value['second'],
172 $this->outputTimezone
173 ));
174
175 if ($this->inputTimezone !== $this->outputTimezone) {
176 $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
177 }
178 } catch (\Exception $e) {
179 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
180 }
181
182 return $dateTime;
183 }
184}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
new file mode 100644
index 00000000..d755e485
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
@@ -0,0 +1,169 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17/**
18 * Transforms between a normalized time and a localized time string
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
22 */
23class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
24{
25 private $dateFormat;
26 private $timeFormat;
27 private $pattern;
28 private $calendar;
29
30 /**
31 * Constructor.
32 *
33 * @see BaseDateTimeTransformer::formats for available format options
34 *
35 * @param string $inputTimezone The name of the input timezone
36 * @param string $outputTimezone The name of the output timezone
37 * @param integer $dateFormat The date format
38 * @param integer $timeFormat The time format
39 * @param integer $calendar One of the \IntlDateFormatter calendar constants
40 * @param string $pattern A pattern to pass to \IntlDateFormatter
41 *
42 * @throws UnexpectedTypeException If a format is not supported or if a timezone is not a string
43 */
44 public function __construct($inputTimezone = null, $outputTimezone = null, $dateFormat = null, $timeFormat = null, $calendar = \IntlDateFormatter::GREGORIAN, $pattern = null)
45 {
46 parent::__construct($inputTimezone, $outputTimezone);
47
48 if (null === $dateFormat) {
49 $dateFormat = \IntlDateFormatter::MEDIUM;
50 }
51
52 if (null === $timeFormat) {
53 $timeFormat = \IntlDateFormatter::SHORT;
54 }
55
56 if (!in_array($dateFormat, self::$formats, true)) {
57 throw new UnexpectedTypeException($dateFormat, implode('", "', self::$formats));
58 }
59
60 if (!in_array($timeFormat, self::$formats, true)) {
61 throw new UnexpectedTypeException($timeFormat, implode('", "', self::$formats));
62 }
63
64 $this->dateFormat = $dateFormat;
65 $this->timeFormat = $timeFormat;
66 $this->calendar = $calendar;
67 $this->pattern = $pattern;
68 }
69
70 /**
71 * Transforms a normalized date into a localized date string/array.
72 *
73 * @param \DateTime $dateTime Normalized date.
74 *
75 * @return string|array Localized date string/array.
76 *
77 * @throws TransformationFailedException If the given value is not an instance
78 * of \DateTime or if the date could not
79 * be transformed.
80 */
81 public function transform($dateTime)
82 {
83 if (null === $dateTime) {
84 return '';
85 }
86
87 if (!$dateTime instanceof \DateTime) {
88 throw new TransformationFailedException('Expected a \DateTime.');
89 }
90
91 // convert time to UTC before passing it to the formatter
92 $dateTime = clone $dateTime;
93 if ('UTC' !== $this->inputTimezone) {
94 $dateTime->setTimezone(new \DateTimeZone('UTC'));
95 }
96
97 $value = $this->getIntlDateFormatter()->format((int) $dateTime->format('U'));
98
99 if (intl_get_error_code() != 0) {
100 throw new TransformationFailedException(intl_get_error_message());
101 }
102
103 return $value;
104 }
105
106 /**
107 * Transforms a localized date string/array into a normalized date.
108 *
109 * @param string|array $value Localized date string/array
110 *
111 * @return \DateTime Normalized date
112 *
113 * @throws TransformationFailedException if the given value is not a string,
114 * if the date could not be parsed or
115 * if the input timezone is not supported
116 */
117 public function reverseTransform($value)
118 {
119 if (!is_string($value)) {
120 throw new TransformationFailedException('Expected a string.');
121 }
122
123 if ('' === $value) {
124 return null;
125 }
126
127 $timestamp = $this->getIntlDateFormatter()->parse($value);
128
129 if (intl_get_error_code() != 0) {
130 throw new TransformationFailedException(intl_get_error_message());
131 }
132
133 try {
134 // read timestamp into DateTime object - the formatter delivers in UTC
135 $dateTime = new \DateTime(sprintf('@%s UTC', $timestamp));
136 } catch (\Exception $e) {
137 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
138 }
139
140 if ('UTC' !== $this->inputTimezone) {
141 try {
142 $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
143 } catch (\Exception $e) {
144 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
145 }
146 }
147
148 return $dateTime;
149 }
150
151 /**
152 * Returns a preconfigured IntlDateFormatter instance
153 *
154 * @return \IntlDateFormatter
155 */
156 protected function getIntlDateFormatter()
157 {
158 $dateFormat = $this->dateFormat;
159 $timeFormat = $this->timeFormat;
160 $timezone = $this->outputTimezone;
161 $calendar = $this->calendar;
162 $pattern = $this->pattern;
163
164 $intlDateFormatter = new \IntlDateFormatter(\Locale::getDefault(), $dateFormat, $timeFormat, $timezone, $calendar, $pattern);
165 $intlDateFormatter->setLenient(false);
166
167 return $intlDateFormatter;
168 }
169}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php
new file mode 100644
index 00000000..0eb07422
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php
@@ -0,0 +1,82 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class DateTimeToRfc3339Transformer extends BaseDateTimeTransformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function transform($dateTime)
25 {
26 if (null === $dateTime) {
27 return '';
28 }
29
30 if (!$dateTime instanceof \DateTime) {
31 throw new TransformationFailedException('Expected a \DateTime.');
32 }
33
34 if ($this->inputTimezone !== $this->outputTimezone) {
35 $dateTime = clone $dateTime;
36 $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
37 }
38
39 return preg_replace('/\+00:00$/', 'Z', $dateTime->format('c'));
40 }
41
42 /**
43 * {@inheritDoc}
44 */
45 public function reverseTransform($rfc3339)
46 {
47 if (!is_string($rfc3339)) {
48 throw new TransformationFailedException('Expected a string.');
49 }
50
51 if ('' === $rfc3339) {
52 return null;
53 }
54
55 try {
56 $dateTime = new \DateTime($rfc3339);
57 } catch (\Exception $e) {
58 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
59 }
60
61 if ($this->outputTimezone !== $this->inputTimezone) {
62 try {
63 $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
64 } catch (\Exception $e) {
65 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
66 }
67 }
68
69 if (preg_match('/(\d{4})-(\d{2})-(\d{2})/', $rfc3339, $matches)) {
70 if (!checkdate($matches[2], $matches[3], $matches[1])) {
71 throw new TransformationFailedException(sprintf(
72 'The date "%s-%s-%s" is not a valid date.',
73 $matches[1],
74 $matches[2],
75 $matches[3]
76 ));
77 }
78 }
79
80 return $dateTime;
81 }
82}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
new file mode 100644
index 00000000..131f45cb
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
@@ -0,0 +1,231 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17/**
18 * Transforms between a date string and a DateTime object
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
22 */
23class DateTimeToStringTransformer extends BaseDateTimeTransformer
24{
25 /**
26 * Format used for generating strings
27 * @var string
28 */
29 private $generateFormat;
30
31 /**
32 * Format used for parsing strings
33 *
34 * Different than the {@link $generateFormat} because formats for parsing
35 * support additional characters in PHP that are not supported for
36 * generating strings.
37 *
38 * @var string
39 */
40 private $parseFormat;
41
42 /**
43 * Whether to parse by appending a pipe "|" to the parse format.
44 *
45 * This only works as of PHP 5.3.7.
46 *
47 * @var Boolean
48 */
49 private $parseUsingPipe;
50
51 /**
52 * Transforms a \DateTime instance to a string
53 *
54 * @see \DateTime::format() for supported formats
55 *
56 * @param string $inputTimezone The name of the input timezone
57 * @param string $outputTimezone The name of the output timezone
58 * @param string $format The date format
59 * @param Boolean $parseUsingPipe Whether to parse by appending a pipe "|" to the parse format
60 *
61 * @throws UnexpectedTypeException if a timezone is not a string
62 */
63 public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s', $parseUsingPipe = null)
64 {
65 parent::__construct($inputTimezone, $outputTimezone);
66
67 $this->generateFormat = $this->parseFormat = $format;
68
69 // The pipe in the parser pattern only works as of PHP 5.3.7
70 // See http://bugs.php.net/54316
71 $this->parseUsingPipe = null === $parseUsingPipe
72 ? version_compare(phpversion(), '5.3.7', '>=')
73 : $parseUsingPipe;
74
75 // See http://php.net/manual/en/datetime.createfromformat.php
76 // The character "|" in the format makes sure that the parts of a date
77 // that are *not* specified in the format are reset to the corresponding
78 // values from 1970-01-01 00:00:00 instead of the current time.
79 // Without "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 12:32:47",
80 // where the time corresponds to the current server time.
81 // With "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 00:00:00",
82 // which is at least deterministic and thus used here.
83 if ($this->parseUsingPipe && false === strpos($this->parseFormat, '|')) {
84 $this->parseFormat .= '|';
85 }
86 }
87
88 /**
89 * Transforms a DateTime object into a date string with the configured format
90 * and timezone
91 *
92 * @param \DateTime $value A DateTime object
93 *
94 * @return string A value as produced by PHP's date() function
95 *
96 * @throws TransformationFailedException If the given value is not a \DateTime
97 * instance or if the output timezone
98 * is not supported.
99 */
100 public function transform($value)
101 {
102 if (null === $value) {
103 return '';
104 }
105
106 if (!$value instanceof \DateTime) {
107 throw new TransformationFailedException('Expected a \DateTime.');
108 }
109
110 $value = clone $value;
111 try {
112 $value->setTimezone(new \DateTimeZone($this->outputTimezone));
113 } catch (\Exception $e) {
114 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
115 }
116
117 return $value->format($this->generateFormat);
118 }
119
120 /**
121 * Transforms a date string in the configured timezone into a DateTime object.
122 *
123 * @param string $value A value as produced by PHP's date() function
124 *
125 * @return \DateTime An instance of \DateTime
126 *
127 * @throws TransformationFailedException If the given value is not a string,
128 * if the date could not be parsed or
129 * if the input timezone is not supported.
130 */
131 public function reverseTransform($value)
132 {
133 if (empty($value)) {
134 return null;
135 }
136
137 if (!is_string($value)) {
138 throw new TransformationFailedException('Expected a string.');
139 }
140
141 try {
142 $outputTz = new \DateTimeZone($this->outputTimezone);
143 $dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);
144
145 $lastErrors = \DateTime::getLastErrors();
146
147 if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) {
148 throw new TransformationFailedException(
149 implode(', ', array_merge(
150 array_values($lastErrors['warnings']),
151 array_values($lastErrors['errors'])
152 ))
153 );
154 }
155
156 // On PHP versions < 5.3.7 we need to emulate the pipe operator
157 // and reset parts not given in the format to their equivalent
158 // of the UNIX base timestamp.
159 if (!$this->parseUsingPipe) {
160 list($year, $month, $day, $hour, $minute, $second) = explode('-', $dateTime->format('Y-m-d-H-i-s'));
161
162 // Check which of the date parts are present in the pattern
163 preg_match(
164 '/(' .
165 '(?P<day>[djDl])|' .
166 '(?P<month>[FMmn])|' .
167 '(?P<year>[Yy])|' .
168 '(?P<hour>[ghGH])|' .
169 '(?P<minute>i)|' .
170 '(?P<second>s)|' .
171 '(?P<dayofyear>z)|' .
172 '(?P<timestamp>U)|' .
173 '[^djDlFMmnYyghGHiszU]' .
174 ')*/',
175 $this->parseFormat,
176 $matches
177 );
178
179 // preg_match() does not guarantee to set all indices, so
180 // set them unless given
181 $matches = array_merge(array(
182 'day' => false,
183 'month' => false,
184 'year' => false,
185 'hour' => false,
186 'minute' => false,
187 'second' => false,
188 'dayofyear' => false,
189 'timestamp' => false,
190 ), $matches);
191
192 // Reset all parts that don't exist in the format to the
193 // corresponding part of the UNIX base timestamp
194 if (!$matches['timestamp']) {
195 if (!$matches['dayofyear']) {
196 if (!$matches['day']) {
197 $day = 1;
198 }
199 if (!$matches['month']) {
200 $month = 1;
201 }
202 }
203 if (!$matches['year']) {
204 $year = 1970;
205 }
206 if (!$matches['hour']) {
207 $hour = 0;
208 }
209 if (!$matches['minute']) {
210 $minute = 0;
211 }
212 if (!$matches['second']) {
213 $second = 0;
214 }
215 $dateTime->setDate($year, $month, $day);
216 $dateTime->setTime($hour, $minute, $second);
217 }
218 }
219
220 if ($this->inputTimezone !== $this->outputTimezone) {
221 $dateTime->setTimeZone(new \DateTimeZone($this->inputTimezone));
222 }
223 } catch (TransformationFailedException $e) {
224 throw $e;
225 } catch (\Exception $e) {
226 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
227 }
228
229 return $dateTime;
230 }
231}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php
new file mode 100644
index 00000000..d2ca6604
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToTimestampTransformer.php
@@ -0,0 +1,89 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16/**
17 * Transforms between a timestamp and a DateTime object
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
21 */
22class DateTimeToTimestampTransformer extends BaseDateTimeTransformer
23{
24 /**
25 * Transforms a DateTime object into a timestamp in the configured timezone.
26 *
27 * @param \DateTime $value A \DateTime object
28 *
29 * @return integer A timestamp
30 *
31 * @throws TransformationFailedException If the given value is not an instance
32 * of \DateTime or if the output
33 * timezone is not supported.
34 */
35 public function transform($value)
36 {
37 if (null === $value) {
38 return null;
39 }
40
41 if (!$value instanceof \DateTime) {
42 throw new TransformationFailedException('Expected a \DateTime.');
43 }
44
45 $value = clone $value;
46 try {
47 $value->setTimezone(new \DateTimeZone($this->outputTimezone));
48 } catch (\Exception $e) {
49 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
50 }
51
52 return (int) $value->format('U');
53 }
54
55 /**
56 * Transforms a timestamp in the configured timezone into a DateTime object
57 *
58 * @param string $value A timestamp
59 *
60 * @return \DateTime A \DateTime object
61 *
62 * @throws TransformationFailedException If the given value is not a timestamp
63 * or if the given timestamp is invalid.
64 */
65 public function reverseTransform($value)
66 {
67 if (null === $value) {
68 return null;
69 }
70
71 if (!is_numeric($value)) {
72 throw new TransformationFailedException('Expected a numeric.');
73 }
74
75 try {
76 $dateTime = new \DateTime();
77 $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
78 $dateTime->setTimestamp($value);
79
80 if ($this->inputTimezone !== $this->outputTimezone) {
81 $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
82 }
83 } catch (\Exception $e) {
84 throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
85 }
86
87 return $dateTime;
88 }
89}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
new file mode 100644
index 00000000..6bb48a9a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
@@ -0,0 +1,53 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16/**
17 * Transforms between an integer and a localized number with grouping
18 * (each thousand) and comma separators.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class IntegerToLocalizedStringTransformer extends NumberToLocalizedStringTransformer
23{
24 /**
25 * {@inheritDoc}
26 */
27 public function reverseTransform($value)
28 {
29 if (!is_string($value)) {
30 throw new TransformationFailedException('Expected a string.');
31 }
32
33 if ('' === $value) {
34 return null;
35 }
36
37 if ('NaN' === $value) {
38 throw new TransformationFailedException('"NaN" is not a valid integer');
39 }
40
41 $formatter = $this->getNumberFormatter();
42 $value = $formatter->parse(
43 $value,
44 PHP_INT_SIZE == 8 ? $formatter::TYPE_INT64 : $formatter::TYPE_INT32
45 );
46
47 if (intl_is_failure($formatter->getErrorCode())) {
48 throw new TransformationFailedException($formatter->getErrorMessage());
49 }
50
51 return $value;
52 }
53}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php
new file mode 100644
index 00000000..5b8e9d96
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php
@@ -0,0 +1,90 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Exception\TransformationFailedException;
15
16/**
17 * Transforms between a normalized format and a localized money string.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
21 */
22class MoneyToLocalizedStringTransformer extends NumberToLocalizedStringTransformer
23{
24
25 private $divisor;
26
27 public function __construct($precision = null, $grouping = null, $roundingMode = null, $divisor = null)
28 {
29 if (null === $grouping) {
30 $grouping = true;
31 }
32
33 if (null === $precision) {
34 $precision = 2;
35 }
36
37 parent::__construct($precision, $grouping, $roundingMode);
38
39 if (null === $divisor) {
40 $divisor = 1;
41 }
42
43 $this->divisor = $divisor;
44 }
45
46 /**
47 * Transforms a normalized format into a localized money string.
48 *
49 * @param number $value Normalized number
50 *
51 * @return string Localized money string.
52 *
53 * @throws TransformationFailedException If the given value is not numeric or
54 * if the value can not be transformed.
55 */
56 public function transform($value)
57 {
58 if (null !== $value) {
59 if (!is_numeric($value)) {
60 throw new TransformationFailedException('Expected a numeric.');
61 }
62
63 $value /= $this->divisor;
64 }
65
66 return parent::transform($value);
67 }
68
69 /**
70 * Transforms a localized money string into a normalized format.
71 *
72 * @param string $value Localized money string
73 *
74 * @return number Normalized number
75 *
76 * @throws TransformationFailedException If the given value is not a string
77 * or if the value can not be transformed.
78 */
79 public function reverseTransform($value)
80 {
81 $value = parent::reverseTransform($value);
82
83 if (null !== $value) {
84 $value *= $this->divisor;
85 }
86
87 return $value;
88 }
89
90}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
new file mode 100644
index 00000000..b0c59b3e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
@@ -0,0 +1,184 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * Transforms between a number type and a localized number with grouping
19 * (each thousand) and comma separators.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
23 */
24class NumberToLocalizedStringTransformer implements DataTransformerInterface
25{
26 const ROUND_FLOOR = \NumberFormatter::ROUND_FLOOR;
27 const ROUND_DOWN = \NumberFormatter::ROUND_DOWN;
28 const ROUND_HALFDOWN = \NumberFormatter::ROUND_HALFDOWN;
29 const ROUND_HALFEVEN = \NumberFormatter::ROUND_HALFEVEN;
30 const ROUND_HALFUP = \NumberFormatter::ROUND_HALFUP;
31 const ROUND_UP = \NumberFormatter::ROUND_UP;
32 const ROUND_CEILING = \NumberFormatter::ROUND_CEILING;
33
34 protected $precision;
35
36 protected $grouping;
37
38 protected $roundingMode;
39
40 public function __construct($precision = null, $grouping = null, $roundingMode = null)
41 {
42 if (null === $grouping) {
43 $grouping = false;
44 }
45
46 if (null === $roundingMode) {
47 $roundingMode = self::ROUND_HALFUP;
48 }
49
50 $this->precision = $precision;
51 $this->grouping = $grouping;
52 $this->roundingMode = $roundingMode;
53 }
54
55 /**
56 * Transforms a number type into localized number.
57 *
58 * @param integer|float $value Number value.
59 *
60 * @return string Localized value.
61 *
62 * @throws TransformationFailedException If the given value is not numeric
63 * or if the value can not be transformed.
64 */
65 public function transform($value)
66 {
67 if (null === $value) {
68 return '';
69 }
70
71 if (!is_numeric($value)) {
72 throw new TransformationFailedException('Expected a numeric.');
73 }
74
75 $formatter = $this->getNumberFormatter();
76 $value = $formatter->format($value);
77
78 if (intl_is_failure($formatter->getErrorCode())) {
79 throw new TransformationFailedException($formatter->getErrorMessage());
80 }
81
82 // Convert fixed spaces to normal ones
83 $value = str_replace("\xc2\xa0", ' ', $value);
84
85 return $value;
86 }
87
88 /**
89 * Transforms a localized number into an integer or float
90 *
91 * @param string $value The localized value
92 *
93 * @return integer|float The numeric value
94 *
95 * @throws TransformationFailedException If the given value is not a string
96 * or if the value can not be transformed.
97 */
98 public function reverseTransform($value)
99 {
100 if (!is_string($value)) {
101 throw new TransformationFailedException('Expected a string.');
102 }
103
104 if ('' === $value) {
105 return null;
106 }
107
108 if ('NaN' === $value) {
109 throw new TransformationFailedException('"NaN" is not a valid number');
110 }
111
112 $position = 0;
113 $formatter = $this->getNumberFormatter();
114 $groupSep = $formatter->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL);
115 $decSep = $formatter->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
116
117 if ('.' !== $decSep && (!$this->grouping || '.' !== $groupSep)) {
118 $value = str_replace('.', $decSep, $value);
119 }
120
121 if (',' !== $decSep && (!$this->grouping || ',' !== $groupSep)) {
122 $value = str_replace(',', $decSep, $value);
123 }
124
125 $result = $formatter->parse($value, \NumberFormatter::TYPE_DOUBLE, $position);
126
127 if (intl_is_failure($formatter->getErrorCode())) {
128 throw new TransformationFailedException($formatter->getErrorMessage());
129 }
130
131 if ($result >= PHP_INT_MAX || $result <= -PHP_INT_MAX) {
132 throw new TransformationFailedException('I don\'t have a clear idea what infinity looks like');
133 }
134
135 if (function_exists('mb_detect_encoding') && false !== $encoding = mb_detect_encoding($value)) {
136 $strlen = function ($string) use ($encoding) {
137 return mb_strlen($string, $encoding);
138 };
139 $substr = function ($string, $offset, $length) use ($encoding) {
140 return mb_substr($string, $offset, $length, $encoding);
141 };
142 } else {
143 $strlen = 'strlen';
144 $substr = 'substr';
145 }
146
147 $length = $strlen($value);
148
149 // After parsing, position holds the index of the character where the
150 // parsing stopped
151 if ($position < $length) {
152 // Check if there are unrecognized characters at the end of the
153 // number (excluding whitespace characters)
154 $remainder = trim($substr($value, $position, $length), " \t\n\r\0\x0b\xc2\xa0");
155
156 if ('' !== $remainder) {
157 throw new TransformationFailedException(
158 sprintf('The number contains unrecognized characters: "%s"', $remainder)
159 );
160 }
161 }
162
163 return $result;
164 }
165
166 /**
167 * Returns a preconfigured \NumberFormatter instance
168 *
169 * @return \NumberFormatter
170 */
171 protected function getNumberFormatter()
172 {
173 $formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL);
174
175 if (null !== $this->precision) {
176 $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->precision);
177 $formatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $this->roundingMode);
178 }
179
180 $formatter->setAttribute(\NumberFormatter::GROUPING_USED, $this->grouping);
181
182 return $formatter;
183 }
184}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php
new file mode 100644
index 00000000..e099d436
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php
@@ -0,0 +1,149 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16use Symfony\Component\Form\Exception\UnexpectedTypeException;
17
18/**
19 * Transforms between a normalized format (integer or float) and a percentage value.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
23 */
24class PercentToLocalizedStringTransformer implements DataTransformerInterface
25{
26 const FRACTIONAL = 'fractional';
27 const INTEGER = 'integer';
28
29 protected static $types = array(
30 self::FRACTIONAL,
31 self::INTEGER,
32 );
33
34 private $type;
35
36 private $precision;
37
38 /**
39 * Constructor.
40 *
41 * @see self::$types for a list of supported types
42 *
43 * @param integer $precision The precision
44 * @param string $type One of the supported types
45 *
46 * @throws UnexpectedTypeException if the given value of type is unknown
47 */
48 public function __construct($precision = null, $type = null)
49 {
50 if (null === $precision) {
51 $precision = 0;
52 }
53
54 if (null === $type) {
55 $type = self::FRACTIONAL;
56 }
57
58 if (!in_array($type, self::$types, true)) {
59 throw new UnexpectedTypeException($type, implode('", "', self::$types));
60 }
61
62 $this->type = $type;
63 $this->precision = $precision;
64 }
65
66 /**
67 * Transforms between a normalized format (integer or float) into a percentage value.
68 *
69 * @param number $value Normalized value
70 *
71 * @return number Percentage value
72 *
73 * @throws TransformationFailedException If the given value is not numeric or
74 * if the value could not be transformed.
75 */
76 public function transform($value)
77 {
78 if (null === $value) {
79 return '';
80 }
81
82 if (!is_numeric($value)) {
83 throw new TransformationFailedException('Expected a numeric.');
84 }
85
86 if (self::FRACTIONAL == $this->type) {
87 $value *= 100;
88 }
89
90 $formatter = $this->getNumberFormatter();
91 $value = $formatter->format($value);
92
93 if (intl_is_failure($formatter->getErrorCode())) {
94 throw new TransformationFailedException($formatter->getErrorMessage());
95 }
96
97 // replace the UTF-8 non break spaces
98 return $value;
99 }
100
101 /**
102 * Transforms between a percentage value into a normalized format (integer or float).
103 *
104 * @param number $value Percentage value.
105 *
106 * @return number Normalized value.
107 *
108 * @throws TransformationFailedException If the given value is not a string or
109 * if the value could not be transformed.
110 */
111 public function reverseTransform($value)
112 {
113 if (!is_string($value)) {
114 throw new TransformationFailedException('Expected a string.');
115 }
116
117 if ('' === $value) {
118 return null;
119 }
120
121 $formatter = $this->getNumberFormatter();
122 // replace normal spaces so that the formatter can read them
123 $value = $formatter->parse(str_replace(' ', ' ', $value));
124
125 if (intl_is_failure($formatter->getErrorCode())) {
126 throw new TransformationFailedException($formatter->getErrorMessage());
127 }
128
129 if (self::FRACTIONAL == $this->type) {
130 $value /= 100;
131 }
132
133 return $value;
134 }
135
136 /**
137 * Returns a preconfigured \NumberFormatter instance
138 *
139 * @return \NumberFormatter
140 */
141 protected function getNumberFormatter()
142 {
143 $formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL);
144
145 $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->precision);
146
147 return $formatter;
148 }
149}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php
new file mode 100644
index 00000000..c34a0139
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php
@@ -0,0 +1,91 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class ValueToDuplicatesTransformer implements DataTransformerInterface
21{
22 private $keys;
23
24 public function __construct(array $keys)
25 {
26 $this->keys = $keys;
27 }
28
29 /**
30 * Duplicates the given value through the array.
31 *
32 * @param mixed $value The value
33 *
34 * @return array The array
35 */
36 public function transform($value)
37 {
38 $result = array();
39
40 foreach ($this->keys as $key) {
41 $result[$key] = $value;
42 }
43
44 return $result;
45 }
46
47 /**
48 * Extracts the duplicated value from an array.
49 *
50 * @param array $array
51 *
52 * @return mixed The value
53 *
54 * @throws TransformationFailedException If the given value is not an array or
55 * if the given array can not be transformed.
56 */
57 public function reverseTransform($array)
58 {
59 if (!is_array($array)) {
60 throw new TransformationFailedException('Expected an array.');
61 }
62
63 $result = current($array);
64 $emptyKeys = array();
65
66 foreach ($this->keys as $key) {
67 if (!empty($array[$key])) {
68 if ($array[$key] !== $result) {
69 throw new TransformationFailedException(
70 'All values in the array should be the same'
71 );
72 }
73 } else {
74 $emptyKeys[] = $key;
75 }
76 }
77
78 if (count($emptyKeys) > 0) {
79 if (count($emptyKeys) == count($this->keys)) {
80 // All keys empty
81 return null;
82 }
83
84 throw new TransformationFailedException(
85 sprintf('The keys "%s" should not be empty', implode('", "', $emptyKeys)
86 ));
87 }
88
89 return $result;
90 }
91}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixCheckboxInputListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixCheckboxInputListener.php
new file mode 100644
index 00000000..1f62e060
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixCheckboxInputListener.php
@@ -0,0 +1,62 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
18
19/**
20 * Takes care of converting the input from a list of checkboxes to a correctly
21 * indexed array.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class FixCheckboxInputListener implements EventSubscriberInterface
26{
27 private $choiceList;
28
29 /**
30 * Constructor.
31 *
32 * @param ChoiceListInterface $choiceList
33 */
34 public function __construct(ChoiceListInterface $choiceList)
35 {
36 $this->choiceList = $choiceList;
37 }
38
39 public function preSubmit(FormEvent $event)
40 {
41 $values = (array) $event->getData();
42 $indices = $this->choiceList->getIndicesForValues($values);
43
44 $event->setData(count($indices) > 0 ? array_combine($indices, $values) : array());
45 }
46
47 /**
48 * Alias of {@link preSubmit()}.
49 *
50 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
51 * {@link preSubmit()} instead.
52 */
53 public function preBind(FormEvent $event)
54 {
55 $this->preSubmit($event);
56 }
57
58 public static function getSubscribedEvents()
59 {
60 return array(FormEvents::PRE_SUBMIT => 'preSubmit');
61 }
62}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixRadioInputListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixRadioInputListener.php
new file mode 100644
index 00000000..bf03792f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixRadioInputListener.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
18
19/**
20 * Takes care of converting the input from a single radio button
21 * to an array.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class FixRadioInputListener implements EventSubscriberInterface
26{
27 private $choiceList;
28
29 private $placeholderPresent;
30
31 /**
32 * Constructor.
33 *
34 * @param ChoiceListInterface $choiceList
35 * @param Boolean $placeholderPresent
36 */
37 public function __construct(ChoiceListInterface $choiceList, $placeholderPresent)
38 {
39 $this->choiceList = $choiceList;
40 $this->placeholderPresent = $placeholderPresent;
41 }
42
43 public function preSubmit(FormEvent $event)
44 {
45 $value = $event->getData();
46 $index = current($this->choiceList->getIndicesForValues(array($value)));
47
48 $event->setData(false !== $index ? array($index => $value) : ($this->placeholderPresent ? array('placeholder' => '') : array())) ;
49 }
50
51 /**
52 * Alias of {@link preSubmit()}.
53 *
54 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
55 * {@link preSubmit()} instead.
56 */
57 public function preBind(FormEvent $event)
58 {
59 $this->preSubmit($event);
60 }
61
62 public static function getSubscribedEvents()
63 {
64 return array(FormEvents::PRE_SUBMIT => 'preSubmit');
65 }
66}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php
new file mode 100644
index 00000000..e25dacf2
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php
@@ -0,0 +1,56 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
18/**
19 * Adds a protocol to a URL if it doesn't already have one.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class FixUrlProtocolListener implements EventSubscriberInterface
24{
25 private $defaultProtocol;
26
27 public function __construct($defaultProtocol = 'http')
28 {
29 $this->defaultProtocol = $defaultProtocol;
30 }
31
32 public function onSubmit(FormEvent $event)
33 {
34 $data = $event->getData();
35
36 if ($this->defaultProtocol && $data && !preg_match('~^\w+://~', $data)) {
37 $event->setData($this->defaultProtocol.'://'.$data);
38 }
39 }
40
41 /**
42 * Alias of {@link onSubmit()}.
43 *
44 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
45 * {@link onSubmit()} instead.
46 */
47 public function onBind(FormEvent $event)
48 {
49 $this->onSubmit($event);
50 }
51
52 public static function getSubscribedEvents()
53 {
54 return array(FormEvents::SUBMIT => 'onSubmit');
55 }
56}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php
new file mode 100644
index 00000000..4d0bdfaa
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php
@@ -0,0 +1,137 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\EventListener;
13
14use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15use Symfony\Component\Form\FormEvents;
16use Symfony\Component\Form\FormEvent;
17use Symfony\Component\Form\Exception\UnexpectedTypeException;
18
19/**
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class MergeCollectionListener implements EventSubscriberInterface
23{
24 /**
25 * Whether elements may be added to the collection
26 * @var Boolean
27 */
28 private $allowAdd;
29
30 /**
31 * Whether elements may be removed from the collection
32 * @var Boolean
33 */
34 private $allowDelete;
35
36 /**
37 * Creates a new listener.
38 *
39 * @param Boolean $allowAdd Whether values might be added to the
40 * collection.
41 * @param Boolean $allowDelete Whether values might be removed from the
42 * collection.
43 */
44 public function __construct($allowAdd = false, $allowDelete = false)
45 {
46 $this->allowAdd = $allowAdd;
47 $this->allowDelete = $allowDelete;
48 }
49
50 public static function getSubscribedEvents()
51 {
52 return array(
53 FormEvents::SUBMIT => 'onSubmit',
54 );
55 }
56
57 public function onSubmit(FormEvent $event)
58 {
59 $dataToMergeInto = $event->getForm()->getNormData();
60 $data = $event->getData();
61
62 if (null === $data) {
63 $data = array();
64 }
65
66 if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
67 throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
68 }
69
70 if (null !== $dataToMergeInto && !is_array($dataToMergeInto) && !($dataToMergeInto instanceof \Traversable && $dataToMergeInto instanceof \ArrayAccess)) {
71 throw new UnexpectedTypeException($dataToMergeInto, 'array or (\Traversable and \ArrayAccess)');
72 }
73
74 // If we are not allowed to change anything, return immediately
75 if ((!$this->allowAdd && !$this->allowDelete) || $data === $dataToMergeInto) {
76 $event->setData($dataToMergeInto);
77
78 return;
79 }
80
81 if (!$dataToMergeInto) {
82 // No original data was set. Set it if allowed
83 if ($this->allowAdd) {
84 $dataToMergeInto = $data;
85 }
86 } else {
87 // Calculate delta
88 $itemsToAdd = is_object($data) ? clone $data : $data;
89 $itemsToDelete = array();
90
91 foreach ($dataToMergeInto as $beforeKey => $beforeItem) {
92 foreach ($data as $afterKey => $afterItem) {
93 if ($afterItem === $beforeItem) {
94 // Item found, next original item
95 unset($itemsToAdd[$afterKey]);
96 continue 2;
97 }
98 }
99
100 // Item not found, remember for deletion
101 $itemsToDelete[] = $beforeKey;
102 }
103
104 // Remove deleted items before adding to free keys that are to be
105 // replaced
106 if ($this->allowDelete) {
107 foreach ($itemsToDelete as $key) {
108 unset($dataToMergeInto[$key]);
109 }
110 }
111
112 // Add remaining items
113 if ($this->allowAdd) {
114 foreach ($itemsToAdd as $key => $item) {
115 if (!isset($dataToMergeInto[$key])) {
116 $dataToMergeInto[$key] = $item;
117 } else {
118 $dataToMergeInto[] = $item;
119 }
120 }
121 }
122 }
123
124 $event->setData($dataToMergeInto);
125 }
126
127 /**
128 * Alias of {@link onSubmit()}.
129 *
130 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
131 * {@link onSubmit()} instead.
132 */
133 public function onBind(FormEvent $event)
134 {
135 $this->onSubmit($event);
136 }
137}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php
new file mode 100644
index 00000000..f1c39db2
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php
@@ -0,0 +1,173 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\Form\Exception\UnexpectedTypeException;
17use Symfony\Component\EventDispatcher\EventSubscriberInterface;
18
19/**
20 * Resize a collection form element based on the data sent from the client.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class ResizeFormListener implements EventSubscriberInterface
25{
26 /**
27 * @var string
28 */
29 protected $type;
30
31 /**
32 * @var array
33 */
34 protected $options;
35
36 /**
37 * Whether children could be added to the group
38 * @var Boolean
39 */
40 protected $allowAdd;
41
42 /**
43 * Whether children could be removed from the group
44 * @var Boolean
45 */
46 protected $allowDelete;
47
48 public function __construct($type, array $options = array(), $allowAdd = false, $allowDelete = false)
49 {
50 $this->type = $type;
51 $this->allowAdd = $allowAdd;
52 $this->allowDelete = $allowDelete;
53 $this->options = $options;
54 }
55
56 public static function getSubscribedEvents()
57 {
58 return array(
59 FormEvents::PRE_SET_DATA => 'preSetData',
60 FormEvents::PRE_SUBMIT => 'preSubmit',
61 // (MergeCollectionListener, MergeDoctrineCollectionListener)
62 FormEvents::SUBMIT => array('onSubmit', 50),
63 );
64 }
65
66 public function preSetData(FormEvent $event)
67 {
68 $form = $event->getForm();
69 $data = $event->getData();
70
71 if (null === $data) {
72 $data = array();
73 }
74
75 if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
76 throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
77 }
78
79 // First remove all rows
80 foreach ($form as $name => $child) {
81 $form->remove($name);
82 }
83
84 // Then add all rows again in the correct order
85 foreach ($data as $name => $value) {
86 $form->add($name, $this->type, array_replace(array(
87 'property_path' => '['.$name.']',
88 ), $this->options));
89 }
90 }
91
92 public function preSubmit(FormEvent $event)
93 {
94 $form = $event->getForm();
95 $data = $event->getData();
96
97 if (null === $data || '' === $data) {
98 $data = array();
99 }
100
101 if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
102 throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
103 }
104
105 // Remove all empty rows
106 if ($this->allowDelete) {
107 foreach ($form as $name => $child) {
108 if (!isset($data[$name])) {
109 $form->remove($name);
110 }
111 }
112 }
113
114 // Add all additional rows
115 if ($this->allowAdd) {
116 foreach ($data as $name => $value) {
117 if (!$form->has($name)) {
118 $form->add($name, $this->type, array_replace(array(
119 'property_path' => '['.$name.']',
120 ), $this->options));
121 }
122 }
123 }
124 }
125
126 public function onSubmit(FormEvent $event)
127 {
128 $form = $event->getForm();
129 $data = $event->getData();
130
131 if (null === $data) {
132 $data = array();
133 }
134
135 if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
136 throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
137 }
138
139 // The data mapper only adds, but does not remove items, so do this
140 // here
141 if ($this->allowDelete) {
142 foreach ($data as $name => $child) {
143 if (!$form->has($name)) {
144 unset($data[$name]);
145 }
146 }
147 }
148
149 $event->setData($data);
150 }
151
152 /**
153 * Alias of {@link preSubmit()}.
154 *
155 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
156 * {@link preSubmit()} instead.
157 */
158 public function preBind(FormEvent $event)
159 {
160 $this->preSubmit($event);
161 }
162
163 /**
164 * Alias of {@link onSubmit()}.
165 *
166 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
167 * {@link onSubmit()} instead.
168 */
169 public function onBind(FormEvent $event)
170 {
171 $this->onSubmit($event);
172 }
173}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/TrimListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/TrimListener.php
new file mode 100644
index 00000000..cbe6e0ab
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/EventListener/TrimListener.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
18/**
19 * Trims string data
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class TrimListener implements EventSubscriberInterface
24{
25 public function preSubmit(FormEvent $event)
26 {
27 $data = $event->getData();
28
29 if (!is_string($data)) {
30 return;
31 }
32
33 if (null !== $result = @preg_replace('/^[\pZ\p{Cc}]+|[\pZ\p{Cc}]+$/u', '', $data)) {
34 $event->setData($result);
35 } else {
36 $event->setData(trim($data));
37 }
38 }
39
40 /**
41 * Alias of {@link preSubmit()}.
42 *
43 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
44 * {@link preSubmit()} instead.
45 */
46 public function preBind(FormEvent $event)
47 {
48 $this->preSubmit($event);
49 }
50
51 public static function getSubscribedEvents()
52 {
53 return array(FormEvents::PRE_SUBMIT => 'preSubmit');
54 }
55}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BaseType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BaseType.php
new file mode 100644
index 00000000..79333a67
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BaseType.php
@@ -0,0 +1,121 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\FormInterface;
17use Symfony\Component\Form\FormView;
18use Symfony\Component\OptionsResolver\OptionsResolverInterface;
19
20/**
21 * Encapsulates common logic of {@link FormType} and {@link ButtonType}.
22 *
23 * This type does not appear in the form's type inheritance chain and as such
24 * cannot be extended (via {@link FormTypeExtension}s) nor themed.
25 *
26 * @author Bernhard Schussek <bschussek@gmail.com>
27 */
28abstract class BaseType extends AbstractType
29{
30 /**
31 * {@inheritdoc}
32 */
33 public function buildForm(FormBuilderInterface $builder, array $options)
34 {
35 $builder->setDisabled($options['disabled']);
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function buildView(FormView $view, FormInterface $form, array $options)
42 {
43 $name = $form->getName();
44 $blockName = $options['block_name'] ?: $form->getName();
45 $translationDomain = $options['translation_domain'];
46
47 if ($view->parent) {
48 if ('' !== ($parentFullName = $view->parent->vars['full_name'])) {
49 $id = sprintf('%s_%s', $view->parent->vars['id'], $name);
50 $fullName = sprintf('%s[%s]', $parentFullName, $name);
51 $uniqueBlockPrefix = sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName);
52 } else {
53 $id = $name;
54 $fullName = $name;
55 $uniqueBlockPrefix = '_'.$blockName;
56 }
57
58 if (!$translationDomain) {
59 $translationDomain = $view->parent->vars['translation_domain'];
60 }
61 } else {
62 $id = $name;
63 $fullName = $name;
64 $uniqueBlockPrefix = '_'.$blockName;
65
66 // Strip leading underscores and digits. These are allowed in
67 // form names, but not in HTML4 ID attributes.
68 // http://www.w3.org/TR/html401/struct/global.html#adef-id
69 $id = ltrim($id, '_0123456789');
70 }
71
72 $blockPrefixes = array();
73 for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) {
74 array_unshift($blockPrefixes, $type->getName());
75 }
76 $blockPrefixes[] = $uniqueBlockPrefix;
77
78 if (!$translationDomain) {
79 $translationDomain = 'messages';
80 }
81
82 $view->vars = array_replace($view->vars, array(
83 'form' => $view,
84 'id' => $id,
85 'name' => $name,
86 'full_name' => $fullName,
87 'disabled' => $form->isDisabled(),
88 'label' => $options['label'],
89 'multipart' => false,
90 'attr' => $options['attr'],
91 'block_prefixes' => $blockPrefixes,
92 'unique_block_prefix' => $uniqueBlockPrefix,
93 'translation_domain' => $translationDomain,
94 // Using the block name here speeds up performance in collection
95 // forms, where each entry has the same full block name.
96 // Including the type is important too, because if rows of a
97 // collection form have different types (dynamically), they should
98 // be rendered differently.
99 // https://github.com/symfony/symfony/issues/5038
100 'cache_key' => $uniqueBlockPrefix.'_'.$form->getConfig()->getType()->getName(),
101 ));
102 }
103
104 /**
105 * {@inheritdoc}
106 */
107 public function setDefaultOptions(OptionsResolverInterface $resolver)
108 {
109 $resolver->setDefaults(array(
110 'block_name' => null,
111 'disabled' => false,
112 'label' => null,
113 'attr' => array(),
114 'translation_domain' => null,
115 ));
116
117 $resolver->setAllowedTypes(array(
118 'attr' => 'array',
119 ));
120 }
121}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php
new file mode 100644
index 00000000..5314c140
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php
@@ -0,0 +1,44 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\OptionsResolverInterface;
16
17class BirthdayType extends AbstractType
18{
19 /**
20 * {@inheritdoc}
21 */
22 public function setDefaultOptions(OptionsResolverInterface $resolver)
23 {
24 $resolver->setDefaults(array(
25 'years' => range(date('Y') - 120, date('Y')),
26 ));
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function getParent()
33 {
34 return 'date';
35 }
36
37 /**
38 * {@inheritdoc}
39 */
40 public function getName()
41 {
42 return 'birthday';
43 }
44}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ButtonType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ButtonType.php
new file mode 100644
index 00000000..3569963b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ButtonType.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\ButtonTypeInterface;
15
16/**
17 * A form button.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ButtonType extends BaseType implements ButtonTypeInterface
22{
23 /**
24 * {@inheritdoc}
25 */
26 public function getParent()
27 {
28 return null;
29 }
30
31 /**
32 * {@inheritdoc}
33 */
34 public function getName()
35 {
36 return 'button';
37 }
38}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php
new file mode 100644
index 00000000..214e581a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CheckboxType.php
@@ -0,0 +1,67 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\FormInterface;
17use Symfony\Component\Form\Extension\Core\DataTransformer\BooleanToStringTransformer;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\OptionsResolver\OptionsResolverInterface;
20
21class CheckboxType extends AbstractType
22{
23 /**
24 * {@inheritdoc}
25 */
26 public function buildForm(FormBuilderInterface $builder, array $options)
27 {
28 $builder
29 ->addViewTransformer(new BooleanToStringTransformer($options['value']))
30 ;
31 }
32
33 /**
34 * {@inheritdoc}
35 */
36 public function buildView(FormView $view, FormInterface $form, array $options)
37 {
38 $view->vars = array_replace($view->vars, array(
39 'value' => $options['value'],
40 'checked' => null !== $form->getViewData(),
41 ));
42 }
43
44 /**
45 * {@inheritdoc}
46 */
47 public function setDefaultOptions(OptionsResolverInterface $resolver)
48 {
49 $emptyData = function (FormInterface $form, $clientData) {
50 return $clientData;
51 };
52
53 $resolver->setDefaults(array(
54 'value' => '1',
55 'empty_data' => $emptyData,
56 'compound' => false,
57 ));
58 }
59
60 /**
61 * {@inheritdoc}
62 */
63 public function getName()
64 {
65 return 'checkbox';
66 }
67}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
new file mode 100644
index 00000000..9a3fdef1
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -0,0 +1,274 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\Extension\Core\View\ChoiceView;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\FormInterface;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\Form\Exception\LogicException;
20use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
21use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
22use Symfony\Component\Form\Extension\Core\EventListener\FixCheckboxInputListener;
23use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
24use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
25use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToBooleanArrayTransformer;
26use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
27use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToBooleanArrayTransformer;
28use Symfony\Component\OptionsResolver\Options;
29use Symfony\Component\OptionsResolver\OptionsResolverInterface;
30
31class ChoiceType extends AbstractType
32{
33 /**
34 * Caches created choice lists.
35 * @var array
36 */
37 private $choiceListCache = array();
38
39 /**
40 * {@inheritdoc}
41 */
42 public function buildForm(FormBuilderInterface $builder, array $options)
43 {
44 if (!$options['choice_list'] && !is_array($options['choices']) && !$options['choices'] instanceof \Traversable) {
45 throw new LogicException('Either the option "choices" or "choice_list" must be set.');
46 }
47
48 if ($options['expanded']) {
49 // Initialize all choices before doing the index check below.
50 // This helps in cases where index checks are optimized for non
51 // initialized choice lists. For example, when using an SQL driver,
52 // the index check would read in one SQL query and the initialization
53 // requires another SQL query. When the initialization is done first,
54 // one SQL query is sufficient.
55 $preferredViews = $options['choice_list']->getPreferredViews();
56 $remainingViews = $options['choice_list']->getRemainingViews();
57
58 // Check if the choices already contain the empty value
59 // Only add the empty value option if this is not the case
60 if (null !== $options['empty_value'] && 0 === count($options['choice_list']->getIndicesForValues(array('')))) {
61 $placeholderView = new ChoiceView(null, '', $options['empty_value']);
62
63 // "placeholder" is a reserved index
64 // see also ChoiceListInterface::getIndicesForChoices()
65 $this->addSubForms($builder, array('placeholder' => $placeholderView), $options);
66 }
67
68 $this->addSubForms($builder, $preferredViews, $options);
69 $this->addSubForms($builder, $remainingViews, $options);
70
71 if ($options['multiple']) {
72 $builder->addViewTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list']));
73 $builder->addEventSubscriber(new FixCheckboxInputListener($options['choice_list']), 10);
74 } else {
75 $builder->addViewTransformer(new ChoiceToBooleanArrayTransformer($options['choice_list'], $builder->has('placeholder')));
76 $builder->addEventSubscriber(new FixRadioInputListener($options['choice_list'], $builder->has('placeholder')), 10);
77 }
78 } else {
79 if ($options['multiple']) {
80 $builder->addViewTransformer(new ChoicesToValuesTransformer($options['choice_list']));
81 } else {
82 $builder->addViewTransformer(new ChoiceToValueTransformer($options['choice_list']));
83 }
84 }
85
86 if ($options['multiple'] && $options['by_reference']) {
87 // Make sure the collection created during the client->norm
88 // transformation is merged back into the original collection
89 $builder->addEventSubscriber(new MergeCollectionListener(true, true));
90 }
91 }
92
93 /**
94 * {@inheritdoc}
95 */
96 public function buildView(FormView $view, FormInterface $form, array $options)
97 {
98 $view->vars = array_replace($view->vars, array(
99 'multiple' => $options['multiple'],
100 'expanded' => $options['expanded'],
101 'preferred_choices' => $options['choice_list']->getPreferredViews(),
102 'choices' => $options['choice_list']->getRemainingViews(),
103 'separator' => '-------------------',
104 'empty_value' => null,
105 ));
106
107 // The decision, whether a choice is selected, is potentially done
108 // thousand of times during the rendering of a template. Provide a
109 // closure here that is optimized for the value of the form, to
110 // avoid making the type check inside the closure.
111 if ($options['multiple']) {
112 $view->vars['is_selected'] = function ($choice, array $values) {
113 return false !== array_search($choice, $values, true);
114 };
115 } else {
116 $view->vars['is_selected'] = function ($choice, $value) {
117 return $choice === $value;
118 };
119 }
120
121 // Check if the choices already contain the empty value
122 // Only add the empty value option if this is not the case
123 if (null !== $options['empty_value'] && 0 === count($options['choice_list']->getIndicesForValues(array('')))) {
124 $view->vars['empty_value'] = $options['empty_value'];
125 }
126
127 if ($options['multiple'] && !$options['expanded']) {
128 // Add "[]" to the name in case a select tag with multiple options is
129 // displayed. Otherwise only one of the selected options is sent in the
130 // POST request.
131 $view->vars['full_name'] = $view->vars['full_name'].'[]';
132 }
133 }
134
135 /**
136 * {@inheritdoc}
137 */
138 public function finishView(FormView $view, FormInterface $form, array $options)
139 {
140 if ($options['expanded']) {
141 // Radio buttons should have the same name as the parent
142 $childName = $view->vars['full_name'];
143
144 // Checkboxes should append "[]" to allow multiple selection
145 if ($options['multiple']) {
146 $childName .= '[]';
147 }
148
149 foreach ($view as $childView) {
150 $childView->vars['full_name'] = $childName;
151 }
152 }
153 }
154
155 /**
156 * {@inheritdoc}
157 */
158 public function setDefaultOptions(OptionsResolverInterface $resolver)
159 {
160 $choiceListCache =& $this->choiceListCache;
161
162 $choiceList = function (Options $options) use (&$choiceListCache) {
163 // Harden against NULL values (like in EntityType and ModelType)
164 $choices = null !== $options['choices'] ? $options['choices'] : array();
165
166 // Reuse existing choice lists in order to increase performance
167 $hash = md5(json_encode(array($choices, $options['preferred_choices'])));
168
169 if (!isset($choiceListCache[$hash])) {
170 $choiceListCache[$hash] = new SimpleChoiceList($choices, $options['preferred_choices']);
171 }
172
173 return $choiceListCache[$hash];
174 };
175
176 $emptyData = function (Options $options) {
177 if ($options['multiple'] || $options['expanded']) {
178 return array();
179 }
180
181 return '';
182 };
183
184 $emptyValue = function (Options $options) {
185 return $options['required'] ? null : '';
186 };
187
188 $emptyValueNormalizer = function (Options $options, $emptyValue) {
189 if ($options['multiple']) {
190 // never use an empty value for this case
191 return null;
192 } elseif (false === $emptyValue) {
193 // an empty value should be added but the user decided otherwise
194 return null;
195 } elseif ($options['expanded'] && '' === $emptyValue) {
196 // never use an empty label for radio buttons
197 return 'None';
198 }
199
200 // empty value has been set explicitly
201 return $emptyValue;
202 };
203
204 $compound = function (Options $options) {
205 return $options['expanded'];
206 };
207
208 $resolver->setDefaults(array(
209 'multiple' => false,
210 'expanded' => false,
211 'choice_list' => $choiceList,
212 'choices' => array(),
213 'preferred_choices' => array(),
214 'empty_data' => $emptyData,
215 'empty_value' => $emptyValue,
216 'error_bubbling' => false,
217 'compound' => $compound,
218 // The view data is always a string, even if the "data" option
219 // is manually set to an object.
220 // See https://github.com/symfony/symfony/pull/5582
221 'data_class' => null,
222 ));
223
224 $resolver->setNormalizers(array(
225 'empty_value' => $emptyValueNormalizer,
226 ));
227
228 $resolver->setAllowedTypes(array(
229 'choice_list' => array('null', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface'),
230 ));
231 }
232
233 /**
234 * {@inheritdoc}
235 */
236 public function getName()
237 {
238 return 'choice';
239 }
240
241 /**
242 * Adds the sub fields for an expanded choice field.
243 *
244 * @param FormBuilderInterface $builder The form builder.
245 * @param array $choiceViews The choice view objects.
246 * @param array $options The build options.
247 */
248 private function addSubForms(FormBuilderInterface $builder, array $choiceViews, array $options)
249 {
250 foreach ($choiceViews as $i => $choiceView) {
251 if (is_array($choiceView)) {
252 // Flatten groups
253 $this->addSubForms($builder, $choiceView, $options);
254 } else {
255 $choiceOpts = array(
256 'value' => $choiceView->value,
257 'label' => $choiceView->label,
258 'translation_domain' => $options['translation_domain'],
259 );
260
261 if ($options['multiple']) {
262 $choiceType = 'checkbox';
263 // The user can check 0 or more checkboxes. If required
264 // is true, he is required to check all of them.
265 $choiceOpts['required'] = false;
266 } else {
267 $choiceType = 'radio';
268 }
269
270 $builder->add($i, $choiceType, $choiceOpts);
271 }
272 }
273 }
274}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CollectionType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CollectionType.php
new file mode 100644
index 00000000..0cb3af1b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CollectionType.php
@@ -0,0 +1,103 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\Form\FormInterface;
18use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
19use Symfony\Component\OptionsResolver\Options;
20use Symfony\Component\OptionsResolver\OptionsResolverInterface;
21
22class CollectionType extends AbstractType
23{
24 /**
25 * {@inheritdoc}
26 */
27 public function buildForm(FormBuilderInterface $builder, array $options)
28 {
29 if ($options['allow_add'] && $options['prototype']) {
30 $prototype = $builder->create($options['prototype_name'], $options['type'], array_replace(array(
31 'label' => $options['prototype_name'].'label__',
32 ), $options['options']));
33 $builder->setAttribute('prototype', $prototype->getForm());
34 }
35
36 $resizeListener = new ResizeFormListener(
37 $options['type'],
38 $options['options'],
39 $options['allow_add'],
40 $options['allow_delete']
41 );
42
43 $builder->addEventSubscriber($resizeListener);
44 }
45
46 /**
47 * {@inheritdoc}
48 */
49 public function buildView(FormView $view, FormInterface $form, array $options)
50 {
51 $view->vars = array_replace($view->vars, array(
52 'allow_add' => $options['allow_add'],
53 'allow_delete' => $options['allow_delete'],
54 ));
55
56 if ($form->getConfig()->hasAttribute('prototype')) {
57 $view->vars['prototype'] = $form->getConfig()->getAttribute('prototype')->createView($view);
58 }
59 }
60
61 /**
62 * {@inheritdoc}
63 */
64 public function finishView(FormView $view, FormInterface $form, array $options)
65 {
66 if ($form->getConfig()->hasAttribute('prototype') && $view->vars['prototype']->vars['multipart']) {
67 $view->vars['multipart'] = true;
68 }
69 }
70
71 /**
72 * {@inheritdoc}
73 */
74 public function setDefaultOptions(OptionsResolverInterface $resolver)
75 {
76 $optionsNormalizer = function (Options $options, $value) {
77 $value['block_name'] = 'entry';
78
79 return $value;
80 };
81
82 $resolver->setDefaults(array(
83 'allow_add' => false,
84 'allow_delete' => false,
85 'prototype' => true,
86 'prototype_name' => '__name__',
87 'type' => 'text',
88 'options' => array(),
89 ));
90
91 $resolver->setNormalizers(array(
92 'options' => $optionsNormalizer,
93 ));
94 }
95
96 /**
97 * {@inheritdoc}
98 */
99 public function getName()
100 {
101 return 'collection';
102 }
103}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CountryType.php
new file mode 100644
index 00000000..3482ba66
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CountryType.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18class CountryType extends AbstractType
19{
20 /**
21 * {@inheritdoc}
22 */
23 public function setDefaultOptions(OptionsResolverInterface $resolver)
24 {
25 $resolver->setDefaults(array(
26 'choices' => Intl::getRegionBundle()->getCountryNames(),
27 ));
28 }
29
30 /**
31 * {@inheritdoc}
32 */
33 public function getParent()
34 {
35 return 'choice';
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getName()
42 {
43 return 'country';
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
new file mode 100644
index 00000000..3a925e3a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18class CurrencyType extends AbstractType
19{
20 /**
21 * {@inheritdoc}
22 */
23 public function setDefaultOptions(OptionsResolverInterface $resolver)
24 {
25 $resolver->setDefaults(array(
26 'choices' => Intl::getCurrencyBundle()->getCurrencyNames(),
27 ));
28 }
29
30 /**
31 * {@inheritdoc}
32 */
33 public function getParent()
34 {
35 return 'choice';
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getName()
42 {
43 return 'currency';
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
new file mode 100644
index 00000000..a612b6fc
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
@@ -0,0 +1,281 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
16use Symfony\Component\Form\FormInterface;
17use Symfony\Component\Form\FormBuilderInterface;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\Form\ReversedTransformer;
20use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
21use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
22use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
23use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
24use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
25use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToRfc3339Transformer;
26use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
27use Symfony\Component\OptionsResolver\Options;
28use Symfony\Component\OptionsResolver\OptionsResolverInterface;
29
30class DateTimeType extends AbstractType
31{
32 const DEFAULT_DATE_FORMAT = \IntlDateFormatter::MEDIUM;
33
34 const DEFAULT_TIME_FORMAT = \IntlDateFormatter::MEDIUM;
35
36 /**
37 * This is not quite the HTML5 format yet, because ICU lacks the
38 * capability of parsing and generating RFC 3339 dates, which
39 * are like the below pattern but with a timezone suffix. The
40 * timezone suffix is
41 *
42 * * "Z" for UTC
43 * * "(-|+)HH:mm" for other timezones (note the colon!)
44 *
45 * For more information see:
46 *
47 * http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax
48 * http://www.w3.org/TR/html-markup/input.datetime.html
49 * http://tools.ietf.org/html/rfc3339
50 *
51 * An ICU ticket was created:
52 * http://icu-project.org/trac/ticket/9421
53 *
54 * It was supposedly fixed, but is not available in all PHP installations
55 * yet. To temporarily circumvent this issue, DateTimeToRfc3339Transformer
56 * is used when the format matches this constant.
57 */
58 const HTML5_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZZZZ";
59
60 private static $acceptedFormats = array(
61 \IntlDateFormatter::FULL,
62 \IntlDateFormatter::LONG,
63 \IntlDateFormatter::MEDIUM,
64 \IntlDateFormatter::SHORT,
65 );
66
67 /**
68 * {@inheritdoc}
69 */
70 public function buildForm(FormBuilderInterface $builder, array $options)
71 {
72 $parts = array('year', 'month', 'day', 'hour');
73 $dateParts = array('year', 'month', 'day');
74 $timeParts = array('hour');
75
76 if ($options['with_minutes']) {
77 $parts[] = 'minute';
78 $timeParts[] = 'minute';
79 }
80
81 if ($options['with_seconds']) {
82 $parts[] = 'second';
83 $timeParts[] = 'second';
84 }
85
86 $dateFormat = is_int($options['date_format']) ? $options['date_format'] : self::DEFAULT_DATE_FORMAT;
87 $timeFormat = self::DEFAULT_TIME_FORMAT;
88 $calendar = \IntlDateFormatter::GREGORIAN;
89 $pattern = is_string($options['format']) ? $options['format'] : null;
90
91 if (!in_array($dateFormat, self::$acceptedFormats, true)) {
92 throw new InvalidOptionsException('The "date_format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.');
93 }
94
95 if ('single_text' === $options['widget']) {
96 if (self::HTML5_FORMAT === $pattern) {
97 $builder->addViewTransformer(new DateTimeToRfc3339Transformer(
98 $options['model_timezone'],
99 $options['view_timezone']
100 ));
101 } else {
102 $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer(
103 $options['model_timezone'],
104 $options['view_timezone'],
105 $dateFormat,
106 $timeFormat,
107 $calendar,
108 $pattern
109 ));
110 }
111 } else {
112 // Only pass a subset of the options to children
113 $dateOptions = array_intersect_key($options, array_flip(array(
114 'years',
115 'months',
116 'days',
117 'empty_value',
118 'required',
119 'translation_domain',
120 )));
121
122 $timeOptions = array_intersect_key($options, array_flip(array(
123 'hours',
124 'minutes',
125 'seconds',
126 'with_minutes',
127 'with_seconds',
128 'empty_value',
129 'required',
130 'translation_domain',
131 )));
132
133 if (null !== $options['date_widget']) {
134 $dateOptions['widget'] = $options['date_widget'];
135 }
136
137 if (null !== $options['time_widget']) {
138 $timeOptions['widget'] = $options['time_widget'];
139 }
140
141 if (null !== $options['date_format']) {
142 $dateOptions['format'] = $options['date_format'];
143 }
144
145 $dateOptions['input'] = $timeOptions['input'] = 'array';
146 $dateOptions['error_bubbling'] = $timeOptions['error_bubbling'] = true;
147
148 $builder
149 ->addViewTransformer(new DataTransformerChain(array(
150 new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts),
151 new ArrayToPartsTransformer(array(
152 'date' => $dateParts,
153 'time' => $timeParts,
154 )),
155 )))
156 ->add('date', 'date', $dateOptions)
157 ->add('time', 'time', $timeOptions)
158 ;
159 }
160
161 if ('string' === $options['input']) {
162 $builder->addModelTransformer(new ReversedTransformer(
163 new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'])
164 ));
165 } elseif ('timestamp' === $options['input']) {
166 $builder->addModelTransformer(new ReversedTransformer(
167 new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
168 ));
169 } elseif ('array' === $options['input']) {
170 $builder->addModelTransformer(new ReversedTransformer(
171 new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts)
172 ));
173 }
174 }
175
176 /**
177 * {@inheritdoc}
178 */
179 public function buildView(FormView $view, FormInterface $form, array $options)
180 {
181 $view->vars['widget'] = $options['widget'];
182
183 // Change the input to a HTML5 date input if
184 // * the widget is set to "single_text"
185 // * the format matches the one expected by HTML5
186 if ('single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) {
187 $view->vars['type'] = 'datetime';
188 }
189 }
190
191 /**
192 * {@inheritdoc}
193 */
194 public function setDefaultOptions(OptionsResolverInterface $resolver)
195 {
196 $compound = function (Options $options) {
197 return $options['widget'] !== 'single_text';
198 };
199
200 // Defaults to the value of "widget"
201 $dateWidget = function (Options $options) {
202 return $options['widget'];
203 };
204
205 // Defaults to the value of "widget"
206 $timeWidget = function (Options $options) {
207 return $options['widget'];
208 };
209
210 $resolver->setDefaults(array(
211 'input' => 'datetime',
212 'model_timezone' => null,
213 'view_timezone' => null,
214 'format' => self::HTML5_FORMAT,
215 'date_format' => null,
216 'widget' => null,
217 'date_widget' => $dateWidget,
218 'time_widget' => $timeWidget,
219 'with_minutes' => true,
220 'with_seconds' => false,
221 // Don't modify \DateTime classes by reference, we treat
222 // them like immutable value objects
223 'by_reference' => false,
224 'error_bubbling' => false,
225 // If initialized with a \DateTime object, FormType initializes
226 // this option to "\DateTime". Since the internal, normalized
227 // representation is not \DateTime, but an array, we need to unset
228 // this option.
229 'data_class' => null,
230 'compound' => $compound,
231 ));
232
233 // Don't add some defaults in order to preserve the defaults
234 // set in DateType and TimeType
235 $resolver->setOptional(array(
236 'empty_value',
237 'years',
238 'months',
239 'days',
240 'hours',
241 'minutes',
242 'seconds',
243 ));
244
245 $resolver->setAllowedValues(array(
246 'input' => array(
247 'datetime',
248 'string',
249 'timestamp',
250 'array',
251 ),
252 'date_widget' => array(
253 null, // inherit default from DateType
254 'single_text',
255 'text',
256 'choice',
257 ),
258 'time_widget' => array(
259 null, // inherit default from TimeType
260 'single_text',
261 'text',
262 'choice',
263 ),
264 // This option will overwrite "date_widget" and "time_widget" options
265 'widget' => array(
266 null, // default, don't overwrite options
267 'single_text',
268 'text',
269 'choice',
270 ),
271 ));
272 }
273
274 /**
275 * {@inheritdoc}
276 */
277 public function getName()
278 {
279 return 'datetime';
280 }
281}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateType.php
new file mode 100644
index 00000000..93d3502e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/DateType.php
@@ -0,0 +1,309 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\FormView;
18use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
19use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
20use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
21use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
22use Symfony\Component\Form\ReversedTransformer;
23use Symfony\Component\OptionsResolver\Options;
24use Symfony\Component\OptionsResolver\OptionsResolverInterface;
25use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
26
27class DateType extends AbstractType
28{
29 const DEFAULT_FORMAT = \IntlDateFormatter::MEDIUM;
30
31 const HTML5_FORMAT = 'yyyy-MM-dd';
32
33 private static $acceptedFormats = array(
34 \IntlDateFormatter::FULL,
35 \IntlDateFormatter::LONG,
36 \IntlDateFormatter::MEDIUM,
37 \IntlDateFormatter::SHORT,
38 );
39
40 /**
41 * {@inheritdoc}
42 */
43 public function buildForm(FormBuilderInterface $builder, array $options)
44 {
45 $dateFormat = is_int($options['format']) ? $options['format'] : self::DEFAULT_FORMAT;
46 $timeFormat = \IntlDateFormatter::NONE;
47 $calendar = \IntlDateFormatter::GREGORIAN;
48 $pattern = is_string($options['format']) ? $options['format'] : null;
49
50 if (!in_array($dateFormat, self::$acceptedFormats, true)) {
51 throw new InvalidOptionsException('The "format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.');
52 }
53
54 if (null !== $pattern && (false === strpos($pattern, 'y') || false === strpos($pattern, 'M') || false === strpos($pattern, 'd'))) {
55 throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" and "d". Its current value is "%s".', $pattern));
56 }
57
58 if ('single_text' === $options['widget']) {
59 $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer(
60 $options['model_timezone'],
61 $options['view_timezone'],
62 $dateFormat,
63 $timeFormat,
64 $calendar,
65 $pattern
66 ));
67 } else {
68 $yearOptions = $monthOptions = $dayOptions = array(
69 'error_bubbling' => true,
70 );
71
72 $formatter = new \IntlDateFormatter(
73 \Locale::getDefault(),
74 $dateFormat,
75 $timeFormat,
76 'UTC',
77 $calendar,
78 $pattern
79 );
80 $formatter->setLenient(false);
81
82 if ('choice' === $options['widget']) {
83 // Only pass a subset of the options to children
84 $yearOptions['choices'] = $this->formatTimestamps($formatter, '/y+/', $this->listYears($options['years']));
85 $yearOptions['empty_value'] = $options['empty_value']['year'];
86 $monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months']));
87 $monthOptions['empty_value'] = $options['empty_value']['month'];
88 $dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days']));
89 $dayOptions['empty_value'] = $options['empty_value']['day'];
90 }
91
92 // Append generic carry-along options
93 foreach (array('required', 'translation_domain') as $passOpt) {
94 $yearOptions[$passOpt] = $monthOptions[$passOpt] = $dayOptions[$passOpt] = $options[$passOpt];
95 }
96
97 $builder
98 ->add('year', $options['widget'], $yearOptions)
99 ->add('month', $options['widget'], $monthOptions)
100 ->add('day', $options['widget'], $dayOptions)
101 ->addViewTransformer(new DateTimeToArrayTransformer(
102 $options['model_timezone'], $options['view_timezone'], array('year', 'month', 'day')
103 ))
104 ->setAttribute('formatter', $formatter)
105 ;
106 }
107
108 if ('string' === $options['input']) {
109 $builder->addModelTransformer(new ReversedTransformer(
110 new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'Y-m-d')
111 ));
112 } elseif ('timestamp' === $options['input']) {
113 $builder->addModelTransformer(new ReversedTransformer(
114 new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
115 ));
116 } elseif ('array' === $options['input']) {
117 $builder->addModelTransformer(new ReversedTransformer(
118 new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], array('year', 'month', 'day'))
119 ));
120 }
121 }
122
123 /**
124 * {@inheritdoc}
125 */
126 public function finishView(FormView $view, FormInterface $form, array $options)
127 {
128 $view->vars['widget'] = $options['widget'];
129
130 // Change the input to a HTML5 date input if
131 // * the widget is set to "single_text"
132 // * the format matches the one expected by HTML5
133 if ('single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) {
134 $view->vars['type'] = 'date';
135 }
136
137 if ($form->getConfig()->hasAttribute('formatter')) {
138 $pattern = $form->getConfig()->getAttribute('formatter')->getPattern();
139
140 // remove special characters unless the format was explicitly specified
141 if (!is_string($options['format'])) {
142 $pattern = preg_replace('/[^yMd]+/', '', $pattern);
143 }
144
145 // set right order with respect to locale (e.g.: de_DE=dd.MM.yy; en_US=M/d/yy)
146 // lookup various formats at http://userguide.icu-project.org/formatparse/datetime
147 if (preg_match('/^([yMd]+)[^yMd]*([yMd]+)[^yMd]*([yMd]+)$/', $pattern)) {
148 $pattern = preg_replace(array('/y+/', '/M+/', '/d+/'), array('{{ year }}', '{{ month }}', '{{ day }}'), $pattern);
149 } else {
150 // default fallback
151 $pattern = '{{ year }}{{ month }}{{ day }}';
152 }
153
154 $view->vars['date_pattern'] = $pattern;
155 }
156 }
157
158 /**
159 * {@inheritdoc}
160 */
161 public function setDefaultOptions(OptionsResolverInterface $resolver)
162 {
163 $compound = function (Options $options) {
164 return $options['widget'] !== 'single_text';
165 };
166
167 $emptyValue = $emptyValueDefault = function (Options $options) {
168 return $options['required'] ? null : '';
169 };
170
171 $emptyValueNormalizer = function (Options $options, $emptyValue) use ($emptyValueDefault) {
172 if (is_array($emptyValue)) {
173 $default = $emptyValueDefault($options);
174
175 return array_merge(
176 array('year' => $default, 'month' => $default, 'day' => $default),
177 $emptyValue
178 );
179 }
180
181 return array(
182 'year' => $emptyValue,
183 'month' => $emptyValue,
184 'day' => $emptyValue
185 );
186 };
187
188 $format = function (Options $options) {
189 return $options['widget'] === 'single_text' ? DateType::HTML5_FORMAT : DateType::DEFAULT_FORMAT;
190 };
191
192 $resolver->setDefaults(array(
193 'years' => range(date('Y') - 5, date('Y') + 5),
194 'months' => range(1, 12),
195 'days' => range(1, 31),
196 'widget' => 'choice',
197 'input' => 'datetime',
198 'format' => $format,
199 'model_timezone' => null,
200 'view_timezone' => null,
201 'empty_value' => $emptyValue,
202 // Don't modify \DateTime classes by reference, we treat
203 // them like immutable value objects
204 'by_reference' => false,
205 'error_bubbling' => false,
206 // If initialized with a \DateTime object, FormType initializes
207 // this option to "\DateTime". Since the internal, normalized
208 // representation is not \DateTime, but an array, we need to unset
209 // this option.
210 'data_class' => null,
211 'compound' => $compound,
212 ));
213
214 $resolver->setNormalizers(array(
215 'empty_value' => $emptyValueNormalizer,
216 ));
217
218 $resolver->setAllowedValues(array(
219 'input' => array(
220 'datetime',
221 'string',
222 'timestamp',
223 'array',
224 ),
225 'widget' => array(
226 'single_text',
227 'text',
228 'choice',
229 ),
230 ));
231
232 $resolver->setAllowedTypes(array(
233 'format' => array('int', 'string'),
234 ));
235 }
236
237 /**
238 * {@inheritdoc}
239 */
240 public function getName()
241 {
242 return 'date';
243 }
244
245 private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $timestamps)
246 {
247 $pattern = $formatter->getPattern();
248 $timezone = $formatter->getTimezoneId();
249
250 if (version_compare(\PHP_VERSION, '5.5.0-dev', '>=')) {
251 $formatter->setTimeZone(\DateTimeZone::UTC);
252 } else {
253 $formatter->setTimeZoneId(\DateTimeZone::UTC);
254 }
255
256 if (preg_match($regex, $pattern, $matches)) {
257 $formatter->setPattern($matches[0]);
258
259 foreach ($timestamps as $key => $timestamp) {
260 $timestamps[$key] = $formatter->format($timestamp);
261 }
262
263 // I'd like to clone the formatter above, but then we get a
264 // segmentation fault, so let's restore the old state instead
265 $formatter->setPattern($pattern);
266 }
267
268 if (version_compare(\PHP_VERSION, '5.5.0-dev', '>=')) {
269 $formatter->setTimeZone($timezone);
270 } else {
271 $formatter->setTimeZoneId($timezone);
272 }
273
274 return $timestamps;
275 }
276
277 private function listYears(array $years)
278 {
279 $result = array();
280
281 foreach ($years as $year) {
282 $result[$year] = gmmktime(0, 0, 0, 6, 15, $year);
283 }
284
285 return $result;
286 }
287
288 private function listMonths(array $months)
289 {
290 $result = array();
291
292 foreach ($months as $month) {
293 $result[$month] = gmmktime(0, 0, 0, $month, 15);
294 }
295
296 return $result;
297 }
298
299 private function listDays(array $days)
300 {
301 $result = array();
302
303 foreach ($days as $day) {
304 $result[$day] = gmmktime(0, 0, 0, 5, $day);
305 }
306
307 return $result;
308 }
309}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/EmailType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/EmailType.php
new file mode 100644
index 00000000..26652ef6
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/EmailType.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15
16class EmailType extends AbstractType
17{
18 /**
19 * {@inheritdoc}
20 */
21 public function getParent()
22 {
23 return 'text';
24 }
25
26 /**
27 * {@inheritdoc}
28 */
29 public function getName()
30 {
31 return 'email';
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FileType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FileType.php
new file mode 100644
index 00000000..2c09da6f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FileType.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class FileType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildView(FormView $view, FormInterface $form, array $options)
25 {
26 $view->vars = array_replace($view->vars, array(
27 'type' => 'file',
28 'value' => '',
29 ));
30 }
31
32 /**
33 * {@inheritdoc}
34 */
35 public function finishView(FormView $view, FormInterface $form, array $options)
36 {
37 $view
38 ->vars['multipart'] = true
39 ;
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function setDefaultOptions(OptionsResolverInterface $resolver)
46 {
47 $resolver->setDefaults(array(
48 'compound' => false,
49 'data_class' => 'Symfony\Component\HttpFoundation\File\File',
50 'empty_data' => null,
51 ));
52 }
53
54 /**
55 * {@inheritdoc}
56 */
57 public function getName()
58 {
59 return 'file';
60 }
61}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FormType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FormType.php
new file mode 100644
index 00000000..0c39d3eb
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/FormType.php
@@ -0,0 +1,214 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\FormBuilderInterface;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
18use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
19use Symfony\Component\Form\Exception\LogicException;
20use Symfony\Component\OptionsResolver\Options;
21use Symfony\Component\OptionsResolver\OptionsResolverInterface;
22use Symfony\Component\PropertyAccess\PropertyAccess;
23use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
24
25class FormType extends BaseType
26{
27 /**
28 * @var PropertyAccessorInterface
29 */
30 private $propertyAccessor;
31
32 public function __construct(PropertyAccessorInterface $propertyAccessor = null)
33 {
34 $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor();
35 }
36
37 /**
38 * {@inheritdoc}
39 */
40 public function buildForm(FormBuilderInterface $builder, array $options)
41 {
42 parent::buildForm($builder, $options);
43
44 $builder
45 ->setRequired($options['required'])
46 ->setErrorBubbling($options['error_bubbling'])
47 ->setEmptyData($options['empty_data'])
48 ->setPropertyPath($options['property_path'])
49 ->setMapped($options['mapped'])
50 ->setByReference($options['by_reference'])
51 ->setInheritData($options['inherit_data'])
52 ->setCompound($options['compound'])
53 ->setData(isset($options['data']) ? $options['data'] : null)
54 ->setDataLocked(isset($options['data']))
55 ->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null)
56 ->setMethod($options['method'])
57 ->setAction($options['action'])
58 ->setAutoInitialize($options['auto_initialize'])
59 ;
60
61 if ($options['trim']) {
62 $builder->addEventSubscriber(new TrimListener());
63 }
64 }
65
66 /**
67 * {@inheritdoc}
68 */
69 public function buildView(FormView $view, FormInterface $form, array $options)
70 {
71 parent::buildView($view, $form, $options);
72
73 $name = $form->getName();
74 $readOnly = $options['read_only'];
75
76 if ($view->parent) {
77 if ('' === $name) {
78 throw new LogicException('Form node with empty name can be used only as root form node.');
79 }
80
81 // Complex fields are read-only if they themselves or their parents are.
82 if (!$readOnly) {
83 $readOnly = $view->parent->vars['read_only'];
84 }
85 }
86
87 $view->vars = array_replace($view->vars, array(
88 'read_only' => $readOnly,
89 'errors' => $form->getErrors(),
90 'valid' => $form->isSubmitted() ? $form->isValid() : true,
91 'value' => $form->getViewData(),
92 'data' => $form->getNormData(),
93 'required' => $form->isRequired(),
94 'max_length' => $options['max_length'],
95 'pattern' => $options['pattern'],
96 'size' => null,
97 'label_attr' => $options['label_attr'],
98 'compound' => $form->getConfig()->getCompound(),
99 'method' => $form->getConfig()->getMethod(),
100 'action' => $form->getConfig()->getAction(),
101 ));
102 }
103
104 /**
105 * {@inheritdoc}
106 */
107 public function finishView(FormView $view, FormInterface $form, array $options)
108 {
109 $multipart = false;
110
111 foreach ($view->children as $child) {
112 if ($child->vars['multipart']) {
113 $multipart = true;
114 break;
115 }
116 }
117
118 $view->vars['multipart'] = $multipart;
119 }
120
121 /**
122 * {@inheritdoc}
123 */
124 public function setDefaultOptions(OptionsResolverInterface $resolver)
125 {
126 parent::setDefaultOptions($resolver);
127
128 // Derive "data_class" option from passed "data" object
129 $dataClass = function (Options $options) {
130 return isset($options['data']) && is_object($options['data']) ? get_class($options['data']) : null;
131 };
132
133 // Derive "empty_data" closure from "data_class" option
134 $emptyData = function (Options $options) {
135 $class = $options['data_class'];
136
137 if (null !== $class) {
138 return function (FormInterface $form) use ($class) {
139 return $form->isEmpty() && !$form->isRequired() ? null : new $class();
140 };
141 }
142
143 return function (FormInterface $form) {
144 return $form->getConfig()->getCompound() ? array() : '';
145 };
146 };
147
148 // For any form that is not represented by a single HTML control,
149 // errors should bubble up by default
150 $errorBubbling = function (Options $options) {
151 return $options['compound'];
152 };
153
154 // BC with old "virtual" option
155 $inheritData = function (Options $options) {
156 if (null !== $options['virtual']) {
157 // Uncomment this as soon as the deprecation note should be shown
158 // trigger_error('The form option "virtual" is deprecated since version 2.3 and will be removed in 3.0. Use "inherit_data" instead.', E_USER_DEPRECATED);
159 return $options['virtual'];
160 }
161
162 return false;
163 };
164
165 // If data is given, the form is locked to that data
166 // (independent of its value)
167 $resolver->setOptional(array(
168 'data',
169 ));
170
171 $resolver->setDefaults(array(
172 'data_class' => $dataClass,
173 'empty_data' => $emptyData,
174 'trim' => true,
175 'required' => true,
176 'read_only' => false,
177 'max_length' => null,
178 'pattern' => null,
179 'property_path' => null,
180 'mapped' => true,
181 'by_reference' => true,
182 'error_bubbling' => $errorBubbling,
183 'label_attr' => array(),
184 'virtual' => null,
185 'inherit_data' => $inheritData,
186 'compound' => true,
187 'method' => 'POST',
188 // According to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt)
189 // section 4.2., empty URIs are considered same-document references
190 'action' => '',
191 'auto_initialize' => true,
192 ));
193
194 $resolver->setAllowedTypes(array(
195 'label_attr' => 'array',
196 ));
197 }
198
199 /**
200 * {@inheritdoc}
201 */
202 public function getParent()
203 {
204 return null;
205 }
206
207 /**
208 * {@inheritdoc}
209 */
210 public function getName()
211 {
212 return 'form';
213 }
214}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/HiddenType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/HiddenType.php
new file mode 100644
index 00000000..bd4fa898
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/HiddenType.php
@@ -0,0 +1,40 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\OptionsResolverInterface;
16
17class HiddenType extends AbstractType
18{
19 /**
20 * {@inheritdoc}
21 */
22 public function setDefaultOptions(OptionsResolverInterface $resolver)
23 {
24 $resolver->setDefaults(array(
25 // hidden fields cannot have a required attribute
26 'required' => false,
27 // Pass errors to the parent
28 'error_bubbling' => true,
29 'compound' => false,
30 ));
31 }
32
33 /**
34 * {@inheritdoc}
35 */
36 public function getName()
37 {
38 return 'hidden';
39 }
40}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/IntegerType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/IntegerType.php
new file mode 100644
index 00000000..b224cac5
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/IntegerType.php
@@ -0,0 +1,68 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class IntegerType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 $builder->addViewTransformer(
27 new IntegerToLocalizedStringTransformer(
28 $options['precision'],
29 $options['grouping'],
30 $options['rounding_mode']
31 ));
32 }
33
34 /**
35 * {@inheritdoc}
36 */
37 public function setDefaultOptions(OptionsResolverInterface $resolver)
38 {
39 $resolver->setDefaults(array(
40 // default precision is locale specific (usually around 3)
41 'precision' => null,
42 'grouping' => false,
43 // Integer cast rounds towards 0, so do the same when displaying fractions
44 'rounding_mode' => \NumberFormatter::ROUND_DOWN,
45 'compound' => false,
46 ));
47
48 $resolver->setAllowedValues(array(
49 'rounding_mode' => array(
50 \NumberFormatter::ROUND_FLOOR,
51 \NumberFormatter::ROUND_DOWN,
52 \NumberFormatter::ROUND_HALFDOWN,
53 \NumberFormatter::ROUND_HALFEVEN,
54 \NumberFormatter::ROUND_HALFUP,
55 \NumberFormatter::ROUND_UP,
56 \NumberFormatter::ROUND_CEILING,
57 ),
58 ));
59 }
60
61 /**
62 * {@inheritdoc}
63 */
64 public function getName()
65 {
66 return 'integer';
67 }
68}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
new file mode 100644
index 00000000..37b2bf33
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18class LanguageType extends AbstractType
19{
20 /**
21 * {@inheritdoc}
22 */
23 public function setDefaultOptions(OptionsResolverInterface $resolver)
24 {
25 $resolver->setDefaults(array(
26 'choices' => Intl::getLanguageBundle()->getLanguageNames(),
27 ));
28 }
29
30 /**
31 * {@inheritdoc}
32 */
33 public function getParent()
34 {
35 return 'choice';
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getName()
42 {
43 return 'language';
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
new file mode 100644
index 00000000..c68c561a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\Locale\Locale;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class LocaleType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function setDefaultOptions(OptionsResolverInterface $resolver)
25 {
26 $resolver->setDefaults(array(
27 'choices' => Intl::getLocaleBundle()->getLocaleNames(),
28 ));
29 }
30
31 /**
32 * {@inheritdoc}
33 */
34 public function getParent()
35 {
36 return 'choice';
37 }
38
39 /**
40 * {@inheritdoc}
41 */
42 public function getName()
43 {
44 return 'locale';
45 }
46}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/MoneyType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/MoneyType.php
new file mode 100644
index 00000000..9e36f9ce
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/MoneyType.php
@@ -0,0 +1,111 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\OptionsResolver\OptionsResolverInterface;
20
21class MoneyType extends AbstractType
22{
23 protected static $patterns = array();
24
25 /**
26 * {@inheritdoc}
27 */
28 public function buildForm(FormBuilderInterface $builder, array $options)
29 {
30 $builder
31 ->addViewTransformer(new MoneyToLocalizedStringTransformer(
32 $options['precision'],
33 $options['grouping'],
34 null,
35 $options['divisor']
36 ))
37 ;
38 }
39
40 /**
41 * {@inheritdoc}
42 */
43 public function buildView(FormView $view, FormInterface $form, array $options)
44 {
45 $view->vars['money_pattern'] = self::getPattern($options['currency']);
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 public function setDefaultOptions(OptionsResolverInterface $resolver)
52 {
53 $resolver->setDefaults(array(
54 'precision' => 2,
55 'grouping' => false,
56 'divisor' => 1,
57 'currency' => 'EUR',
58 'compound' => false,
59 ));
60 }
61
62 /**
63 * {@inheritdoc}
64 */
65 public function getName()
66 {
67 return 'money';
68 }
69
70 /**
71 * Returns the pattern for this locale
72 *
73 * The pattern contains the placeholder "{{ widget }}" where the HTML tag should
74 * be inserted
75 */
76 protected static function getPattern($currency)
77 {
78 if (!$currency) {
79 return '{{ widget }}';
80 }
81
82 $locale = \Locale::getDefault();
83
84 if (!isset(self::$patterns[$locale])) {
85 self::$patterns[$locale] = array();
86 }
87
88 if (!isset(self::$patterns[$locale][$currency])) {
89 $format = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
90 $pattern = $format->formatCurrency('123', $currency);
91
92 // the spacings between currency symbol and number are ignored, because
93 // a single space leads to better readability in combination with input
94 // fields
95
96 // the regex also considers non-break spaces (0xC2 or 0xA0 in UTF-8)
97
98 preg_match('/^([^\s\xc2\xa0]*)[\s\xc2\xa0]*123(?:[,.]0+)?[\s\xc2\xa0]*([^\s\xc2\xa0]*)$/u', $pattern, $matches);
99
100 if (!empty($matches[1])) {
101 self::$patterns[$locale][$currency] = $matches[1].' {{ widget }}';
102 } elseif (!empty($matches[2])) {
103 self::$patterns[$locale][$currency] = '{{ widget }} '.$matches[2];
104 } else {
105 self::$patterns[$locale][$currency] = '{{ widget }}';
106 }
107 }
108
109 return self::$patterns[$locale][$currency];
110 }
111}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/NumberType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/NumberType.php
new file mode 100644
index 00000000..beb3c89a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/NumberType.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class NumberType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 $builder->addViewTransformer(new NumberToLocalizedStringTransformer(
27 $options['precision'],
28 $options['grouping'],
29 $options['rounding_mode']
30 ));
31 }
32
33 /**
34 * {@inheritdoc}
35 */
36 public function setDefaultOptions(OptionsResolverInterface $resolver)
37 {
38 $resolver->setDefaults(array(
39 // default precision is locale specific (usually around 3)
40 'precision' => null,
41 'grouping' => false,
42 'rounding_mode' => \NumberFormatter::ROUND_HALFUP,
43 'compound' => false,
44 ));
45
46 $resolver->setAllowedValues(array(
47 'rounding_mode' => array(
48 \NumberFormatter::ROUND_FLOOR,
49 \NumberFormatter::ROUND_DOWN,
50 \NumberFormatter::ROUND_HALFDOWN,
51 \NumberFormatter::ROUND_HALFEVEN,
52 \NumberFormatter::ROUND_HALFUP,
53 \NumberFormatter::ROUND_UP,
54 \NumberFormatter::ROUND_CEILING,
55 ),
56 ));
57 }
58
59 /**
60 * {@inheritdoc}
61 */
62 public function getName()
63 {
64 return 'number';
65 }
66}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PasswordType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PasswordType.php
new file mode 100644
index 00000000..5a5b1635
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PasswordType.php
@@ -0,0 +1,57 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class PasswordType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildView(FormView $view, FormInterface $form, array $options)
25 {
26 if ($options['always_empty'] || !$form->isSubmitted()) {
27 $view->vars['value'] = '';
28 }
29 }
30
31 /**
32 * {@inheritdoc}
33 */
34 public function setDefaultOptions(OptionsResolverInterface $resolver)
35 {
36 $resolver->setDefaults(array(
37 'always_empty' => true,
38 'trim' => false,
39 ));
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function getParent()
46 {
47 return 'text';
48 }
49
50 /**
51 * {@inheritdoc}
52 */
53 public function getName()
54 {
55 return 'password';
56 }
57}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PercentType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PercentType.php
new file mode 100644
index 00000000..b1df9436
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/PercentType.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class PercentType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 $builder->addViewTransformer(new PercentToLocalizedStringTransformer($options['precision'], $options['type']));
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function setDefaultOptions(OptionsResolverInterface $resolver)
33 {
34 $resolver->setDefaults(array(
35 'precision' => 0,
36 'type' => 'fractional',
37 'compound' => false,
38 ));
39
40 $resolver->setAllowedValues(array(
41 'type' => array(
42 'fractional',
43 'integer',
44 ),
45 ));
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 public function getName()
52 {
53 return 'percent';
54 }
55}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RadioType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RadioType.php
new file mode 100644
index 00000000..dfa7c7d5
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RadioType.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15
16class RadioType extends AbstractType
17{
18 /**
19 * {@inheritdoc}
20 */
21 public function getParent()
22 {
23 return 'checkbox';
24 }
25
26 /**
27 * {@inheritdoc}
28 */
29 public function getName()
30 {
31 return 'radio';
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php
new file mode 100644
index 00000000..9a3cd146
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php
@@ -0,0 +1,67 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\DataTransformer\ValueToDuplicatesTransformer;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class RepeatedType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 // Overwrite required option for child fields
27 $options['first_options']['required'] = $options['required'];
28 $options['second_options']['required'] = $options['required'];
29
30 if (!isset($options['options']['error_bubbling'])) {
31 $options['options']['error_bubbling'] = $options['error_bubbling'];
32 }
33
34 $builder
35 ->addViewTransformer(new ValueToDuplicatesTransformer(array(
36 $options['first_name'],
37 $options['second_name'],
38 )))
39 ->add($options['first_name'], $options['type'], array_merge($options['options'], $options['first_options']))
40 ->add($options['second_name'], $options['type'], array_merge($options['options'], $options['second_options']))
41 ;
42 }
43
44 /**
45 * {@inheritdoc}
46 */
47 public function setDefaultOptions(OptionsResolverInterface $resolver)
48 {
49 $resolver->setDefaults(array(
50 'type' => 'text',
51 'options' => array(),
52 'first_options' => array(),
53 'second_options' => array(),
54 'first_name' => 'first',
55 'second_name' => 'second',
56 'error_bubbling' => false,
57 ));
58 }
59
60 /**
61 * {@inheritdoc}
62 */
63 public function getName()
64 {
65 return 'repeated';
66 }
67}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ResetType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ResetType.php
new file mode 100644
index 00000000..cf55f7c5
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/ResetType.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\ButtonTypeInterface;
16
17/**
18 * A reset button.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class ResetType extends AbstractType implements ButtonTypeInterface
23{
24 /**
25 * {@inheritdoc}
26 */
27 public function getParent()
28 {
29 return 'button';
30 }
31
32 /**
33 * {@inheritdoc}
34 */
35 public function getName()
36 {
37 return 'reset';
38 }
39}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SearchType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SearchType.php
new file mode 100644
index 00000000..bf82972d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SearchType.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15
16class SearchType extends AbstractType
17{
18 /**
19 * {@inheritdoc}
20 */
21 public function getParent()
22 {
23 return 'text';
24 }
25
26 /**
27 * {@inheritdoc}
28 */
29 public function getName()
30 {
31 return 'search';
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SubmitType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SubmitType.php
new file mode 100644
index 00000000..6d160b96
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/SubmitType.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormView;
17use Symfony\Component\Form\SubmitButtonTypeInterface;
18
19/**
20 * A submit button.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class SubmitType extends AbstractType implements SubmitButtonTypeInterface
25{
26 public function buildView(FormView $view, FormInterface $form, array $options)
27 {
28 $view->vars['clicked'] = $form->isClicked();
29 }
30
31 /**
32 * {@inheritdoc}
33 */
34 public function getParent()
35 {
36 return 'button';
37 }
38
39 /**
40 * {@inheritdoc}
41 */
42 public function getName()
43 {
44 return 'submit';
45 }
46}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextType.php
new file mode 100644
index 00000000..11503261
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextType.php
@@ -0,0 +1,36 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\OptionsResolverInterface;
16
17class TextType extends AbstractType
18{
19 /**
20 * {@inheritdoc}
21 */
22 public function setDefaultOptions(OptionsResolverInterface $resolver)
23 {
24 $resolver->setDefaults(array(
25 'compound' => false,
26 ));
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function getName()
33 {
34 return 'text';
35 }
36}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextareaType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextareaType.php
new file mode 100644
index 00000000..0e749b15
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TextareaType.php
@@ -0,0 +1,43 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormView;
16use Symfony\Component\Form\FormInterface;
17
18class TextareaType extends AbstractType
19{
20 /**
21 * {@inheritdoc}
22 */
23 public function buildView(FormView $view, FormInterface $form, array $options)
24 {
25 $view->vars['pattern'] = null;
26 }
27
28 /**
29 * {@inheritdoc}
30 */
31 public function getParent()
32 {
33 return 'text';
34 }
35
36 /**
37 * {@inheritdoc}
38 */
39 public function getName()
40 {
41 return 'textarea';
42 }
43}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimeType.php
new file mode 100644
index 00000000..d7a2a9ef
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimeType.php
@@ -0,0 +1,225 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\ReversedTransformer;
18use Symfony\Component\Form\Exception\InvalidConfigurationException;
19use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
20use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
21use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
22use Symfony\Component\Form\FormView;
23use Symfony\Component\OptionsResolver\Options;
24use Symfony\Component\OptionsResolver\OptionsResolverInterface;
25
26class TimeType extends AbstractType
27{
28 /**
29 * {@inheritdoc}
30 */
31 public function buildForm(FormBuilderInterface $builder, array $options)
32 {
33 $parts = array('hour');
34 $format = 'H';
35
36 if ($options['with_seconds'] && !$options['with_minutes']) {
37 throw new InvalidConfigurationException('You can not disable minutes if you have enabled seconds.');
38 }
39
40 if ($options['with_minutes']) {
41 $format .= ':i';
42 $parts[] = 'minute';
43 }
44
45 if ($options['with_seconds']) {
46 $format .= ':s';
47 $parts[] = 'second';
48 }
49
50 if ('single_text' === $options['widget']) {
51 $builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format));
52 } else {
53 $hourOptions = $minuteOptions = $secondOptions = array(
54 'error_bubbling' => true,
55 );
56
57 if ('choice' === $options['widget']) {
58 $hours = $minutes = array();
59
60 foreach ($options['hours'] as $hour) {
61 $hours[$hour] = str_pad($hour, 2, '0', STR_PAD_LEFT);
62 }
63
64 // Only pass a subset of the options to children
65 $hourOptions['choices'] = $hours;
66 $hourOptions['empty_value'] = $options['empty_value']['hour'];
67
68 if ($options['with_minutes']) {
69 foreach ($options['minutes'] as $minute) {
70 $minutes[$minute] = str_pad($minute, 2, '0', STR_PAD_LEFT);
71 }
72
73 $minuteOptions['choices'] = $minutes;
74 $minuteOptions['empty_value'] = $options['empty_value']['minute'];
75 }
76
77 if ($options['with_seconds']) {
78 $seconds = array();
79
80 foreach ($options['seconds'] as $second) {
81 $seconds[$second] = str_pad($second, 2, '0', STR_PAD_LEFT);
82 }
83
84 $secondOptions['choices'] = $seconds;
85 $secondOptions['empty_value'] = $options['empty_value']['second'];
86 }
87
88 // Append generic carry-along options
89 foreach (array('required', 'translation_domain') as $passOpt) {
90 $hourOptions[$passOpt] = $options[$passOpt];
91
92 if ($options['with_minutes']) {
93 $minuteOptions[$passOpt] = $options[$passOpt];
94 }
95
96 if ($options['with_seconds']) {
97 $secondOptions[$passOpt] = $options[$passOpt];
98 }
99 }
100 }
101
102 $builder->add('hour', $options['widget'], $hourOptions);
103
104 if ($options['with_minutes']) {
105 $builder->add('minute', $options['widget'], $minuteOptions);
106 }
107
108 if ($options['with_seconds']) {
109 $builder->add('second', $options['widget'], $secondOptions);
110 }
111
112 $builder->addViewTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts, 'text' === $options['widget']));
113 }
114
115 if ('string' === $options['input']) {
116 $builder->addModelTransformer(new ReversedTransformer(
117 new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'H:i:s')
118 ));
119 } elseif ('timestamp' === $options['input']) {
120 $builder->addModelTransformer(new ReversedTransformer(
121 new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
122 ));
123 } elseif ('array' === $options['input']) {
124 $builder->addModelTransformer(new ReversedTransformer(
125 new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts)
126 ));
127 }
128 }
129
130 /**
131 * {@inheritdoc}
132 */
133 public function buildView(FormView $view, FormInterface $form, array $options)
134 {
135 $view->vars = array_replace($view->vars, array(
136 'widget' => $options['widget'],
137 'with_minutes' => $options['with_minutes'],
138 'with_seconds' => $options['with_seconds'],
139 ));
140
141 if ('single_text' === $options['widget']) {
142 $view->vars['type'] = 'time';
143 }
144 }
145
146 /**
147 * {@inheritdoc}
148 */
149 public function setDefaultOptions(OptionsResolverInterface $resolver)
150 {
151 $compound = function (Options $options) {
152 return $options['widget'] !== 'single_text';
153 };
154
155 $emptyValue = $emptyValueDefault = function (Options $options) {
156 return $options['required'] ? null : '';
157 };
158
159 $emptyValueNormalizer = function (Options $options, $emptyValue) use ($emptyValueDefault) {
160 if (is_array($emptyValue)) {
161 $default = $emptyValueDefault($options);
162
163 return array_merge(
164 array('hour' => $default, 'minute' => $default, 'second' => $default),
165 $emptyValue
166 );
167 }
168
169 return array(
170 'hour' => $emptyValue,
171 'minute' => $emptyValue,
172 'second' => $emptyValue
173 );
174 };
175
176 $resolver->setDefaults(array(
177 'hours' => range(0, 23),
178 'minutes' => range(0, 59),
179 'seconds' => range(0, 59),
180 'widget' => 'choice',
181 'input' => 'datetime',
182 'with_minutes' => true,
183 'with_seconds' => false,
184 'model_timezone' => null,
185 'view_timezone' => null,
186 'empty_value' => $emptyValue,
187 // Don't modify \DateTime classes by reference, we treat
188 // them like immutable value objects
189 'by_reference' => false,
190 'error_bubbling' => false,
191 // If initialized with a \DateTime object, FormType initializes
192 // this option to "\DateTime". Since the internal, normalized
193 // representation is not \DateTime, but an array, we need to unset
194 // this option.
195 'data_class' => null,
196 'compound' => $compound,
197 ));
198
199 $resolver->setNormalizers(array(
200 'empty_value' => $emptyValueNormalizer,
201 ));
202
203 $resolver->setAllowedValues(array(
204 'input' => array(
205 'datetime',
206 'string',
207 'timestamp',
208 'array',
209 ),
210 'widget' => array(
211 'single_text',
212 'text',
213 'choice',
214 ),
215 ));
216 }
217
218 /**
219 * {@inheritdoc}
220 */
221 public function getName()
222 {
223 return 'time';
224 }
225}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
new file mode 100644
index 00000000..cd4a2ad3
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
@@ -0,0 +1,86 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\OptionsResolver\OptionsResolverInterface;
16
17class TimezoneType extends AbstractType
18{
19 /**
20 * Stores the available timezone choices
21 * @var array
22 */
23 private static $timezones;
24
25 /**
26 * {@inheritdoc}
27 */
28 public function setDefaultOptions(OptionsResolverInterface $resolver)
29 {
30 $resolver->setDefaults(array(
31 'choices' => self::getTimezones(),
32 ));
33 }
34
35 /**
36 * {@inheritdoc}
37 */
38 public function getParent()
39 {
40 return 'choice';
41 }
42
43 /**
44 * {@inheritdoc}
45 */
46 public function getName()
47 {
48 return 'timezone';
49 }
50
51 /**
52 * Returns the timezone choices.
53 *
54 * The choices are generated from the ICU function
55 * \DateTimeZone::listIdentifiers(). They are cached during a single request,
56 * so multiple timezone fields on the same page don't lead to unnecessary
57 * overhead.
58 *
59 * @return array The timezone choices
60 */
61 public static function getTimezones()
62 {
63 if (null === static::$timezones) {
64 static::$timezones = array();
65
66 foreach (\DateTimeZone::listIdentifiers() as $timezone) {
67 $parts = explode('/', $timezone);
68
69 if (count($parts) > 2) {
70 $region = $parts[0];
71 $name = $parts[1].' - '.$parts[2];
72 } elseif (count($parts) > 1) {
73 $region = $parts[0];
74 $name = $parts[1];
75 } else {
76 $region = 'Other';
77 $name = $parts[0];
78 }
79
80 static::$timezones[$region][$timezone] = str_replace('_', ' ', $name);
81 }
82 }
83
84 return static::$timezones;
85 }
86}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/UrlType.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/UrlType.php
new file mode 100644
index 00000000..27749b1a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/Type/UrlType.php
@@ -0,0 +1,54 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener;
17use Symfony\Component\OptionsResolver\OptionsResolverInterface;
18
19class UrlType extends AbstractType
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function buildForm(FormBuilderInterface $builder, array $options)
25 {
26 $builder->addEventSubscriber(new FixUrlProtocolListener($options['default_protocol']));
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function setDefaultOptions(OptionsResolverInterface $resolver)
33 {
34 $resolver->setDefaults(array(
35 'default_protocol' => 'http',
36 ));
37 }
38
39 /**
40 * {@inheritdoc}
41 */
42 public function getParent()
43 {
44 return 'text';
45 }
46
47 /**
48 * {@inheritdoc}
49 */
50 public function getName()
51 {
52 return 'url';
53 }
54}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Core/View/ChoiceView.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/View/ChoiceView.php
new file mode 100644
index 00000000..97cdd214
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Core/View/ChoiceView.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\View;
13
14/**
15 * Represents a choice in templates.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class ChoiceView
20{
21 /**
22 * The original choice value.
23 *
24 * @var mixed
25 */
26 public $data;
27
28 /**
29 * The view representation of the choice.
30 *
31 * @var string
32 */
33 public $value;
34
35 /**
36 * The label displayed to humans.
37 *
38 * @var string
39 */
40 public $label;
41
42 /**
43 * Creates a new ChoiceView.
44 *
45 * @param mixed $data The original choice.
46 * @param string $value The view representation of the choice.
47 * @param string $label The label displayed to humans.
48 */
49 public function __construct($data, $value, $label)
50 {
51 $this->data = $data;
52 $this->value = $value;
53 $this->label = $label;
54 }
55}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
new file mode 100644
index 00000000..f9d9e40a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Csrf;
13
14use Symfony\Component\Form\Extension\Csrf\Type;
15use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
16use Symfony\Component\Form\AbstractExtension;
17use Symfony\Component\Translation\TranslatorInterface;
18
19/**
20 * This extension protects forms by using a CSRF token.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class CsrfExtension extends AbstractExtension
25{
26 /**
27 * @var CsrfProviderInterface
28 */
29 private $csrfProvider;
30
31 /**
32 * @var TranslatorInterface
33 */
34 private $translator;
35
36 /**
37 * @var null|string
38 */
39 private $translationDomain;
40
41 /**
42 * Constructor.
43 *
44 * @param CsrfProviderInterface $csrfProvider The CSRF provider
45 * @param TranslatorInterface $translator The translator for translating error messages.
46 * @param null|string $translationDomain The translation domain for translating.
47 */
48 public function __construct(CsrfProviderInterface $csrfProvider, TranslatorInterface $translator = null, $translationDomain = null)
49 {
50 $this->csrfProvider = $csrfProvider;
51 $this->translator = $translator;
52 $this->translationDomain = $translationDomain;
53 }
54
55 /**
56 * {@inheritDoc}
57 */
58 protected function loadTypeExtensions()
59 {
60 return array(
61 new Type\FormTypeCsrfExtension($this->csrfProvider, true, '_token', $this->translator, $this->translationDomain),
62 );
63 }
64}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderInterface.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderInterface.php
new file mode 100644
index 00000000..7143b130
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderInterface.php
@@ -0,0 +1,49 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
13
14/**
15 * Marks classes able to provide CSRF protection
16 *
17 * You can generate a CSRF token by using the method generateCsrfToken(). To
18 * this method you should pass a value that is unique to the page that should
19 * be secured against CSRF attacks. This value doesn't necessarily have to be
20 * secret. Implementations of this interface are responsible for adding more
21 * secret information.
22 *
23 * If you want to secure a form submission against CSRF attacks, you could
24 * supply an "intention" string. This way you make sure that the form can only
25 * be submitted to pages that are designed to handle the form, that is, that use
26 * the same intention string to validate the CSRF token with isCsrfTokenValid().
27 *
28 * @author Bernhard Schussek <bschussek@gmail.com>
29 */
30interface CsrfProviderInterface
31{
32 /**
33 * Generates a CSRF token for a page of your application.
34 *
35 * @param string $intention Some value that identifies the action intention
36 * (i.e. "authenticate"). Doesn't have to be a secret value.
37 */
38 public function generateCsrfToken($intention);
39
40 /**
41 * Validates a CSRF token.
42 *
43 * @param string $intention The intention used when generating the CSRF token
44 * @param string $token The token supplied by the browser
45 *
46 * @return Boolean Whether the token supplied by the browser is correct
47 */
48 public function isCsrfTokenValid($intention, $token);
49}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php
new file mode 100644
index 00000000..5354886c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php
@@ -0,0 +1,78 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
13
14/**
15 * Default implementation of CsrfProviderInterface.
16 *
17 * This provider uses the session ID returned by session_id() as well as a
18 * user-defined secret value to secure the CSRF token.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class DefaultCsrfProvider implements CsrfProviderInterface
23{
24 /**
25 * A secret value used for generating the CSRF token
26 * @var string
27 */
28 protected $secret;
29
30 /**
31 * Initializes the provider with a secret value
32 *
33 * A recommended value for the secret is a generated value with at least
34 * 32 characters and mixed letters, digits and special characters.
35 *
36 * @param string $secret A secret value included in the CSRF token
37 */
38 public function __construct($secret)
39 {
40 $this->secret = $secret;
41 }
42
43 /**
44 * {@inheritDoc}
45 */
46 public function generateCsrfToken($intention)
47 {
48 return sha1($this->secret.$intention.$this->getSessionId());
49 }
50
51 /**
52 * {@inheritDoc}
53 */
54 public function isCsrfTokenValid($intention, $token)
55 {
56 return $token === $this->generateCsrfToken($intention);
57 }
58
59 /**
60 * Returns the ID of the user session.
61 *
62 * Automatically starts the session if necessary.
63 *
64 * @return string The session ID
65 */
66 protected function getSessionId()
67 {
68 if (version_compare(PHP_VERSION, '5.4', '>=')) {
69 if (PHP_SESSION_NONE === session_status()) {
70 session_start();
71 }
72 } elseif (!session_id()) {
73 session_start();
74 }
75
76 return session_id();
77 }
78}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php
new file mode 100644
index 00000000..ea1fa585
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php
@@ -0,0 +1,57 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
13
14use Symfony\Component\HttpFoundation\Session\Session;
15
16/**
17 * This provider uses a Symfony2 Session object to retrieve the user's
18 * session ID.
19 *
20 * @see DefaultCsrfProvider
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class SessionCsrfProvider extends DefaultCsrfProvider
25{
26 /**
27 * The user session from which the session ID is returned
28 * @var Session
29 */
30 protected $session;
31
32 /**
33 * Initializes the provider with a Session object and a secret value.
34 *
35 * A recommended value for the secret is a generated value with at least
36 * 32 characters and mixed letters, digits and special characters.
37 *
38 * @param Session $session The user session
39 * @param string $secret A secret value included in the CSRF token
40 */
41 public function __construct(Session $session, $secret)
42 {
43 parent::__construct($secret);
44
45 $this->session = $session;
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 protected function getSessionId()
52 {
53 $this->session->start();
54
55 return $this->session->getId();
56 }
57}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
new file mode 100644
index 00000000..547e9d75
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
@@ -0,0 +1,115 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Csrf\EventListener;
13
14use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15use Symfony\Component\Form\FormEvents;
16use Symfony\Component\Form\FormError;
17use Symfony\Component\Form\FormEvent;
18use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
19use Symfony\Component\Translation\TranslatorInterface;
20
21/**
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class CsrfValidationListener implements EventSubscriberInterface
25{
26 /**
27 * The name of the CSRF field
28 * @var string
29 */
30 private $fieldName;
31
32 /**
33 * The provider for generating and validating CSRF tokens
34 * @var CsrfProviderInterface
35 */
36 private $csrfProvider;
37
38 /**
39 * A text mentioning the intention of the CSRF token
40 *
41 * Validation of the token will only succeed if it was generated in the
42 * same session and with the same intention.
43 *
44 * @var string
45 */
46 private $intention;
47
48 /**
49 * The message displayed in case of an error.
50 * @var string
51 */
52 private $errorMessage;
53
54 /**
55 * @var TranslatorInterface
56 */
57 private $translator;
58
59 /**
60 * @var null|string
61 */
62 private $translationDomain;
63
64 public static function getSubscribedEvents()
65 {
66 return array(
67 FormEvents::PRE_SUBMIT => 'preSubmit',
68 );
69 }
70
71 public function __construct($fieldName, CsrfProviderInterface $csrfProvider, $intention, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null)
72 {
73 $this->fieldName = $fieldName;
74 $this->csrfProvider = $csrfProvider;
75 $this->intention = $intention;
76 $this->errorMessage = $errorMessage;
77 $this->translator = $translator;
78 $this->translationDomain = $translationDomain;
79 }
80
81 public function preSubmit(FormEvent $event)
82 {
83 $form = $event->getForm();
84 $data = $event->getData();
85
86 if ($form->isRoot() && $form->getConfig()->getOption('compound')) {
87 if (!isset($data[$this->fieldName]) || !$this->csrfProvider->isCsrfTokenValid($this->intention, $data[$this->fieldName])) {
88 $errorMessage = $this->errorMessage;
89
90 if (null !== $this->translator) {
91 $errorMessage = $this->translator->trans($errorMessage, array(), $this->translationDomain);
92 }
93
94 $form->addError(new FormError($errorMessage));
95 }
96
97 if (is_array($data)) {
98 unset($data[$this->fieldName]);
99 }
100 }
101
102 $event->setData($data);
103 }
104
105 /**
106 * Alias of {@link preSubmit()}.
107 *
108 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
109 * {@link preSubmit()} instead.
110 */
111 public function preBind(FormEvent $event)
112 {
113 $this->preSubmit($event);
114 }
115}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
new file mode 100644
index 00000000..336cf047
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
@@ -0,0 +1,129 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Csrf\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
16use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
17use Symfony\Component\Form\FormBuilderInterface;
18use Symfony\Component\Form\FormView;
19use Symfony\Component\Form\FormInterface;
20use Symfony\Component\OptionsResolver\OptionsResolverInterface;
21use Symfony\Component\Translation\TranslatorInterface;
22
23/**
24 * @author Bernhard Schussek <bschussek@gmail.com>
25 */
26class FormTypeCsrfExtension extends AbstractTypeExtension
27{
28 /**
29 * @var CsrfProviderInterface
30 */
31 private $defaultCsrfProvider;
32
33 /**
34 * @var Boolean
35 */
36 private $defaultEnabled;
37
38 /**
39 * @var string
40 */
41 private $defaultFieldName;
42
43 /**
44 * @var TranslatorInterface
45 */
46 private $translator;
47
48 /**
49 * @var null|string
50 */
51 private $translationDomain;
52
53 public function __construct(CsrfProviderInterface $defaultCsrfProvider, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null)
54 {
55 $this->defaultCsrfProvider = $defaultCsrfProvider;
56 $this->defaultEnabled = $defaultEnabled;
57 $this->defaultFieldName = $defaultFieldName;
58 $this->translator = $translator;
59 $this->translationDomain = $translationDomain;
60 }
61
62 /**
63 * Adds a CSRF field to the form when the CSRF protection is enabled.
64 *
65 * @param FormBuilderInterface $builder The form builder
66 * @param array $options The options
67 */
68 public function buildForm(FormBuilderInterface $builder, array $options)
69 {
70 if (!$options['csrf_protection']) {
71 return;
72 }
73
74 $builder
75 ->setAttribute('csrf_factory', $builder->getFormFactory())
76 ->addEventSubscriber(new CsrfValidationListener(
77 $options['csrf_field_name'],
78 $options['csrf_provider'],
79 $options['intention'],
80 $options['csrf_message'],
81 $this->translator,
82 $this->translationDomain
83 ))
84 ;
85 }
86
87 /**
88 * Adds a CSRF field to the root form view.
89 *
90 * @param FormView $view The form view
91 * @param FormInterface $form The form
92 * @param array $options The options
93 */
94 public function finishView(FormView $view, FormInterface $form, array $options)
95 {
96 if ($options['csrf_protection'] && !$view->parent && $options['compound']) {
97 $factory = $form->getConfig()->getAttribute('csrf_factory');
98 $data = $options['csrf_provider']->generateCsrfToken($options['intention']);
99
100 $csrfForm = $factory->createNamed($options['csrf_field_name'], 'hidden', $data, array(
101 'mapped' => false,
102 ));
103
104 $view->children[$options['csrf_field_name']] = $csrfForm->createView($view);
105 }
106 }
107
108 /**
109 * {@inheritDoc}
110 */
111 public function setDefaultOptions(OptionsResolverInterface $resolver)
112 {
113 $resolver->setDefaults(array(
114 'csrf_protection' => $this->defaultEnabled,
115 'csrf_field_name' => $this->defaultFieldName,
116 'csrf_provider' => $this->defaultCsrfProvider,
117 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.',
118 'intention' => 'unknown',
119 ));
120 }
121
122 /**
123 * {@inheritDoc}
124 */
125 public function getExtendedType()
126 {
127 return 'form';
128 }
129}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php
new file mode 100644
index 00000000..6637ac8c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php
@@ -0,0 +1,101 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\DependencyInjection;
13
14use Symfony\Component\Form\FormExtensionInterface;
15use Symfony\Component\Form\FormTypeGuesserChain;
16use Symfony\Component\Form\Exception\InvalidArgumentException;
17use Symfony\Component\DependencyInjection\ContainerInterface;
18
19class DependencyInjectionExtension implements FormExtensionInterface
20{
21 private $container;
22
23 private $typeServiceIds;
24
25 private $guesserServiceIds;
26
27 private $guesser;
28
29 private $guesserLoaded = false;
30
31 public function __construct(ContainerInterface $container,
32 array $typeServiceIds, array $typeExtensionServiceIds,
33 array $guesserServiceIds)
34 {
35 $this->container = $container;
36 $this->typeServiceIds = $typeServiceIds;
37 $this->typeExtensionServiceIds = $typeExtensionServiceIds;
38 $this->guesserServiceIds = $guesserServiceIds;
39 }
40
41 public function getType($name)
42 {
43 if (!isset($this->typeServiceIds[$name])) {
44 throw new InvalidArgumentException(sprintf('The field type "%s" is not registered with the service container.', $name));
45 }
46
47 $type = $this->container->get($this->typeServiceIds[$name]);
48
49 if ($type->getName() !== $name) {
50 throw new InvalidArgumentException(
51 sprintf('The type name specified for the service "%s" does not match the actual name. Expected "%s", given "%s"',
52 $this->typeServiceIds[$name],
53 $name,
54 $type->getName()
55 ));
56 }
57
58 return $type;
59 }
60
61 public function hasType($name)
62 {
63 return isset($this->typeServiceIds[$name]);
64 }
65
66 public function getTypeExtensions($name)
67 {
68 $extensions = array();
69
70 if (isset($this->typeExtensionServiceIds[$name])) {
71 foreach ($this->typeExtensionServiceIds[$name] as $serviceId) {
72 $extensions[] = $this->container->get($serviceId);
73 }
74 }
75
76 return $extensions;
77 }
78
79 public function hasTypeExtensions($name)
80 {
81 return isset($this->typeExtensionServiceIds[$name]);
82 }
83
84 public function getTypeGuesser()
85 {
86 if (!$this->guesserLoaded) {
87 $this->guesserLoaded = true;
88 $guessers = array();
89
90 foreach ($this->guesserServiceIds as $serviceId) {
91 $guessers[] = $this->container->get($serviceId);
92 }
93
94 if (count($guessers) > 0) {
95 $this->guesser = new FormTypeGuesserChain($guessers);
96 }
97 }
98
99 return $this->guesser;
100 }
101}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/EventListener/BindRequestListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/EventListener/BindRequestListener.php
new file mode 100644
index 00000000..6205b98d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/EventListener/BindRequestListener.php
@@ -0,0 +1,91 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\HttpFoundation\EventListener;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\Form\Exception\LogicException;
17use Symfony\Component\EventDispatcher\EventSubscriberInterface;
18use Symfony\Component\HttpFoundation\Request;
19
20/**
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 *
23 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Pass the
24 * Request instance to {@link Form::process()} instead.
25 */
26class BindRequestListener implements EventSubscriberInterface
27{
28 public static function getSubscribedEvents()
29 {
30 // High priority in order to supersede other listeners
31 return array(FormEvents::PRE_BIND => array('preBind', 128));
32 }
33
34 public function preBind(FormEvent $event)
35 {
36 $form = $event->getForm();
37
38 /* @var Request $request */
39 $request = $event->getData();
40
41 // Only proceed if we actually deal with a Request
42 if (!$request instanceof Request) {
43 return;
44 }
45
46 // Uncomment this as soon as the deprecation note should be shown
47 // trigger_error('Passing a Request instance to Form::submit() is deprecated since version 2.3 and will be disabled in 3.0. Call Form::process($request) instead.', E_USER_DEPRECATED);
48
49 $name = $form->getConfig()->getName();
50 $default = $form->getConfig()->getCompound() ? array() : null;
51
52 // Store the bound data in case of a post request
53 switch ($request->getMethod()) {
54 case 'POST':
55 case 'PUT':
56 case 'DELETE':
57 case 'PATCH':
58 if ('' === $name) {
59 // Form bound without name
60 $params = $request->request->all();
61 $files = $request->files->all();
62 } else {
63 $params = $request->request->get($name, $default);
64 $files = $request->files->get($name, $default);
65 }
66
67 if (is_array($params) && is_array($files)) {
68 $data = array_replace_recursive($params, $files);
69 } else {
70 $data = $params ?: $files;
71 }
72
73 break;
74
75 case 'GET':
76 $data = '' === $name
77 ? $request->query->all()
78 : $request->query->get($name, $default);
79
80 break;
81
82 default:
83 throw new LogicException(sprintf(
84 'The request method "%s" is not supported',
85 $request->getMethod()
86 ));
87 }
88
89 $event->setData($data);
90 }
91}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php
new file mode 100644
index 00000000..08bd89c9
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php
@@ -0,0 +1,29 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\HttpFoundation;
13
14use Symfony\Component\Form\AbstractExtension;
15
16/**
17 * Integrates the HttpFoundation component with the Form library.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class HttpFoundationExtension extends AbstractExtension
22{
23 protected function loadTypeExtensions()
24 {
25 return array(
26 new Type\FormTypeHttpFoundationExtension(),
27 );
28 }
29}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
new file mode 100644
index 00000000..cc485156
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
@@ -0,0 +1,79 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\HttpFoundation;
13
14use Symfony\Component\Form\Exception\UnexpectedTypeException;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\RequestHandlerInterface;
17use Symfony\Component\HttpFoundation\Request;
18
19/**
20 * A request processor using the {@link Request} class of the HttpFoundation
21 * component.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class HttpFoundationRequestHandler implements RequestHandlerInterface
26{
27 /**
28 * {@inheritdoc}
29 */
30 public function handleRequest(FormInterface $form, $request = null)
31 {
32 if (!$request instanceof Request) {
33 throw new UnexpectedTypeException($request, 'Symfony\Component\HttpFoundation\Request');
34 }
35
36 $name = $form->getName();
37 $method = $form->getConfig()->getMethod();
38
39 if ($method !== $request->getMethod()) {
40 return;
41 }
42
43 if ('GET' === $method) {
44 if ('' === $name) {
45 $data = $request->query->all();
46 } else {
47 // Don't submit GET requests if the form's name does not exist
48 // in the request
49 if (!$request->query->has($name)) {
50 return;
51 }
52
53 $data = $request->query->get($name);
54 }
55 } else {
56 if ('' === $name) {
57 $params = $request->request->all();
58 $files = $request->files->all();
59 } else {
60 $default = $form->getConfig()->getCompound() ? array() : null;
61 $params = $request->request->get($name, $default);
62 $files = $request->files->get($name, $default);
63 }
64
65 if (is_array($params) && is_array($files)) {
66 $data = array_replace_recursive($params, $files);
67 } else {
68 $data = $params ?: $files;
69 }
70 }
71
72 // Don't auto-submit the form unless at least one field is present.
73 if ('' === $name && count(array_intersect_key($data, $form->all())) <= 0) {
74 return;
75 }
76
77 $form->submit($data, 'PATCH' !== $method);
78 }
79}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
new file mode 100644
index 00000000..9b09b05c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
@@ -0,0 +1,56 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\HttpFoundation\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
16use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
17use Symfony\Component\Form\FormBuilderInterface;
18
19/**
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class FormTypeHttpFoundationExtension extends AbstractTypeExtension
23{
24 /**
25 * @var BindRequestListener
26 */
27 private $listener;
28
29 /**
30 * @var HttpFoundationRequestHandler
31 */
32 private $requestHandler;
33
34 public function __construct()
35 {
36 $this->listener = new BindRequestListener();
37 $this->requestHandler = new HttpFoundationRequestHandler();
38 }
39
40 /**
41 * {@inheritdoc}
42 */
43 public function buildForm(FormBuilderInterface $builder, array $options)
44 {
45 $builder->addEventSubscriber($this->listener);
46 $builder->setRequestHandler($this->requestHandler);
47 }
48
49 /**
50 * {@inheritdoc}
51 */
52 public function getExtendedType()
53 {
54 return 'form';
55 }
56}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php
new file mode 100644
index 00000000..573cb518
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Templating;
13
14use Symfony\Component\Form\AbstractExtension;
15use Symfony\Component\Form\FormRenderer;
16use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
17use Symfony\Component\Templating\PhpEngine;
18use Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper;
19
20/**
21 * Integrates the Templating component with the Form library.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class TemplatingExtension extends AbstractExtension
26{
27 public function __construct(PhpEngine $engine, CsrfProviderInterface $csrfProvider = null, array $defaultThemes = array())
28 {
29 $engine->addHelpers(array(
30 new FormHelper(new FormRenderer(new TemplatingRendererEngine($engine, $defaultThemes), $csrfProvider))
31 ));
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingRendererEngine.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingRendererEngine.php
new file mode 100644
index 00000000..c1dda60b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Templating/TemplatingRendererEngine.php
@@ -0,0 +1,125 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Templating;
13
14use Symfony\Component\Form\AbstractRendererEngine;
15use Symfony\Component\Form\FormView;
16use Symfony\Component\Templating\EngineInterface;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class TemplatingRendererEngine extends AbstractRendererEngine
22{
23 /**
24 * @var EngineInterface
25 */
26 private $engine;
27
28 public function __construct(EngineInterface $engine, array $defaultThemes = array())
29 {
30 parent::__construct($defaultThemes);
31
32 $this->engine = $engine;
33 }
34
35 /**
36 * {@inheritdoc}
37 */
38 public function renderBlock(FormView $view, $resource, $blockName, array $variables = array())
39 {
40 return trim($this->engine->render($resource, $variables));
41 }
42
43 /**
44 * Loads the cache with the resource for a given block name.
45 *
46 * This implementation tries to load as few blocks as possible, since each block
47 * is represented by a template on the file system.
48 *
49 * @see getResourceForBlock()
50 *
51 * @param string $cacheKey The cache key of the form view.
52 * @param FormView $view The form view for finding the applying themes.
53 * @param string $blockName The name of the block to load.
54 *
55 * @return Boolean True if the resource could be loaded, false otherwise.
56 */
57 protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName)
58 {
59 // Recursively try to find the block in the themes assigned to $view,
60 // then of its parent form, then of the parent form of the parent and so on.
61 // When the root form is reached in this recursion, also the default
62 // themes are taken into account.
63
64 // Check each theme whether it contains the searched block
65 if (isset($this->themes[$cacheKey])) {
66 for ($i = count($this->themes[$cacheKey]) - 1; $i >= 0; --$i) {
67 if ($this->loadResourceFromTheme($cacheKey, $blockName, $this->themes[$cacheKey][$i])) {
68 return true;
69 }
70 }
71 }
72
73 // Check the default themes once we reach the root form without success
74 if (!$view->parent) {
75 for ($i = count($this->defaultThemes) - 1; $i >= 0; --$i) {
76 if ($this->loadResourceFromTheme($cacheKey, $blockName, $this->defaultThemes[$i])) {
77 return true;
78 }
79 }
80 }
81
82 // If we did not find anything in the themes of the current view, proceed
83 // with the themes of the parent view
84 if ($view->parent) {
85 $parentCacheKey = $view->parent->vars[self::CACHE_KEY_VAR];
86
87 if (!isset($this->resources[$parentCacheKey][$blockName])) {
88 $this->loadResourceForBlockName($parentCacheKey, $view->parent, $blockName);
89 }
90
91 // If a template exists in the parent themes, cache that template
92 // for the current theme as well to speed up further accesses
93 if ($this->resources[$parentCacheKey][$blockName]) {
94 $this->resources[$cacheKey][$blockName] = $this->resources[$parentCacheKey][$blockName];
95
96 return true;
97 }
98 }
99
100 // Cache that we didn't find anything to speed up further accesses
101 $this->resources[$cacheKey][$blockName] = false;
102
103 return false;
104 }
105
106 /**
107 * Tries to load the resource for a block from a theme.
108 *
109 * @param string $cacheKey The cache key for storing the resource.
110 * @param string $blockName The name of the block to load a resource for.
111 * @param mixed $theme The theme to load the block from.
112 *
113 * @return Boolean True if the resource could be loaded, false otherwise.
114 */
115 protected function loadResourceFromTheme($cacheKey, $blockName, $theme)
116 {
117 if ($this->engine->exists($templateName = $theme.':'.$blockName.'.html.php')) {
118 $this->resources[$cacheKey][$blockName] = $templateName;
119
120 return true;
121 }
122
123 return false;
124 }
125}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/Form.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/Form.php
new file mode 100644
index 00000000..87e33297
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/Form.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\Constraints;
13
14use Symfony\Component\Validator\Constraint;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class Form extends Constraint
20{
21 /**
22 * Violation code marking an invalid form.
23 */
24 const ERR_INVALID = 1;
25
26 /**
27 * {@inheritdoc}
28 */
29 public function getTargets()
30 {
31 return self::CLASS_CONSTRAINT;
32 }
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
new file mode 100644
index 00000000..bad5a007
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
@@ -0,0 +1,236 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\Constraints;
13
14use Symfony\Component\Form\ClickableInterface;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\Extension\Validator\Util\ServerParams;
17use Symfony\Component\Validator\Constraint;
18use Symfony\Component\Validator\ConstraintValidator;
19
20/**
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class FormValidator extends ConstraintValidator
24{
25 /**
26 * @var ServerParams
27 */
28 private $serverParams;
29
30 /**
31 * Creates a validator with the given server parameters.
32 *
33 * @param ServerParams $params The server parameters. Default
34 * parameters are created if null.
35 */
36 public function __construct(ServerParams $params = null)
37 {
38 $this->serverParams = $params ?: new ServerParams();
39 }
40
41 /**
42 * {@inheritdoc}
43 */
44 public function validate($form, Constraint $constraint)
45 {
46 if (!$form instanceof FormInterface) {
47 return;
48 }
49
50 /* @var FormInterface $form */
51 $config = $form->getConfig();
52
53 if ($form->isSynchronized()) {
54 // Validate the form data only if transformation succeeded
55 $groups = self::getValidationGroups($form);
56
57 // Validate the data against its own constraints
58 if (self::allowDataWalking($form)) {
59 foreach ($groups as $group) {
60 $this->context->validate($form->getData(), 'data', $group, true);
61 }
62 }
63
64 // Validate the data against the constraints defined
65 // in the form
66 $constraints = $config->getOption('constraints');
67 foreach ($constraints as $constraint) {
68 foreach ($groups as $group) {
69 if (in_array($group, $constraint->groups)) {
70 $this->context->validateValue($form->getData(), $constraint, 'data', $group);
71
72 // Prevent duplicate validation
73 continue 2;
74 }
75 }
76 }
77 } else {
78 $childrenSynchronized = true;
79
80 foreach ($form as $child) {
81 if (!$child->isSynchronized()) {
82 $childrenSynchronized = false;
83 break;
84 }
85 }
86
87 // Mark the form with an error if it is not synchronized BUT all
88 // of its children are synchronized. If any child is not
89 // synchronized, an error is displayed there already and showing
90 // a second error in its parent form is pointless, or worse, may
91 // lead to duplicate errors if error bubbling is enabled on the
92 // child.
93 // See also https://github.com/symfony/symfony/issues/4359
94 if ($childrenSynchronized) {
95 $clientDataAsString = is_scalar($form->getViewData())
96 ? (string) $form->getViewData()
97 : gettype($form->getViewData());
98
99 $this->context->addViolation(
100 $config->getOption('invalid_message'),
101 array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters')),
102 $form->getViewData(),
103 null,
104 Form::ERR_INVALID
105 );
106 }
107 }
108
109 // Mark the form with an error if it contains extra fields
110 if (count($form->getExtraData()) > 0) {
111 $this->context->addViolation(
112 $config->getOption('extra_fields_message'),
113 array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
114 $form->getExtraData()
115 );
116 }
117
118 // Mark the form with an error if the uploaded size was too large
119 $length = $this->serverParams->getContentLength();
120
121 if ($form->isRoot() && null !== $length) {
122 $max = $this->serverParams->getPostMaxSize();
123
124 if (!empty($max) && $length > $max) {
125 $this->context->addViolation(
126 $config->getOption('post_max_size_message'),
127 array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()),
128 $length
129 );
130 }
131 }
132 }
133
134 /**
135 * Returns whether the data of a form may be walked.
136 *
137 * @param FormInterface $form The form to test.
138 *
139 * @return Boolean Whether the graph walker may walk the data.
140 */
141 private static function allowDataWalking(FormInterface $form)
142 {
143 $data = $form->getData();
144
145 // Scalar values cannot have mapped constraints
146 if (!is_object($data) && !is_array($data)) {
147 return false;
148 }
149
150 // Root forms are always validated
151 if ($form->isRoot()) {
152 return true;
153 }
154
155 // Non-root forms are validated if validation cascading
156 // is enabled in all ancestor forms
157 while (null !== ($form = $form->getParent())) {
158 if (!$form->getConfig()->getOption('cascade_validation')) {
159 return false;
160 }
161 }
162
163 return true;
164 }
165
166 /**
167 * Returns the validation groups of the given form.
168 *
169 * @param FormInterface $form The form.
170 *
171 * @return array The validation groups.
172 */
173 private static function getValidationGroups(FormInterface $form)
174 {
175 $button = self::findClickedButton($form->getRoot());
176
177 if (null !== $button) {
178 $groups = $button->getConfig()->getOption('validation_groups');
179
180 if (null !== $groups) {
181 return self::resolveValidationGroups($groups, $form);
182 }
183 }
184
185 do {
186 $groups = $form->getConfig()->getOption('validation_groups');
187
188 if (null !== $groups) {
189 return self::resolveValidationGroups($groups, $form);
190 }
191
192 $form = $form->getParent();
193 } while (null !== $form);
194
195 return array(Constraint::DEFAULT_GROUP);
196 }
197
198 /**
199 * Extracts a clicked button from a form tree, if one exists.
200 *
201 * @param FormInterface $form The root form.
202 *
203 * @return ClickableInterface|null The clicked button or null.
204 */
205 private static function findClickedButton(FormInterface $form)
206 {
207 if ($form instanceof ClickableInterface && $form->isClicked()) {
208 return $form;
209 }
210
211 foreach ($form as $child) {
212 if (null !== ($button = self::findClickedButton($child))) {
213 return $button;
214 }
215 }
216
217 return null;
218 }
219
220 /**
221 * Post-processes the validation groups option for a given form.
222 *
223 * @param array|callable $groups The validation groups.
224 * @param FormInterface $form The validated form.
225 *
226 * @return array The validation groups.
227 */
228 private static function resolveValidationGroups($groups, FormInterface $form)
229 {
230 if (!is_string($groups) && is_callable($groups)) {
231 $groups = call_user_func($groups, $form);
232 }
233
234 return (array) $groups;
235 }
236}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
new file mode 100644
index 00000000..14147531
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
@@ -0,0 +1,68 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\EventListener;
13
14use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface;
16use Symfony\Component\Validator\ValidatorInterface;
17use Symfony\Component\Form\FormEvents;
18use Symfony\Component\Form\FormEvent;
19use Symfony\Component\Form\Extension\Validator\Constraints\Form;
20
21/**
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class ValidationListener implements EventSubscriberInterface
25{
26 private $validator;
27
28 private $violationMapper;
29
30 /**
31 * {@inheritdoc}
32 */
33 public static function getSubscribedEvents()
34 {
35 return array(FormEvents::POST_SUBMIT => 'validateForm');
36 }
37
38 public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper)
39 {
40 $this->validator = $validator;
41 $this->violationMapper = $violationMapper;
42 }
43
44 /**
45 * Validates the form and its domain object.
46 *
47 * @param FormEvent $event The event object
48 */
49 public function validateForm(FormEvent $event)
50 {
51 $form = $event->getForm();
52
53 if ($form->isRoot()) {
54 // Validate the form in group "Default"
55 $violations = $this->validator->validate($form);
56
57 if (count($violations) > 0) {
58 foreach ($violations as $violation) {
59 // Allow the "invalid" constraint to be put onto
60 // non-synchronized forms
61 $allowNonSynchronized = Form::ERR_INVALID === $violation->getCode();
62
63 $this->violationMapper->mapViolation($violation, $form, $allowNonSynchronized);
64 }
65 }
66 }
67 }
68}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php
new file mode 100644
index 00000000..7c5e6784
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php
@@ -0,0 +1,56 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\OptionsResolver\Options;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18/**
19 * Encapsulates common logic of {@link FormTypeValidatorExtension} and
20 * {@link SubmitTypeValidatorExtension}.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24abstract class BaseValidatorExtension extends AbstractTypeExtension
25{
26 /**
27 * {@inheritdoc}
28 */
29 public function setDefaultOptions(OptionsResolverInterface $resolver)
30 {
31 // Make sure that validation groups end up as null, closure or array
32 $validationGroupsNormalizer = function (Options $options, $groups) {
33 if (false === $groups) {
34 return array();
35 }
36
37 if (empty($groups)) {
38 return null;
39 }
40
41 if (is_callable($groups)) {
42 return $groups;
43 }
44
45 return (array) $groups;
46 };
47
48 $resolver->setDefaults(array(
49 'validation_groups' => null,
50 ));
51
52 $resolver->setNormalizers(array(
53 'validation_groups' => $validationGroupsNormalizer,
54 ));
55 }
56}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
new file mode 100644
index 00000000..344bddad
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
@@ -0,0 +1,84 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\Type;
13
14use Symfony\Component\Form\FormBuilderInterface;
15use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
16use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
17use Symfony\Component\Validator\ValidatorInterface;
18use Symfony\Component\OptionsResolver\Options;
19use Symfony\Component\OptionsResolver\OptionsResolverInterface;
20
21/**
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class FormTypeValidatorExtension extends BaseValidatorExtension
25{
26 /**
27 * @var ValidatorInterface
28 */
29 private $validator;
30
31 /**
32 * @var ViolationMapper
33 */
34 private $violationMapper;
35
36 public function __construct(ValidatorInterface $validator)
37 {
38 $this->validator = $validator;
39 $this->violationMapper = new ViolationMapper();
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function buildForm(FormBuilderInterface $builder, array $options)
46 {
47 $builder->addEventSubscriber(new ValidationListener($this->validator, $this->violationMapper));
48 }
49
50 /**
51 * {@inheritdoc}
52 */
53 public function setDefaultOptions(OptionsResolverInterface $resolver)
54 {
55 parent::setDefaultOptions($resolver);
56
57 // Constraint should always be converted to an array
58 $constraintsNormalizer = function (Options $options, $constraints) {
59 return is_object($constraints) ? array($constraints) : (array) $constraints;
60 };
61
62 $resolver->setDefaults(array(
63 'error_mapping' => array(),
64 'constraints' => array(),
65 'cascade_validation' => false,
66 'invalid_message' => 'This value is not valid.',
67 'invalid_message_parameters' => array(),
68 'extra_fields_message' => 'This form should not contain extra fields.',
69 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
70 ));
71
72 $resolver->setNormalizers(array(
73 'constraints' => $constraintsNormalizer,
74 ));
75 }
76
77 /**
78 * {@inheritdoc}
79 */
80 public function getExtendedType()
81 {
82 return 'form';
83 }
84}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php
new file mode 100644
index 00000000..858ff0fa
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\OptionsResolver\Options;
16use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class RepeatedTypeValidatorExtension extends AbstractTypeExtension
22{
23 /**
24 * {@inheritdoc}
25 */
26 public function setDefaultOptions(OptionsResolverInterface $resolver)
27 {
28 // Map errors to the first field
29 $errorMapping = function (Options $options) {
30 return array('.' => $options['first_name']);
31 };
32
33 $resolver->setDefaults(array(
34 'error_mapping' => $errorMapping,
35 ));
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getExtendedType()
42 {
43 return 'repeated';
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php
new file mode 100644
index 00000000..5aad67fb
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\Type;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class SubmitTypeValidatorExtension extends AbstractTypeExtension
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function getExtendedType()
25 {
26 return 'submit';
27 }
28}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php
new file mode 100644
index 00000000..fab6ac2a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\Util;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class ServerParams
18{
19 /**
20 * Returns maximum post size in bytes.
21 *
22 * @return null|integer The maximum post size in bytes
23 */
24 public function getPostMaxSize()
25 {
26 $iniMax = $this->getNormalizedIniPostMaxSize();
27
28 if ('' === $iniMax) {
29 return null;
30 }
31
32 if (preg_match('#^\+?(0X?)?(.*?)([KMG]?)$#', $iniMax, $match)) {
33 $shifts = array('' => 0, 'K' => 10, 'M' => 20, 'G' => 30);
34 $bases = array('' => 10, '0' => 8, '0X' => 16);
35
36 return intval($match[2], $bases[$match[1]]) << $shifts[$match[3]];
37 }
38
39 return 0;
40 }
41
42 /**
43 * Returns the normalized "post_max_size" ini setting.
44 *
45 * @return string
46 */
47 public function getNormalizedIniPostMaxSize()
48 {
49 return strtoupper(trim(ini_get('post_max_size')));
50 }
51
52 /**
53 * Returns the content length of the request.
54 *
55 * @return mixed The request content length.
56 */
57 public function getContentLength()
58 {
59 return isset($_SERVER['CONTENT_LENGTH'])
60 ? (int) $_SERVER['CONTENT_LENGTH']
61 : null;
62 }
63
64}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
new file mode 100644
index 00000000..9cff22a2
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
@@ -0,0 +1,57 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator;
13
14use Symfony\Component\Form\Extension\Validator\Type;
15use Symfony\Component\Form\Extension\Validator\Constraints\Form;
16use Symfony\Component\Form\AbstractExtension;
17use Symfony\Component\Validator\ValidatorInterface;
18use Symfony\Component\Validator\Constraints\Valid;
19
20/**
21 * Extension supporting the Symfony2 Validator component in forms.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class ValidatorExtension extends AbstractExtension
26{
27 private $validator;
28
29 public function __construct(ValidatorInterface $validator)
30 {
31 $this->validator = $validator;
32
33 // Register the form constraints in the validator programmatically.
34 // This functionality is required when using the Form component without
35 // the DIC, where the XML file is loaded automatically. Thus the following
36 // code must be kept synchronized with validation.xml
37
38 /** @var \Symfony\Component\Validator\Mapping\ClassMetadata $metadata */
39 $metadata = $this->validator->getMetadataFactory()->getMetadataFor('Symfony\Component\Form\Form');
40 $metadata->addConstraint(new Form());
41 $metadata->addPropertyConstraint('children', new Valid());
42 }
43
44 public function loadTypeGuesser()
45 {
46 return new ValidatorTypeGuesser($this->validator->getMetadataFactory());
47 }
48
49 protected function loadTypeExtensions()
50 {
51 return array(
52 new Type\FormTypeValidatorExtension($this->validator),
53 new Type\RepeatedTypeValidatorExtension(),
54 new Type\SubmitTypeValidatorExtension(),
55 );
56 }
57}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
new file mode 100644
index 00000000..dcd9cc55
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
@@ -0,0 +1,286 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator;
13
14use Symfony\Component\Form\FormTypeGuesserInterface;
15use Symfony\Component\Form\Guess\Guess;
16use Symfony\Component\Form\Guess\TypeGuess;
17use Symfony\Component\Form\Guess\ValueGuess;
18use Symfony\Component\Validator\MetadataFactoryInterface;
19use Symfony\Component\Validator\Constraint;
20
21class ValidatorTypeGuesser implements FormTypeGuesserInterface
22{
23 private $metadataFactory;
24
25 public function __construct(MetadataFactoryInterface $metadataFactory)
26 {
27 $this->metadataFactory = $metadataFactory;
28 }
29
30 /**
31 * {@inheritDoc}
32 */
33 public function guessType($class, $property)
34 {
35 $guesser = $this;
36
37 return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
38 return $guesser->guessTypeForConstraint($constraint);
39 });
40 }
41
42 /**
43 * {@inheritDoc}
44 */
45 public function guessRequired($class, $property)
46 {
47 $guesser = $this;
48
49 return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
50 return $guesser->guessRequiredForConstraint($constraint);
51 // If we don't find any constraint telling otherwise, we can assume
52 // that a field is not required (with LOW_CONFIDENCE)
53 }, false);
54 }
55
56 /**
57 * {@inheritDoc}
58 */
59 public function guessMaxLength($class, $property)
60 {
61 $guesser = $this;
62
63 return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
64 return $guesser->guessMaxLengthForConstraint($constraint);
65 });
66 }
67
68 /**
69 * {@inheritDoc}
70 */
71 public function guessPattern($class, $property)
72 {
73 $guesser = $this;
74
75 return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
76 return $guesser->guessPatternForConstraint($constraint);
77 });
78 }
79
80 /**
81 * Guesses a field class name for a given constraint
82 *
83 * @param Constraint $constraint The constraint to guess for
84 *
85 * @return TypeGuess The guessed field class and options
86 */
87 public function guessTypeForConstraint(Constraint $constraint)
88 {
89 switch (get_class($constraint)) {
90 case 'Symfony\Component\Validator\Constraints\Type':
91 switch ($constraint->type) {
92 case 'array':
93 return new TypeGuess('collection', array(), Guess::MEDIUM_CONFIDENCE);
94 case 'boolean':
95 case 'bool':
96 return new TypeGuess('checkbox', array(), Guess::MEDIUM_CONFIDENCE);
97
98 case 'double':
99 case 'float':
100 case 'numeric':
101 case 'real':
102 return new TypeGuess('number', array(), Guess::MEDIUM_CONFIDENCE);
103
104 case 'integer':
105 case 'int':
106 case 'long':
107 return new TypeGuess('integer', array(), Guess::MEDIUM_CONFIDENCE);
108
109 case '\DateTime':
110 return new TypeGuess('date', array(), Guess::MEDIUM_CONFIDENCE);
111
112 case 'string':
113 return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
114 }
115 break;
116
117 case 'Symfony\Component\Validator\Constraints\Country':
118 return new TypeGuess('country', array(), Guess::HIGH_CONFIDENCE);
119
120 case 'Symfony\Component\Validator\Constraints\Date':
121 return new TypeGuess('date', array('input' => 'string'), Guess::HIGH_CONFIDENCE);
122
123 case 'Symfony\Component\Validator\Constraints\DateTime':
124 return new TypeGuess('datetime', array('input' => 'string'), Guess::HIGH_CONFIDENCE);
125
126 case 'Symfony\Component\Validator\Constraints\Email':
127 return new TypeGuess('email', array(), Guess::HIGH_CONFIDENCE);
128
129 case 'Symfony\Component\Validator\Constraints\File':
130 case 'Symfony\Component\Validator\Constraints\Image':
131 return new TypeGuess('file', array(), Guess::HIGH_CONFIDENCE);
132
133 case 'Symfony\Component\Validator\Constraints\Language':
134 return new TypeGuess('language', array(), Guess::HIGH_CONFIDENCE);
135
136 case 'Symfony\Component\Validator\Constraints\Locale':
137 return new TypeGuess('locale', array(), Guess::HIGH_CONFIDENCE);
138
139 case 'Symfony\Component\Validator\Constraints\Time':
140 return new TypeGuess('time', array('input' => 'string'), Guess::HIGH_CONFIDENCE);
141
142 case 'Symfony\Component\Validator\Constraints\Url':
143 return new TypeGuess('url', array(), Guess::HIGH_CONFIDENCE);
144
145 case 'Symfony\Component\Validator\Constraints\Ip':
146 return new TypeGuess('text', array(), Guess::MEDIUM_CONFIDENCE);
147
148 case 'Symfony\Component\Validator\Constraints\MaxLength':
149 case 'Symfony\Component\Validator\Constraints\MinLength':
150 case 'Symfony\Component\Validator\Constraints\Regex':
151 return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
152
153 case 'Symfony\Component\Validator\Constraints\Min':
154 case 'Symfony\Component\Validator\Constraints\Max':
155 return new TypeGuess('number', array(), Guess::LOW_CONFIDENCE);
156
157 case 'Symfony\Component\Validator\Constraints\MinCount':
158 case 'Symfony\Component\Validator\Constraints\MaxCount':
159 return new TypeGuess('collection', array(), Guess::LOW_CONFIDENCE);
160
161 case 'Symfony\Component\Validator\Constraints\True':
162 case 'Symfony\Component\Validator\Constraints\False':
163 return new TypeGuess('checkbox', array(), Guess::MEDIUM_CONFIDENCE);
164 }
165
166 return null;
167 }
168
169 /**
170 * Guesses whether a field is required based on the given constraint
171 *
172 * @param Constraint $constraint The constraint to guess for
173 *
174 * @return Guess The guess whether the field is required
175 */
176 public function guessRequiredForConstraint(Constraint $constraint)
177 {
178 switch (get_class($constraint)) {
179 case 'Symfony\Component\Validator\Constraints\NotNull':
180 case 'Symfony\Component\Validator\Constraints\NotBlank':
181 case 'Symfony\Component\Validator\Constraints\True':
182 return new ValueGuess(true, Guess::HIGH_CONFIDENCE);
183 }
184
185 return null;
186 }
187
188 /**
189 * Guesses a field's maximum length based on the given constraint
190 *
191 * @param Constraint $constraint The constraint to guess for
192 *
193 * @return Guess The guess for the maximum length
194 */
195 public function guessMaxLengthForConstraint(Constraint $constraint)
196 {
197 switch (get_class($constraint)) {
198 case 'Symfony\Component\Validator\Constraints\MaxLength':
199 return new ValueGuess($constraint->limit, Guess::HIGH_CONFIDENCE);
200
201 case 'Symfony\Component\Validator\Constraints\Type':
202 if (in_array($constraint->type, array('double', 'float', 'numeric', 'real'))) {
203 return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
204 }
205 break;
206
207 case 'Symfony\Component\Validator\Constraints\Max':
208 return new ValueGuess(strlen((string) $constraint->limit), Guess::LOW_CONFIDENCE);
209 }
210
211 return null;
212 }
213
214 /**
215 * Guesses a field's pattern based on the given constraint
216 *
217 * @param Constraint $constraint The constraint to guess for
218 *
219 * @return Guess The guess for the pattern
220 */
221 public function guessPatternForConstraint(Constraint $constraint)
222 {
223 switch (get_class($constraint)) {
224 case 'Symfony\Component\Validator\Constraints\MinLength':
225 return new ValueGuess(sprintf('.{%s,}', (string) $constraint->limit), Guess::LOW_CONFIDENCE);
226
227 case 'Symfony\Component\Validator\Constraints\Regex':
228 $htmlPattern = $constraint->getHtmlPattern();
229
230 if (null !== $htmlPattern) {
231 return new ValueGuess($htmlPattern, Guess::HIGH_CONFIDENCE);
232 }
233 break;
234
235 case 'Symfony\Component\Validator\Constraints\Min':
236 return new ValueGuess(sprintf('.{%s,}', strlen((string) $constraint->limit)), Guess::LOW_CONFIDENCE);
237
238 case 'Symfony\Component\Validator\Constraints\Type':
239 if (in_array($constraint->type, array('double', 'float', 'numeric', 'real'))) {
240 return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
241 }
242 break;
243 }
244
245 return null;
246 }
247
248 /**
249 * Iterates over the constraints of a property, executes a constraints on
250 * them and returns the best guess
251 *
252 * @param string $class The class to read the constraints from
253 * @param string $property The property for which to find constraints
254 * @param \Closure $closure The closure that returns a guess
255 * for a given constraint
256 * @param mixed $defaultValue The default value assumed if no other value
257 * can be guessed.
258 *
259 * @return Guess The guessed value with the highest confidence
260 */
261 protected function guess($class, $property, \Closure $closure, $defaultValue = null)
262 {
263 $guesses = array();
264 $classMetadata = $this->metadataFactory->getMetadataFor($class);
265
266 if ($classMetadata->hasMemberMetadatas($property)) {
267 $memberMetadatas = $classMetadata->getMemberMetadatas($property);
268
269 foreach ($memberMetadatas as $memberMetadata) {
270 $constraints = $memberMetadata->getConstraints();
271
272 foreach ($constraints as $constraint) {
273 if ($guess = $closure($constraint)) {
274 $guesses[] = $guess;
275 }
276 }
277 }
278
279 if (null !== $defaultValue) {
280 $guesses[] = new ValueGuess($defaultValue, Guess::LOW_CONFIDENCE);
281 }
282 }
283
284 return Guess::getBestGuess($guesses);
285 }
286}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php
new file mode 100644
index 00000000..7b96efb4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php
@@ -0,0 +1,106 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
13
14use Symfony\Component\Form\FormInterface;
15use Symfony\Component\Form\Exception\ErrorMappingException;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class MappingRule
21{
22 /**
23 * @var FormInterface
24 */
25 private $origin;
26
27 /**
28 * @var string
29 */
30 private $propertyPath;
31
32 /**
33 * @var string
34 */
35 private $targetPath;
36
37 public function __construct(FormInterface $origin, $propertyPath, $targetPath)
38 {
39 $this->origin = $origin;
40 $this->propertyPath = $propertyPath;
41 $this->targetPath = $targetPath;
42 }
43
44 /**
45 * @return FormInterface
46 */
47 public function getOrigin()
48 {
49 return $this->origin;
50 }
51
52 /**
53 * Matches a property path against the rule path.
54 *
55 * If the rule matches, the form mapped by the rule is returned.
56 * Otherwise this method returns false.
57 *
58 * @param string $propertyPath The property path to match against the rule.
59 *
60 * @return null|FormInterface The mapped form or null.
61 */
62 public function match($propertyPath)
63 {
64 if ($propertyPath === (string) $this->propertyPath) {
65 return $this->getTarget();
66 }
67
68 return null;
69 }
70
71 /**
72 * Matches a property path against a prefix of the rule path.
73 *
74 * @param string $propertyPath The property path to match against the rule.
75 *
76 * @return Boolean Whether the property path is a prefix of the rule or not.
77 */
78 public function isPrefix($propertyPath)
79 {
80 $length = strlen($propertyPath);
81 $prefix = substr($this->propertyPath, 0, $length);
82 $next = isset($this->propertyPath[$length]) ? $this->propertyPath[$length] : null;
83
84 return $prefix === $propertyPath && ('[' === $next || '.' === $next);
85 }
86
87 /**
88 * @return FormInterface
89 *
90 * @throws ErrorMappingException
91 */
92 public function getTarget()
93 {
94 $childNames = explode('.', $this->targetPath);
95 $target = $this->origin;
96
97 foreach ($childNames as $childName) {
98 if (!$target->has($childName)) {
99 throw new ErrorMappingException(sprintf('The child "%s" of "%s" mapped by the rule "%s" in "%s" does not exist.', $childName, $target->getName(), $this->targetPath, $this->origin->getName()));
100 }
101 $target = $target->get($childName);
102 }
103
104 return $target;
105 }
106}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php
new file mode 100644
index 00000000..ef5c9fad
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
13
14use Symfony\Component\Form\FormInterface;
15use Symfony\Component\PropertyAccess\PropertyPath;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class RelativePath extends PropertyPath
21{
22 /**
23 * @var FormInterface
24 */
25 private $root;
26
27 /**
28 * @param FormInterface $root
29 * @param string $propertyPath
30 */
31 public function __construct(FormInterface $root, $propertyPath)
32 {
33 parent::__construct($propertyPath);
34
35 $this->root = $root;
36 }
37
38 /**
39 * @return FormInterface
40 */
41 public function getRoot()
42 {
43 return $this->root;
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
new file mode 100644
index 00000000..8a7636c7
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
@@ -0,0 +1,299 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
13
14use Symfony\Component\Form\FormInterface;
15use Symfony\Component\Form\Util\InheritDataAwareIterator;
16use Symfony\Component\PropertyAccess\PropertyPathIterator;
17use Symfony\Component\PropertyAccess\PropertyPathBuilder;
18use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface;
19use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationPathIterator;
20use Symfony\Component\Form\FormError;
21use Symfony\Component\Validator\ConstraintViolation;
22
23/**
24 * @author Bernhard Schussek <bschussek@gmail.com>
25 */
26class ViolationMapper implements ViolationMapperInterface
27{
28 /**
29 * @var Boolean
30 */
31 private $allowNonSynchronized;
32
33 /**
34 * {@inheritdoc}
35 */
36 public function mapViolation(ConstraintViolation $violation, FormInterface $form, $allowNonSynchronized = false)
37 {
38 $this->allowNonSynchronized = $allowNonSynchronized;
39
40 // The scope is the currently found most specific form that
41 // an error should be mapped to. After setting the scope, the
42 // mapper will try to continue to find more specific matches in
43 // the children of scope. If it cannot, the error will be
44 // mapped to this scope.
45 $scope = null;
46
47 $violationPath = null;
48 $relativePath = null;
49 $match = false;
50
51 // Don't create a ViolationPath instance for empty property paths
52 if (strlen($violation->getPropertyPath()) > 0) {
53 $violationPath = new ViolationPath($violation->getPropertyPath());
54 $relativePath = $this->reconstructPath($violationPath, $form);
55 }
56
57 // This case happens if the violation path is empty and thus
58 // the violation should be mapped to the root form
59 if (null === $violationPath) {
60 $scope = $form;
61 }
62
63 // In general, mapping happens from the root form to the leaf forms
64 // First, the rules of the root form are applied to determine
65 // the subsequent descendant. The rules of this descendant are then
66 // applied to find the next and so on, until we have found the
67 // most specific form that matches the violation.
68
69 // If any of the forms found in this process is not synchronized,
70 // mapping is aborted. Non-synchronized forms could not reverse
71 // transform the value entered by the user, thus any further violations
72 // caused by the (invalid) reverse transformed value should be
73 // ignored.
74
75 if (null !== $relativePath) {
76 // Set the scope to the root of the relative path
77 // This root will usually be $form. If the path contains
78 // an unmapped form though, the last unmapped form found
79 // will be the root of the path.
80 $scope = $relativePath->getRoot();
81 $it = new PropertyPathIterator($relativePath);
82
83 while ($this->acceptsErrors($scope) && null !== ($child = $this->matchChild($scope, $it))) {
84 $scope = $child;
85 $it->next();
86 $match = true;
87 }
88 }
89
90 // This case happens if an error happened in the data under a
91 // form inheriting its parent data that does not match any of the
92 // children of that form.
93 if (null !== $violationPath && !$match) {
94 // If we could not map the error to anything more specific
95 // than the root element, map it to the innermost directly
96 // mapped form of the violation path
97 // e.g. "children[foo].children[bar].data.baz"
98 // Here the innermost directly mapped child is "bar"
99
100 $scope = $form;
101 $it = new ViolationPathIterator($violationPath);
102
103 // Note: acceptsErrors() will always return true for forms inheriting
104 // their parent data, because these forms can never be non-synchronized
105 // (they don't do any data transformation on their own)
106 while ($this->acceptsErrors($scope) && $it->valid() && $it->mapsForm()) {
107 if (!$scope->has($it->current())) {
108 // Break if we find a reference to a non-existing child
109 break;
110 }
111
112 $scope = $scope->get($it->current());
113 $it->next();
114 }
115 }
116
117 // Follow dot rules until we have the final target
118 $mapping = $scope->getConfig()->getOption('error_mapping');
119
120 while ($this->acceptsErrors($scope) && isset($mapping['.'])) {
121 $dotRule = new MappingRule($scope, '.', $mapping['.']);
122 $scope = $dotRule->getTarget();
123 $mapping = $scope->getConfig()->getOption('error_mapping');
124 }
125
126 // Only add the error if the form is synchronized
127 if ($this->acceptsErrors($scope)) {
128 $scope->addError(new FormError(
129 $violation->getMessage(),
130 $violation->getMessageTemplate(),
131 $violation->getMessageParameters(),
132 $violation->getMessagePluralization()
133 ));
134 }
135 }
136
137 /**
138 * Tries to match the beginning of the property path at the
139 * current position against the children of the scope.
140 *
141 * If a matching child is found, it is returned. Otherwise
142 * null is returned.
143 *
144 * @param FormInterface $form The form to search.
145 * @param PropertyPathIteratorInterface $it The iterator at its current position.
146 *
147 * @return null|FormInterface The found match or null.
148 */
149 private function matchChild(FormInterface $form, PropertyPathIteratorInterface $it)
150 {
151 // Remember at what property path underneath "data"
152 // we are looking. Check if there is a child with that
153 // path, otherwise increase path by one more piece
154 $chunk = '';
155 $foundChild = null;
156 $foundAtIndex = 0;
157
158 // Construct mapping rules for the given form
159 $rules = array();
160
161 foreach ($form->getConfig()->getOption('error_mapping') as $propertyPath => $targetPath) {
162 // Dot rules are considered at the very end
163 if ('.' !== $propertyPath) {
164 $rules[] = new MappingRule($form, $propertyPath, $targetPath);
165 }
166 }
167
168 // Skip forms inheriting their parent data when iterating the children
169 $childIterator = new \RecursiveIteratorIterator(
170 new InheritDataAwareIterator($form->all())
171 );
172
173 // Make the path longer until we find a matching child
174 while (true) {
175 if (!$it->valid()) {
176 return null;
177 }
178
179 if ($it->isIndex()) {
180 $chunk .= '['.$it->current().']';
181 } else {
182 $chunk .= ('' === $chunk ? '' : '.').$it->current();
183 }
184
185 // Test mapping rules as long as we have any
186 foreach ($rules as $key => $rule) {
187 /* @var MappingRule $rule */
188
189 // Mapping rule matches completely, terminate.
190 if (null !== ($form = $rule->match($chunk))) {
191 return $form;
192 }
193
194 // Keep only rules that have $chunk as prefix
195 if (!$rule->isPrefix($chunk)) {
196 unset($rules[$key]);
197 }
198 }
199
200 // Test children unless we already found one
201 if (null === $foundChild) {
202 foreach ($childIterator as $child) {
203 /* @var FormInterface $child */
204 $childPath = (string) $child->getPropertyPath();
205
206 // Child found, mark as return value
207 if ($chunk === $childPath) {
208 $foundChild = $child;
209 $foundAtIndex = $it->key();
210 }
211 }
212 }
213
214 // Add element to the chunk
215 $it->next();
216
217 // If we reached the end of the path or if there are no
218 // more matching mapping rules, return the found child
219 if (null !== $foundChild && (!$it->valid() || count($rules) === 0)) {
220 // Reset index in case we tried to find mapping
221 // rules further down the path
222 $it->seek($foundAtIndex);
223
224 return $foundChild;
225 }
226 }
227
228 return null;
229 }
230
231 /**
232 * Reconstructs a property path from a violation path and a form tree.
233 *
234 * @param ViolationPath $violationPath The violation path.
235 * @param FormInterface $origin The root form of the tree.
236 *
237 * @return RelativePath The reconstructed path.
238 */
239 private function reconstructPath(ViolationPath $violationPath, FormInterface $origin)
240 {
241 $propertyPathBuilder = new PropertyPathBuilder($violationPath);
242 $it = $violationPath->getIterator();
243 $scope = $origin;
244
245 // Remember the current index in the builder
246 $i = 0;
247
248 // Expand elements that map to a form (like "children[address]")
249 for ($it->rewind(); $it->valid() && $it->mapsForm(); $it->next()) {
250 if (!$scope->has($it->current())) {
251 // Scope relates to a form that does not exist
252 // Bail out
253 break;
254 }
255
256 // Process child form
257 $scope = $scope->get($it->current());
258
259 if ($scope->getConfig()->getInheritData()) {
260 // Form inherits its parent data
261 // Cut the piece out of the property path and proceed
262 $propertyPathBuilder->remove($i);
263 } elseif (!$scope->getConfig()->getMapped()) {
264 // Form is not mapped
265 // Set the form as new origin and strip everything
266 // we have so far in the path
267 $origin = $scope;
268 $propertyPathBuilder->remove(0, $i + 1);
269 $i = 0;
270 } else {
271 /* @var \Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath */
272 $propertyPath = $scope->getPropertyPath();
273
274 if (null === $propertyPath) {
275 // Property path of a mapped form is null
276 // Should not happen, bail out
277 break;
278 }
279
280 $propertyPathBuilder->replace($i, 1, $propertyPath);
281 $i += $propertyPath->getLength();
282 }
283 }
284
285 $finalPath = $propertyPathBuilder->getPropertyPath();
286
287 return null !== $finalPath ? new RelativePath($origin, $finalPath) : null;
288 }
289
290 /**
291 * @param FormInterface $form
292 *
293 * @return Boolean
294 */
295 private function acceptsErrors(FormInterface $form)
296 {
297 return $this->allowNonSynchronized || $form->isSynchronized();
298 }
299}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php
new file mode 100644
index 00000000..eb8907f1
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
13
14use Symfony\Component\Form\FormInterface;
15use Symfony\Component\Validator\ConstraintViolation;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20interface ViolationMapperInterface
21{
22 /**
23 * Maps a constraint violation to a form in the form tree under
24 * the given form.
25 *
26 * @param ConstraintViolation $violation The violation to map.
27 * @param FormInterface $form The root form of the tree
28 * to map it to.
29 * @param Boolean $allowNonSynchronized Whether to allow
30 * mapping to non-synchronized forms.
31 */
32 public function mapViolation(ConstraintViolation $violation, FormInterface $form, $allowNonSynchronized = false);
33}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php
new file mode 100644
index 00000000..06d09195
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php
@@ -0,0 +1,250 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
13
14use Symfony\Component\Form\Exception\OutOfBoundsException;
15use Symfony\Component\PropertyAccess\PropertyPath;
16use Symfony\Component\PropertyAccess\PropertyPathInterface;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ViolationPath implements \IteratorAggregate, PropertyPathInterface
22{
23 /**
24 * @var array
25 */
26 private $elements = array();
27
28 /**
29 * @var array
30 */
31 private $isIndex = array();
32
33 /**
34 * @var array
35 */
36 private $mapsForm = array();
37
38 /**
39 * @var string
40 */
41 private $pathAsString = '';
42
43 /**
44 * @var integer
45 */
46 private $length = 0;
47
48 /**
49 * Creates a new violation path from a string.
50 *
51 * @param string $violationPath The property path of a {@link ConstraintViolation}
52 * object.
53 */
54 public function __construct($violationPath)
55 {
56 $path = new PropertyPath($violationPath);
57 $elements = $path->getElements();
58 $data = false;
59
60 for ($i = 0, $l = count($elements); $i < $l; ++$i) {
61 if (!$data) {
62 // The element "data" has not yet been passed
63 if ('children' === $elements[$i] && $path->isProperty($i)) {
64 // Skip element "children"
65 ++$i;
66
67 // Next element must exist and must be an index
68 // Otherwise consider this the end of the path
69 if ($i >= $l || !$path->isIndex($i)) {
70 break;
71 }
72
73 $this->elements[] = $elements[$i];
74 $this->isIndex[] = true;
75 $this->mapsForm[] = true;
76 } elseif ('data' === $elements[$i] && $path->isProperty($i)) {
77 // Skip element "data"
78 ++$i;
79
80 // End of path
81 if ($i >= $l) {
82 break;
83 }
84
85 $this->elements[] = $elements[$i];
86 $this->isIndex[] = $path->isIndex($i);
87 $this->mapsForm[] = false;
88 $data = true;
89 } else {
90 // Neither "children" nor "data" property found
91 // Consider this the end of the path
92 break;
93 }
94 } else {
95 // Already after the "data" element
96 // Pick everything as is
97 $this->elements[] = $elements[$i];
98 $this->isIndex[] = $path->isIndex($i);
99 $this->mapsForm[] = false;
100 }
101 }
102
103 $this->length = count($this->elements);
104
105 $this->buildString();
106 }
107
108 /**
109 * {@inheritdoc}
110 */
111 public function __toString()
112 {
113 return $this->pathAsString;
114 }
115
116 /**
117 * {@inheritdoc}
118 */
119 public function getLength()
120 {
121 return $this->length;
122 }
123
124 /**
125 * {@inheritdoc}
126 */
127 public function getParent()
128 {
129 if ($this->length <= 1) {
130 return null;
131 }
132
133 $parent = clone $this;
134
135 --$parent->length;
136 array_pop($parent->elements);
137 array_pop($parent->isIndex);
138 array_pop($parent->mapsForm);
139
140 $parent->buildString();
141
142 return $parent;
143 }
144
145 /**
146 * {@inheritdoc}
147 */
148 public function getElements()
149 {
150 return $this->elements;
151 }
152
153 /**
154 * {@inheritdoc}
155 */
156 public function getElement($index)
157 {
158 if (!isset($this->elements[$index])) {
159 throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
160 }
161
162 return $this->elements[$index];
163 }
164
165 /**
166 * {@inheritdoc}
167 */
168 public function isProperty($index)
169 {
170 if (!isset($this->isIndex[$index])) {
171 throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
172 }
173
174 return !$this->isIndex[$index];
175 }
176
177 /**
178 * {@inheritdoc}
179 */
180 public function isIndex($index)
181 {
182 if (!isset($this->isIndex[$index])) {
183 throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
184 }
185
186 return $this->isIndex[$index];
187 }
188
189 /**
190 * Returns whether an element maps directly to a form.
191 *
192 * Consider the following violation path:
193 *
194 * <code>
195 * children[address].children[office].data.street
196 * </code>
197 *
198 * In this example, "address" and "office" map to forms, while
199 * "street does not.
200 *
201 * @param integer $index The element index.
202 *
203 * @return Boolean Whether the element maps to a form.
204 *
205 * @throws OutOfBoundsException If the offset is invalid.
206 */
207 public function mapsForm($index)
208 {
209 if (!isset($this->mapsForm[$index])) {
210 throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
211 }
212
213 return $this->mapsForm[$index];
214 }
215
216 /**
217 * Returns a new iterator for this path
218 *
219 * @return ViolationPathIterator
220 */
221 public function getIterator()
222 {
223 return new ViolationPathIterator($this);
224 }
225
226 /**
227 * Builds the string representation from the elements.
228 */
229 private function buildString()
230 {
231 $this->pathAsString = '';
232 $data = false;
233
234 foreach ($this->elements as $index => $element) {
235 if ($this->mapsForm[$index]) {
236 $this->pathAsString .= ".children[$element]";
237 } elseif (!$data) {
238 $this->pathAsString .= '.data'.($this->isIndex[$index] ? "[$element]" : ".$element");
239 $data = true;
240 } else {
241 $this->pathAsString .= $this->isIndex[$index] ? "[$element]" : ".$element";
242 }
243 }
244
245 if ('' !== $this->pathAsString) {
246 // remove leading dot
247 $this->pathAsString = substr($this->pathAsString, 1);
248 }
249 }
250}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php
new file mode 100644
index 00000000..50baa453
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php
@@ -0,0 +1,30 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
13
14use Symfony\Component\PropertyAccess\PropertyPathIterator;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class ViolationPathIterator extends PropertyPathIterator
20{
21 public function __construct(ViolationPath $violationPath)
22 {
23 parent::__construct($violationPath);
24 }
25
26 public function mapsForm()
27 {
28 return $this->path->mapsForm($this->key());
29 }
30}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Form.php b/vendor/symfony/form/Symfony/Component/Form/Form.php
new file mode 100644
index 00000000..35135274
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Form.php
@@ -0,0 +1,1046 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\RuntimeException;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16use Symfony\Component\Form\Exception\AlreadySubmittedException;
17use Symfony\Component\Form\Exception\TransformationFailedException;
18use Symfony\Component\Form\Exception\LogicException;
19use Symfony\Component\Form\Exception\OutOfBoundsException;
20use Symfony\Component\Form\Util\FormUtil;
21use Symfony\Component\Form\Util\InheritDataAwareIterator;
22use Symfony\Component\PropertyAccess\PropertyPath;
23
24/**
25 * Form represents a form.
26 *
27 * To implement your own form fields, you need to have a thorough understanding
28 * of the data flow within a form. A form stores its data in three different
29 * representations:
30 *
31 * (1) the "model" format required by the form's object
32 * (2) the "normalized" format for internal processing
33 * (3) the "view" format used for display
34 *
35 * A date field, for example, may store a date as "Y-m-d" string (1) in the
36 * object. To facilitate processing in the field, this value is normalized
37 * to a DateTime object (2). In the HTML representation of your form, a
38 * localized string (3) is presented to and modified by the user.
39 *
40 * In most cases, format (1) and format (2) will be the same. For example,
41 * a checkbox field uses a Boolean value for both internal processing and
42 * storage in the object. In these cases you simply need to set a value
43 * transformer to convert between formats (2) and (3). You can do this by
44 * calling addViewTransformer().
45 *
46 * In some cases though it makes sense to make format (1) configurable. To
47 * demonstrate this, let's extend our above date field to store the value
48 * either as "Y-m-d" string or as timestamp. Internally we still want to
49 * use a DateTime object for processing. To convert the data from string/integer
50 * to DateTime you can set a normalization transformer by calling
51 * addNormTransformer(). The normalized data is then converted to the displayed
52 * data as described before.
53 *
54 * The conversions (1) -> (2) -> (3) use the transform methods of the transformers.
55 * The conversions (3) -> (2) -> (1) use the reverseTransform methods of the transformers.
56 *
57 * @author Fabien Potencier <fabien@symfony.com>
58 * @author Bernhard Schussek <bschussek@gmail.com>
59 */
60class Form implements \IteratorAggregate, FormInterface
61{
62 /**
63 * The form's configuration
64 * @var FormConfigInterface
65 */
66 private $config;
67
68 /**
69 * The parent of this form
70 * @var FormInterface
71 */
72 private $parent;
73
74 /**
75 * The children of this form
76 * @var FormInterface[] An array of FormInterface instances
77 */
78 private $children = array();
79
80 /**
81 * The errors of this form
82 * @var FormError[] An array of FormError instances
83 */
84 private $errors = array();
85
86 /**
87 * Whether this form was submitted
88 * @var Boolean
89 */
90 private $submitted = false;
91
92 /**
93 * The form data in model format
94 * @var mixed
95 */
96 private $modelData;
97
98 /**
99 * The form data in normalized format
100 * @var mixed
101 */
102 private $normData;
103
104 /**
105 * The form data in view format
106 * @var mixed
107 */
108 private $viewData;
109
110 /**
111 * The submitted values that don't belong to any children
112 * @var array
113 */
114 private $extraData = array();
115
116 /**
117 * Whether the data in model, normalized and view format is
118 * synchronized. Data may not be synchronized if transformation errors
119 * occur.
120 * @var Boolean
121 */
122 private $synchronized = true;
123
124 /**
125 * Whether the form's data has been initialized.
126 *
127 * When the data is initialized with its default value, that default value
128 * is passed through the transformer chain in order to synchronize the
129 * model, normalized and view format for the first time. This is done
130 * lazily in order to save performance when {@link setData()} is called
131 * manually, making the initialization with the configured default value
132 * superfluous.
133 *
134 * @var Boolean
135 */
136 private $defaultDataSet = false;
137
138 /**
139 * Whether setData() is currently being called.
140 * @var Boolean
141 */
142 private $lockSetData = false;
143
144 /**
145 * Creates a new form based on the given configuration.
146 *
147 * @param FormConfigInterface $config The form configuration.
148 *
149 * @throws LogicException if a data mapper is not provided for a compound form
150 */
151 public function __construct(FormConfigInterface $config)
152 {
153 // Compound forms always need a data mapper, otherwise calls to
154 // `setData` and `add` will not lead to the correct population of
155 // the child forms.
156 if ($config->getCompound() && !$config->getDataMapper()) {
157 throw new LogicException('Compound forms need a data mapper');
158 }
159
160 // If the form inherits the data from its parent, it is not necessary
161 // to call setData() with the default data.
162 if ($config->getInheritData()) {
163 $this->defaultDataSet = true;
164 }
165
166 $this->config = $config;
167 }
168
169 public function __clone()
170 {
171 foreach ($this->children as $key => $child) {
172 $this->children[$key] = clone $child;
173 }
174 }
175
176 /**
177 * {@inheritdoc}
178 */
179 public function getConfig()
180 {
181 return $this->config;
182 }
183
184 /**
185 * {@inheritdoc}
186 */
187 public function getName()
188 {
189 return $this->config->getName();
190 }
191
192 /**
193 * {@inheritdoc}
194 */
195 public function getPropertyPath()
196 {
197 if (null !== $this->config->getPropertyPath()) {
198 return $this->config->getPropertyPath();
199 }
200
201 if (null === $this->getName() || '' === $this->getName()) {
202 return null;
203 }
204
205 $parent = $this->parent;
206
207 while ($parent && $parent->getConfig()->getInheritData()) {
208 $parent = $parent->getParent();
209 }
210
211 if ($parent && null === $parent->getConfig()->getDataClass()) {
212 return new PropertyPath('['.$this->getName().']');
213 }
214
215 return new PropertyPath($this->getName());
216 }
217
218 /**
219 * {@inheritdoc}
220 */
221 public function isRequired()
222 {
223 if (null === $this->parent || $this->parent->isRequired()) {
224 return $this->config->getRequired();
225 }
226
227 return false;
228 }
229
230 /**
231 * {@inheritDoc}
232 */
233 public function isDisabled()
234 {
235 if (null === $this->parent || !$this->parent->isDisabled()) {
236 return $this->config->getDisabled();
237 }
238
239 return true;
240 }
241
242 /**
243 * {@inheritdoc}
244 */
245 public function setParent(FormInterface $parent = null)
246 {
247 if ($this->submitted) {
248 throw new AlreadySubmittedException('You cannot set the parent of a submitted form');
249 }
250
251 if (null !== $parent && '' === $this->config->getName()) {
252 throw new LogicException('A form with an empty name cannot have a parent form.');
253 }
254
255 $this->parent = $parent;
256
257 return $this;
258 }
259
260 /**
261 * {@inheritdoc}
262 */
263 public function getParent()
264 {
265 return $this->parent;
266 }
267
268 /**
269 * {@inheritdoc}
270 */
271 public function getRoot()
272 {
273 return $this->parent ? $this->parent->getRoot() : $this;
274 }
275
276 /**
277 * {@inheritdoc}
278 */
279 public function isRoot()
280 {
281 return null === $this->parent;
282 }
283
284 /**
285 * {@inheritdoc}
286 */
287 public function setData($modelData)
288 {
289 // If the form is submitted while disabled, it is set to submitted, but the data is not
290 // changed. In such cases (i.e. when the form is not initialized yet) don't
291 // abort this method.
292 if ($this->submitted && $this->defaultDataSet) {
293 throw new AlreadySubmittedException('You cannot change the data of a submitted form.');
294 }
295
296 // If the form inherits its parent's data, disallow data setting to
297 // prevent merge conflicts
298 if ($this->config->getInheritData()) {
299 throw new RuntimeException('You cannot change the data of a form inheriting its parent data.');
300 }
301
302 // Don't allow modifications of the configured data if the data is locked
303 if ($this->config->getDataLocked() && $modelData !== $this->config->getData()) {
304 return $this;
305 }
306
307 if (is_object($modelData) && !$this->config->getByReference()) {
308 $modelData = clone $modelData;
309 }
310
311 if ($this->lockSetData) {
312 throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call setData(). You should call setData() on the FormEvent object instead.');
313 }
314
315 $this->lockSetData = true;
316 $dispatcher = $this->config->getEventDispatcher();
317
318 // Hook to change content of the data
319 if ($dispatcher->hasListeners(FormEvents::PRE_SET_DATA)) {
320 $event = new FormEvent($this, $modelData);
321 $dispatcher->dispatch(FormEvents::PRE_SET_DATA, $event);
322 $modelData = $event->getData();
323 }
324
325 // Treat data as strings unless a value transformer exists
326 if (!$this->config->getViewTransformers() && !$this->config->getModelTransformers() && is_scalar($modelData)) {
327 $modelData = (string) $modelData;
328 }
329
330 // Synchronize representations - must not change the content!
331 $normData = $this->modelToNorm($modelData);
332 $viewData = $this->normToView($normData);
333
334 // Validate if view data matches data class (unless empty)
335 if (!FormUtil::isEmpty($viewData)) {
336 $dataClass = $this->config->getDataClass();
337
338 $actualType = is_object($viewData) ? 'an instance of class '.get_class($viewData) : ' a(n) '.gettype($viewData);
339
340 if (null === $dataClass && is_object($viewData) && !$viewData instanceof \ArrayAccess) {
341 $expectedType = 'scalar, array or an instance of \ArrayAccess';
342
343 throw new LogicException(
344 'The form\'s view data is expected to be of type '.$expectedType.', ' .
345 'but is '.$actualType.'. You ' .
346 'can avoid this error by setting the "data_class" option to ' .
347 '"'.get_class($viewData).'" or by adding a view transformer ' .
348 'that transforms '.$actualType.' to '.$expectedType.'.'
349 );
350 }
351
352 if (null !== $dataClass && !$viewData instanceof $dataClass) {
353 throw new LogicException(
354 'The form\'s view data is expected to be an instance of class ' .
355 $dataClass.', but is '. $actualType.'. You can avoid this error ' .
356 'by setting the "data_class" option to null or by adding a view ' .
357 'transformer that transforms '.$actualType.' to an instance of ' .
358 $dataClass.'.'
359 );
360 }
361 }
362
363 $this->modelData = $modelData;
364 $this->normData = $normData;
365 $this->viewData = $viewData;
366 $this->defaultDataSet = true;
367 $this->lockSetData = false;
368
369 // It is not necessary to invoke this method if the form doesn't have children,
370 // even if the form is compound.
371 if (count($this->children) > 0) {
372 // Update child forms from the data
373 $childrenIterator = new InheritDataAwareIterator($this->children);
374 $childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
375 $this->config->getDataMapper()->mapDataToForms($viewData, $childrenIterator);
376 }
377
378 if ($dispatcher->hasListeners(FormEvents::POST_SET_DATA)) {
379 $event = new FormEvent($this, $modelData);
380 $dispatcher->dispatch(FormEvents::POST_SET_DATA, $event);
381 }
382
383 return $this;
384 }
385
386 /**
387 * {@inheritdoc}
388 */
389 public function getData()
390 {
391 if ($this->config->getInheritData()) {
392 if (!$this->parent) {
393 throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
394 }
395
396 return $this->parent->getData();
397 }
398
399 if (!$this->defaultDataSet) {
400 $this->setData($this->config->getData());
401 }
402
403 return $this->modelData;
404 }
405
406 /**
407 * {@inheritdoc}
408 */
409 public function getNormData()
410 {
411 if ($this->config->getInheritData()) {
412 if (!$this->parent) {
413 throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
414 }
415
416 return $this->parent->getNormData();
417 }
418
419 if (!$this->defaultDataSet) {
420 $this->setData($this->config->getData());
421 }
422
423 return $this->normData;
424 }
425
426 /**
427 * {@inheritdoc}
428 */
429 public function getViewData()
430 {
431 if ($this->config->getInheritData()) {
432 if (!$this->parent) {
433 throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
434 }
435
436 return $this->parent->getViewData();
437 }
438
439 if (!$this->defaultDataSet) {
440 $this->setData($this->config->getData());
441 }
442
443 return $this->viewData;
444 }
445
446 /**
447 * {@inheritdoc}
448 */
449 public function getExtraData()
450 {
451 return $this->extraData;
452 }
453
454 /**
455 * {@inheritdoc}
456 */
457 public function initialize()
458 {
459 if (null !== $this->parent) {
460 throw new RuntimeException('Only root forms should be initialized.');
461 }
462
463 // Guarantee that the *_SET_DATA events have been triggered once the
464 // form is initialized. This makes sure that dynamically added or
465 // removed fields are already visible after initialization.
466 if (!$this->defaultDataSet) {
467 $this->setData($this->config->getData());
468 }
469
470 return $this;
471 }
472
473 /**
474 * {@inheritdoc}
475 */
476 public function handleRequest($request = null)
477 {
478 $this->config->getRequestHandler()->handleRequest($this, $request);
479
480 return $this;
481 }
482
483 /**
484 * {@inheritdoc}
485 */
486 public function submit($submittedData, $clearMissing = true)
487 {
488 if ($this->submitted) {
489 throw new AlreadySubmittedException('A form can only be submitted once');
490 }
491
492 // Initialize errors in the very beginning so that we don't lose any
493 // errors added during listeners
494 $this->errors = array();
495
496 // Obviously, a disabled form should not change its data upon submission.
497 if ($this->isDisabled()) {
498 $this->submitted = true;
499
500 return $this;
501 }
502
503 // The data must be initialized if it was not initialized yet.
504 // This is necessary to guarantee that the *_SET_DATA listeners
505 // are always invoked before submit() takes place.
506 if (!$this->defaultDataSet) {
507 $this->setData($this->config->getData());
508 }
509
510 // Treat false as NULL to support binding false to checkboxes.
511 // Don't convert NULL to a string here in order to determine later
512 // whether an empty value has been submitted or whether no value has
513 // been submitted at all. This is important for processing checkboxes
514 // and radio buttons with empty values.
515 if (false === $submittedData) {
516 $submittedData = null;
517 } elseif (is_scalar($submittedData)) {
518 $submittedData = (string) $submittedData;
519 }
520
521 $dispatcher = $this->config->getEventDispatcher();
522
523 // Hook to change content of the data submitted by the browser
524 if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
525 $event = new FormEvent($this, $submittedData);
526 $dispatcher->dispatch(FormEvents::PRE_SUBMIT, $event);
527 $submittedData = $event->getData();
528 }
529
530 // Check whether the form is compound.
531 // This check is preferable over checking the number of children,
532 // since forms without children may also be compound.
533 // (think of empty collection forms)
534 if ($this->config->getCompound()) {
535 if (!is_array($submittedData)) {
536 $submittedData = array();
537 }
538
539 foreach ($this->children as $name => $child) {
540 if (isset($submittedData[$name]) || $clearMissing) {
541 $child->submit(isset($submittedData[$name]) ? $submittedData[$name] : null, $clearMissing);
542 unset($submittedData[$name]);
543 }
544 }
545
546 $this->extraData = $submittedData;
547 }
548
549 // Forms that inherit their parents' data also are not processed,
550 // because then it would be too difficult to merge the changes in
551 // the child and the parent form. Instead, the parent form also takes
552 // changes in the grandchildren (i.e. children of the form that inherits
553 // its parent's data) into account.
554 // (see InheritDataAwareIterator below)
555 if ($this->config->getInheritData()) {
556 $this->submitted = true;
557
558 // When POST_SUBMIT is reached, the data is not yet updated, so pass
559 // NULL to prevent hard-to-debug bugs.
560 $dataForPostSubmit = null;
561 } else {
562 // If the form is compound, the default data in view format
563 // is reused. The data of the children is merged into this
564 // default data using the data mapper.
565 // If the form is not compound, the submitted data is also the data in view format.
566 $viewData = $this->config->getCompound() ? $this->viewData : $submittedData;
567
568 if (FormUtil::isEmpty($viewData)) {
569 $emptyData = $this->config->getEmptyData();
570
571 if ($emptyData instanceof \Closure) {
572 /* @var \Closure $emptyData */
573 $emptyData = $emptyData($this, $viewData);
574 }
575
576 $viewData = $emptyData;
577 }
578
579 // Merge form data from children into existing view data
580 // It is not necessary to invoke this method if the form has no children,
581 // even if it is compound.
582 if (count($this->children) > 0) {
583 // Use InheritDataAwareIterator to process children of
584 // descendants that inherit this form's data.
585 // These descendants will not be submitted normally (see the check
586 // for $this->config->getInheritData() above)
587 $childrenIterator = new InheritDataAwareIterator($this->children);
588 $childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
589 $this->config->getDataMapper()->mapFormsToData($childrenIterator, $viewData);
590 }
591
592 $modelData = null;
593 $normData = null;
594
595 try {
596 // Normalize data to unified representation
597 $normData = $this->viewToNorm($viewData);
598
599 // Hook to change content of the data into the normalized
600 // representation
601 if ($dispatcher->hasListeners(FormEvents::SUBMIT)) {
602 $event = new FormEvent($this, $normData);
603 $dispatcher->dispatch(FormEvents::SUBMIT, $event);
604 $normData = $event->getData();
605 }
606
607 // Synchronize representations - must not change the content!
608 $modelData = $this->normToModel($normData);
609 $viewData = $this->normToView($normData);
610 } catch (TransformationFailedException $e) {
611 $this->synchronized = false;
612 }
613
614 $this->submitted = true;
615 $this->modelData = $modelData;
616 $this->normData = $normData;
617 $this->viewData = $viewData;
618
619 $dataForPostSubmit = $viewData;
620 }
621
622 if ($dispatcher->hasListeners(FormEvents::POST_SUBMIT)) {
623 $event = new FormEvent($this, $dataForPostSubmit);
624 $dispatcher->dispatch(FormEvents::POST_SUBMIT, $event);
625 }
626
627 return $this;
628 }
629
630 /**
631 * Alias of {@link submit()}.
632 *
633 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
634 * {@link submit()} instead.
635 */
636 public function bind($submittedData)
637 {
638 return $this->submit($submittedData);
639 }
640
641 /**
642 * {@inheritdoc}
643 */
644 public function addError(FormError $error)
645 {
646 if ($this->parent && $this->config->getErrorBubbling()) {
647 $this->parent->addError($error);
648 } else {
649 $this->errors[] = $error;
650 }
651
652 return $this;
653 }
654
655 /**
656 * {@inheritdoc}
657 */
658 public function isSubmitted()
659 {
660 return $this->submitted;
661 }
662
663 /**
664 * Alias of {@link isSubmitted()}.
665 *
666 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
667 * {@link isSubmitted()} instead.
668 */
669 public function isBound()
670 {
671 return $this->submitted;
672 }
673
674 /**
675 * {@inheritdoc}
676 */
677 public function isSynchronized()
678 {
679 return $this->synchronized;
680 }
681
682 /**
683 * {@inheritdoc}
684 */
685 public function isEmpty()
686 {
687 foreach ($this->children as $child) {
688 if (!$child->isEmpty()) {
689 return false;
690 }
691 }
692
693 return FormUtil::isEmpty($this->modelData) ||
694 // arrays, countables
695 0 === count($this->modelData) ||
696 // traversables that are not countable
697 ($this->modelData instanceof \Traversable && 0 === iterator_count($this->modelData));
698 }
699
700 /**
701 * {@inheritdoc}
702 */
703 public function isValid()
704 {
705 if (!$this->submitted) {
706 return false;
707 }
708
709 if (count($this->errors) > 0) {
710 return false;
711 }
712
713 if (!$this->isDisabled()) {
714 foreach ($this->children as $child) {
715 if (!$child->isValid()) {
716 return false;
717 }
718 }
719 }
720
721 return true;
722 }
723
724 /**
725 * {@inheritdoc}
726 */
727 public function getErrors()
728 {
729 return $this->errors;
730 }
731
732 /**
733 * Returns a string representation of all form errors (including children errors).
734 *
735 * This method should only be used to help debug a form.
736 *
737 * @param integer $level The indentation level (used internally)
738 *
739 * @return string A string representation of all errors
740 */
741 public function getErrorsAsString($level = 0)
742 {
743 $errors = '';
744 foreach ($this->errors as $error) {
745 $errors .= str_repeat(' ', $level).'ERROR: '.$error->getMessage()."\n";
746 }
747
748 foreach ($this->children as $key => $child) {
749 $errors .= str_repeat(' ', $level).$key.":\n";
750 if ($err = $child->getErrorsAsString($level + 4)) {
751 $errors .= $err;
752 } else {
753 $errors .= str_repeat(' ', $level + 4)."No errors\n";
754 }
755 }
756
757 return $errors;
758 }
759
760 /**
761 * {@inheritdoc}
762 */
763 public function all()
764 {
765 return $this->children;
766 }
767
768 /**
769 * {@inheritdoc}
770 */
771 public function add($child, $type = null, array $options = array())
772 {
773 if ($this->submitted) {
774 throw new AlreadySubmittedException('You cannot add children to a submitted form');
775 }
776
777 if (!$this->config->getCompound()) {
778 throw new LogicException('You cannot add children to a simple form. Maybe you should set the option "compound" to true?');
779 }
780
781 // Obtain the view data
782 $viewData = null;
783
784 // If setData() is currently being called, there is no need to call
785 // mapDataToForms() here, as mapDataToForms() is called at the end
786 // of setData() anyway. Not doing this check leads to an endless
787 // recursion when initializing the form lazily and an event listener
788 // (such as ResizeFormListener) adds fields depending on the data:
789 //
790 // * setData() is called, the form is not initialized yet
791 // * add() is called by the listener (setData() is not complete, so
792 // the form is still not initialized)
793 // * getViewData() is called
794 // * setData() is called since the form is not initialized yet
795 // * ... endless recursion ...
796 //
797 // Also skip data mapping if setData() has not been called yet.
798 // setData() will be called upon form initialization and data mapping
799 // will take place by then.
800 if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
801 $viewData = $this->getViewData();
802 }
803
804 if (!$child instanceof FormInterface) {
805 if (!is_string($child) && !is_int($child)) {
806 throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormInterface');
807 }
808
809 if (null !== $type && !is_string($type) && !$type instanceof FormTypeInterface) {
810 throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
811 }
812
813 // Never initialize child forms automatically
814 $options['auto_initialize'] = false;
815
816 if (null === $type) {
817 $child = $this->config->getFormFactory()->createForProperty($this->config->getDataClass(), $child, null, $options);
818 } else {
819 $child = $this->config->getFormFactory()->createNamed($child, $type, null, $options);
820 }
821 } elseif ($child->getConfig()->getAutoInitialize()) {
822 throw new RuntimeException(sprintf(
823 'Automatic initialization is only supported on root forms. You '.
824 'should set the "auto_initialize" option to false on the field "%s".',
825 $child->getName()
826 ));
827 }
828
829 $this->children[$child->getName()] = $child;
830
831 $child->setParent($this);
832
833 if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
834 $childrenIterator = new InheritDataAwareIterator(array($child));
835 $childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
836 $this->config->getDataMapper()->mapDataToForms($viewData, $childrenIterator);
837 }
838
839 return $this;
840 }
841
842 /**
843 * {@inheritdoc}
844 */
845 public function remove($name)
846 {
847 if ($this->submitted) {
848 throw new AlreadySubmittedException('You cannot remove children from a submitted form');
849 }
850
851 if (isset($this->children[$name])) {
852 $this->children[$name]->setParent(null);
853
854 unset($this->children[$name]);
855 }
856
857 return $this;
858 }
859
860 /**
861 * {@inheritdoc}
862 */
863 public function has($name)
864 {
865 return isset($this->children[$name]);
866 }
867
868 /**
869 * {@inheritdoc}
870 */
871 public function get($name)
872 {
873 if (isset($this->children[$name])) {
874 return $this->children[$name];
875 }
876
877 throw new OutOfBoundsException(sprintf('Child "%s" does not exist.', $name));
878 }
879
880 /**
881 * Returns whether a child with the given name exists (implements the \ArrayAccess interface).
882 *
883 * @param string $name The name of the child
884 *
885 * @return Boolean
886 */
887 public function offsetExists($name)
888 {
889 return $this->has($name);
890 }
891
892 /**
893 * Returns the child with the given name (implements the \ArrayAccess interface).
894 *
895 * @param string $name The name of the child
896 *
897 * @return FormInterface The child form
898 *
899 * @throws \OutOfBoundsException If the named child does not exist.
900 */
901 public function offsetGet($name)
902 {
903 return $this->get($name);
904 }
905
906 /**
907 * Adds a child to the form (implements the \ArrayAccess interface).
908 *
909 * @param string $name Ignored. The name of the child is used.
910 * @param FormInterface $child The child to be added.
911 *
912 * @throws AlreadySubmittedException If the form has already been submitted.
913 * @throws LogicException When trying to add a child to a non-compound form.
914 *
915 * @see self::add()
916 */
917 public function offsetSet($name, $child)
918 {
919 $this->add($child);
920 }
921
922 /**
923 * Removes the child with the given name from the form (implements the \ArrayAccess interface).
924 *
925 * @param string $name The name of the child to remove
926 *
927 * @throws AlreadySubmittedException If the form has already been submitted.
928 */
929 public function offsetUnset($name)
930 {
931 $this->remove($name);
932 }
933
934 /**
935 * Returns the iterator for this group.
936 *
937 * @return \ArrayIterator
938 */
939 public function getIterator()
940 {
941 return new \ArrayIterator($this->children);
942 }
943
944 /**
945 * Returns the number of form children (implements the \Countable interface).
946 *
947 * @return integer The number of embedded form children
948 */
949 public function count()
950 {
951 return count($this->children);
952 }
953
954 /**
955 * {@inheritdoc}
956 */
957 public function createView(FormView $parent = null)
958 {
959 if (null === $parent && $this->parent) {
960 $parent = $this->parent->createView();
961 }
962
963 return $this->config->getType()->createView($this, $parent);
964 }
965
966 /**
967 * Normalizes the value if a normalization transformer is set.
968 *
969 * @param mixed $value The value to transform
970 *
971 * @return mixed
972 */
973 private function modelToNorm($value)
974 {
975 foreach ($this->config->getModelTransformers() as $transformer) {
976 $value = $transformer->transform($value);
977 }
978
979 return $value;
980 }
981
982 /**
983 * Reverse transforms a value if a normalization transformer is set.
984 *
985 * @param string $value The value to reverse transform
986 *
987 * @return mixed
988 */
989 private function normToModel($value)
990 {
991 $transformers = $this->config->getModelTransformers();
992
993 for ($i = count($transformers) - 1; $i >= 0; --$i) {
994 $value = $transformers[$i]->reverseTransform($value);
995 }
996
997 return $value;
998 }
999
1000 /**
1001 * Transforms the value if a value transformer is set.
1002 *
1003 * @param mixed $value The value to transform
1004 *
1005 * @return mixed
1006 */
1007 private function normToView($value)
1008 {
1009 // Scalar values should be converted to strings to
1010 // facilitate differentiation between empty ("") and zero (0).
1011 // Only do this for simple forms, as the resulting value in
1012 // compound forms is passed to the data mapper and thus should
1013 // not be converted to a string before.
1014 if (!$this->config->getViewTransformers() && !$this->config->getCompound()) {
1015 return null === $value || is_scalar($value) ? (string) $value : $value;
1016 }
1017
1018 foreach ($this->config->getViewTransformers() as $transformer) {
1019 $value = $transformer->transform($value);
1020 }
1021
1022 return $value;
1023 }
1024
1025 /**
1026 * Reverse transforms a value if a value transformer is set.
1027 *
1028 * @param string $value The value to reverse transform
1029 *
1030 * @return mixed
1031 */
1032 private function viewToNorm($value)
1033 {
1034 $transformers = $this->config->getViewTransformers();
1035
1036 if (!$transformers) {
1037 return '' === $value ? null : $value;
1038 }
1039
1040 for ($i = count($transformers) - 1; $i >= 0; --$i) {
1041 $value = $transformers[$i]->reverseTransform($value);
1042 }
1043
1044 return $value;
1045 }
1046}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormBuilder.php b/vendor/symfony/form/Symfony/Component/Form/FormBuilder.php
new file mode 100644
index 00000000..2caefe48
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormBuilder.php
@@ -0,0 +1,275 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\BadMethodCallException;
15use Symfony\Component\Form\Exception\InvalidArgumentException;
16use Symfony\Component\Form\Exception\UnexpectedTypeException;
17use Symfony\Component\EventDispatcher\EventDispatcherInterface;
18
19/**
20 * A builder for creating {@link Form} instances.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormBuilderInterface
25{
26 /**
27 * The children of the form builder.
28 *
29 * @var FormBuilderInterface[]
30 */
31 private $children = array();
32
33 /**
34 * The data of children who haven't been converted to form builders yet.
35 *
36 * @var array
37 */
38 private $unresolvedChildren = array();
39
40 /**
41 * Creates a new form builder.
42 *
43 * @param string $name
44 * @param string $dataClass
45 * @param EventDispatcherInterface $dispatcher
46 * @param FormFactoryInterface $factory
47 * @param array $options
48 */
49 public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory, array $options = array())
50 {
51 parent::__construct($name, $dataClass, $dispatcher, $options);
52
53 $this->setFormFactory($factory);
54 }
55
56 /**
57 * {@inheritdoc}
58 */
59 public function add($child, $type = null, array $options = array())
60 {
61 if ($this->locked) {
62 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
63 }
64
65 if ($child instanceof self) {
66 $this->children[$child->getName()] = $child;
67
68 // In case an unresolved child with the same name exists
69 unset($this->unresolvedChildren[$child->getName()]);
70
71 return $this;
72 }
73
74 if (!is_string($child) && !is_int($child)) {
75 throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormBuilder');
76 }
77
78 if (null !== $type && !is_string($type) && !$type instanceof FormTypeInterface) {
79 throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
80 }
81
82 // Add to "children" to maintain order
83 $this->children[$child] = null;
84 $this->unresolvedChildren[$child] = array(
85 'type' => $type,
86 'options' => $options,
87 );
88
89 return $this;
90 }
91
92 /**
93 * {@inheritdoc}
94 */
95 public function create($name, $type = null, array $options = array())
96 {
97 if ($this->locked) {
98 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
99 }
100
101 if (null === $type && null === $this->getDataClass()) {
102 $type = 'text';
103 }
104
105 if (null !== $type) {
106 return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options);
107 }
108
109 return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options);
110 }
111
112 /**
113 * {@inheritdoc}
114 */
115 public function get($name)
116 {
117 if ($this->locked) {
118 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
119 }
120
121 if (isset($this->unresolvedChildren[$name])) {
122 return $this->resolveChild($name);
123 }
124
125 if (isset($this->children[$name])) {
126 return $this->children[$name];
127 }
128
129 throw new InvalidArgumentException(sprintf('The child with the name "%s" does not exist.', $name));
130 }
131
132 /**
133 * {@inheritdoc}
134 */
135 public function remove($name)
136 {
137 if ($this->locked) {
138 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
139 }
140
141 unset($this->unresolvedChildren[$name]);
142
143 if (array_key_exists($name, $this->children)) {
144 unset($this->children[$name]);
145 }
146
147 return $this;
148 }
149
150 /**
151 * {@inheritdoc}
152 */
153 public function has($name)
154 {
155 if ($this->locked) {
156 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
157 }
158
159 if (isset($this->unresolvedChildren[$name])) {
160 return true;
161 }
162
163 if (isset($this->children[$name])) {
164 return true;
165 }
166
167 return false;
168 }
169
170 /**
171 * {@inheritdoc}
172 */
173 public function all()
174 {
175 if ($this->locked) {
176 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
177 }
178
179 $this->resolveChildren();
180
181 return $this->children;
182 }
183
184 /**
185 * {@inheritdoc}
186 */
187 public function count()
188 {
189 if ($this->locked) {
190 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
191 }
192
193 return count($this->children);
194 }
195
196 /**
197 * {@inheritdoc}
198 */
199 public function getFormConfig()
200 {
201 $config = parent::getFormConfig();
202
203 $config->children = array();
204 $config->unresolvedChildren = array();
205
206 return $config;
207 }
208
209 /**
210 * {@inheritdoc}
211 */
212 public function getForm()
213 {
214 if ($this->locked) {
215 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
216 }
217
218 $this->resolveChildren();
219
220 $form = new Form($this->getFormConfig());
221
222 foreach ($this->children as $child) {
223 // Automatic initialization is only supported on root forms
224 $form->add($child->setAutoInitialize(false)->getForm());
225 }
226
227 if ($this->getAutoInitialize()) {
228 // Automatically initialize the form if it is configured so
229 $form->initialize();
230 }
231
232 return $form;
233 }
234
235 /**
236 * {@inheritdoc}
237 */
238 public function getIterator()
239 {
240 if ($this->locked) {
241 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
242 }
243
244 return new \ArrayIterator($this->children);
245 }
246
247 /**
248 * Converts an unresolved child into a {@link FormBuilder} instance.
249 *
250 * @param string $name The name of the unresolved child.
251 *
252 * @return FormBuilder The created instance.
253 */
254 private function resolveChild($name)
255 {
256 $info = $this->unresolvedChildren[$name];
257 $child = $this->create($name, $info['type'], $info['options']);
258 $this->children[$name] = $child;
259 unset($this->unresolvedChildren[$name]);
260
261 return $child;
262 }
263
264 /**
265 * Converts all unresolved children into {@link FormBuilder} instances.
266 */
267 private function resolveChildren()
268 {
269 foreach ($this->unresolvedChildren as $name => $info) {
270 $this->children[$name] = $this->create($name, $info['type'], $info['options']);
271 }
272
273 $this->unresolvedChildren = array();
274 }
275}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormBuilderInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormBuilderInterface.php
new file mode 100644
index 00000000..1dc4a64e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormBuilderInterface.php
@@ -0,0 +1,87 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17interface FormBuilderInterface extends \Traversable, \Countable, FormConfigBuilderInterface
18{
19 /**
20 * Adds a new field to this group. A field must have a unique name within
21 * the group. Otherwise the existing field is overwritten.
22 *
23 * If you add a nested group, this group should also be represented in the
24 * object hierarchy.
25 *
26 * @param string|integer|FormBuilderInterface $child
27 * @param string|FormTypeInterface $type
28 * @param array $options
29 *
30 * @return FormBuilderInterface The builder object.
31 */
32 public function add($child, $type = null, array $options = array());
33
34 /**
35 * Creates a form builder.
36 *
37 * @param string $name The name of the form or the name of the property
38 * @param string|FormTypeInterface $type The type of the form or null if name is a property
39 * @param array $options The options
40 *
41 * @return FormBuilderInterface The created builder.
42 */
43 public function create($name, $type = null, array $options = array());
44
45 /**
46 * Returns a child by name.
47 *
48 * @param string $name The name of the child
49 *
50 * @return FormBuilderInterface The builder for the child
51 *
52 * @throws Exception\InvalidArgumentException if the given child does not exist
53 */
54 public function get($name);
55
56 /**
57 * Removes the field with the given name.
58 *
59 * @param string $name
60 *
61 * @return FormBuilderInterface The builder object.
62 */
63 public function remove($name);
64
65 /**
66 * Returns whether a field with the given name exists.
67 *
68 * @param string $name
69 *
70 * @return Boolean
71 */
72 public function has($name);
73
74 /**
75 * Returns the children.
76 *
77 * @return array
78 */
79 public function all();
80
81 /**
82 * Creates the form.
83 *
84 * @return Form The form
85 */
86 public function getForm();
87}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormConfigBuilder.php b/vendor/symfony/form/Symfony/Component/Form/FormConfigBuilder.php
new file mode 100644
index 00000000..1015da4f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormConfigBuilder.php
@@ -0,0 +1,919 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\BadMethodCallException;
15use Symfony\Component\Form\Exception\InvalidArgumentException;
16use Symfony\Component\Form\Exception\UnexpectedTypeException;
17use Symfony\Component\PropertyAccess\PropertyPath;
18use Symfony\Component\PropertyAccess\PropertyPathInterface;
19use Symfony\Component\EventDispatcher\EventDispatcherInterface;
20use Symfony\Component\EventDispatcher\EventSubscriberInterface;
21use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
22
23/**
24 * A basic form configuration.
25 *
26 * @author Bernhard Schussek <bschussek@gmail.com>
27 */
28class FormConfigBuilder implements FormConfigBuilderInterface
29{
30 /**
31 * Caches a globally unique {@link NativeRequestHandler} instance.
32 *
33 * @var NativeRequestHandler
34 */
35 private static $nativeRequestProcessor;
36
37 /**
38 * The accepted request methods.
39 *
40 * @var array
41 */
42 private static $allowedMethods = array(
43 'GET',
44 'PUT',
45 'POST',
46 'DELETE',
47 'PATCH'
48 );
49
50 /**
51 * @var Boolean
52 */
53 protected $locked = false;
54
55 /**
56 * @var EventDispatcherInterface
57 */
58 private $dispatcher;
59
60 /**
61 * @var string
62 */
63 private $name;
64
65 /**
66 * @var PropertyPathInterface
67 */
68 private $propertyPath;
69
70 /**
71 * @var Boolean
72 */
73 private $mapped = true;
74
75 /**
76 * @var Boolean
77 */
78 private $byReference = true;
79
80 /**
81 * @var Boolean
82 */
83 private $inheritData = false;
84
85 /**
86 * @var Boolean
87 */
88 private $compound = false;
89
90 /**
91 * @var ResolvedFormTypeInterface
92 */
93 private $type;
94
95 /**
96 * @var array
97 */
98 private $viewTransformers = array();
99
100 /**
101 * @var array
102 */
103 private $modelTransformers = array();
104
105 /**
106 * @var DataMapperInterface
107 */
108 private $dataMapper;
109
110 /**
111 * @var Boolean
112 */
113 private $required = true;
114
115 /**
116 * @var Boolean
117 */
118 private $disabled = false;
119
120 /**
121 * @var Boolean
122 */
123 private $errorBubbling = false;
124
125 /**
126 * @var mixed
127 */
128 private $emptyData;
129
130 /**
131 * @var array
132 */
133 private $attributes = array();
134
135 /**
136 * @var mixed
137 */
138 private $data;
139
140 /**
141 * @var string
142 */
143 private $dataClass;
144
145 /**
146 * @var Boolean
147 */
148 private $dataLocked;
149
150 /**
151 * @var FormFactoryInterface
152 */
153 private $formFactory;
154
155 /**
156 * @var string
157 */
158 private $action;
159
160 /**
161 * @var string
162 */
163 private $method = 'POST';
164
165 /**
166 * @var RequestHandlerInterface
167 */
168 private $requestHandler;
169
170 /**
171 * @var Boolean
172 */
173 private $autoInitialize = false;
174
175 /**
176 * @var array
177 */
178 private $options;
179
180 /**
181 * Creates an empty form configuration.
182 *
183 * @param string|integer $name The form name
184 * @param string $dataClass The class of the form's data
185 * @param EventDispatcherInterface $dispatcher The event dispatcher
186 * @param array $options The form options
187 *
188 * @throws InvalidArgumentException If the data class is not a valid class or if
189 * the name contains invalid characters.
190 */
191 public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, array $options = array())
192 {
193 self::validateName($name);
194
195 if (null !== $dataClass && !class_exists($dataClass)) {
196 throw new InvalidArgumentException(sprintf('The data class "%s" is not a valid class.', $dataClass));
197 }
198
199 $this->name = (string) $name;
200 $this->dataClass = $dataClass;
201 $this->dispatcher = $dispatcher;
202 $this->options = $options;
203 }
204
205 /**
206 * {@inheritdoc}
207 */
208 public function addEventListener($eventName, $listener, $priority = 0)
209 {
210 if ($this->locked) {
211 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
212 }
213
214 $this->dispatcher->addListener($eventName, $listener, $priority);
215
216 return $this;
217 }
218
219 /**
220 * {@inheritdoc}
221 */
222 public function addEventSubscriber(EventSubscriberInterface $subscriber)
223 {
224 if ($this->locked) {
225 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
226 }
227
228 $this->dispatcher->addSubscriber($subscriber);
229
230 return $this;
231 }
232
233 /**
234 * {@inheritdoc}
235 */
236 public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false)
237 {
238 if ($this->locked) {
239 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
240 }
241
242 if ($forcePrepend) {
243 array_unshift($this->viewTransformers, $viewTransformer);
244 } else {
245 $this->viewTransformers[] = $viewTransformer;
246 }
247
248 return $this;
249 }
250
251 /**
252 * {@inheritdoc}
253 */
254 public function resetViewTransformers()
255 {
256 if ($this->locked) {
257 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
258 }
259
260 $this->viewTransformers = array();
261
262 return $this;
263 }
264
265 /**
266 * {@inheritdoc}
267 */
268 public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false)
269 {
270 if ($this->locked) {
271 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
272 }
273
274 if ($forceAppend) {
275 $this->modelTransformers[] = $modelTransformer;
276 } else {
277 array_unshift($this->modelTransformers, $modelTransformer);
278 }
279
280 return $this;
281 }
282
283 /**
284 * {@inheritdoc}
285 */
286 public function resetModelTransformers()
287 {
288 if ($this->locked) {
289 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
290 }
291
292 $this->modelTransformers = array();
293
294 return $this;
295 }
296
297 /**
298 * {@inheritdoc}
299 */
300 public function getEventDispatcher()
301 {
302 if ($this->locked && !$this->dispatcher instanceof ImmutableEventDispatcher) {
303 $this->dispatcher = new ImmutableEventDispatcher($this->dispatcher);
304 }
305
306 return $this->dispatcher;
307 }
308
309 /**
310 * {@inheritdoc}
311 */
312 public function getName()
313 {
314 return $this->name;
315 }
316
317 /**
318 * {@inheritdoc}
319 */
320 public function getPropertyPath()
321 {
322 return $this->propertyPath;
323 }
324
325 /**
326 * {@inheritdoc}
327 */
328 public function getMapped()
329 {
330 return $this->mapped;
331 }
332
333 /**
334 * {@inheritdoc}
335 */
336 public function getByReference()
337 {
338 return $this->byReference;
339 }
340
341 /**
342 * {@inheritdoc}
343 */
344 public function getInheritData()
345 {
346 return $this->inheritData;
347 }
348
349 /**
350 * Alias of {@link getInheritData()}.
351 *
352 * @return FormConfigBuilder The configuration object.
353 *
354 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
355 * {@link getInheritData()} instead.
356 */
357 public function getVirtual()
358 {
359 // Uncomment this as soon as the deprecation note should be shown
360 // trigger_error('getVirtual() is deprecated since version 2.3 and will be removed in 3.0. Use getInheritData() instead.', E_USER_DEPRECATED);
361 return $this->getInheritData();
362 }
363
364 /**
365 * {@inheritdoc}
366 */
367 public function getCompound()
368 {
369 return $this->compound;
370 }
371
372 /**
373 * {@inheritdoc}
374 */
375 public function getType()
376 {
377 return $this->type;
378 }
379
380 /**
381 * {@inheritdoc}
382 */
383 public function getViewTransformers()
384 {
385 return $this->viewTransformers;
386 }
387
388 /**
389 * {@inheritdoc}
390 */
391 public function getModelTransformers()
392 {
393 return $this->modelTransformers;
394 }
395
396 /**
397 * {@inheritdoc}
398 */
399 public function getDataMapper()
400 {
401 return $this->dataMapper;
402 }
403
404 /**
405 * {@inheritdoc}
406 */
407 public function getRequired()
408 {
409 return $this->required;
410 }
411
412 /**
413 * {@inheritdoc}
414 */
415 public function getDisabled()
416 {
417 return $this->disabled;
418 }
419
420 /**
421 * {@inheritdoc}
422 */
423 public function getErrorBubbling()
424 {
425 return $this->errorBubbling;
426 }
427
428 /**
429 * {@inheritdoc}
430 */
431 public function getEmptyData()
432 {
433 return $this->emptyData;
434 }
435
436 /**
437 * {@inheritdoc}
438 */
439 public function getAttributes()
440 {
441 return $this->attributes;
442 }
443
444 /**
445 * {@inheritdoc}
446 */
447 public function hasAttribute($name)
448 {
449 return array_key_exists($name, $this->attributes);
450 }
451
452 /**
453 * {@inheritdoc}
454 */
455 public function getAttribute($name, $default = null)
456 {
457 return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
458 }
459
460 /**
461 * {@inheritdoc}
462 */
463 public function getData()
464 {
465 return $this->data;
466 }
467
468 /**
469 * {@inheritdoc}
470 */
471 public function getDataClass()
472 {
473 return $this->dataClass;
474 }
475
476 /**
477 * {@inheritdoc}
478 */
479 public function getDataLocked()
480 {
481 return $this->dataLocked;
482 }
483
484 /**
485 * {@inheritdoc}
486 */
487 public function getFormFactory()
488 {
489 return $this->formFactory;
490 }
491
492 /**
493 * {@inheritdoc}
494 */
495 public function getAction()
496 {
497 return $this->action;
498 }
499
500 /**
501 * {@inheritdoc}
502 */
503 public function getMethod()
504 {
505 return $this->method;
506 }
507
508 /**
509 * {@inheritdoc}
510 */
511 public function getRequestHandler()
512 {
513 if (null === $this->requestHandler) {
514 if (null === self::$nativeRequestProcessor) {
515 self::$nativeRequestProcessor = new NativeRequestHandler();
516 }
517 $this->requestHandler = self::$nativeRequestProcessor;
518 }
519
520 return $this->requestHandler;
521 }
522
523 /**
524 * {@inheritdoc}
525 */
526 public function getAutoInitialize()
527 {
528 return $this->autoInitialize;
529 }
530
531 /**
532 * {@inheritdoc}
533 */
534 public function getOptions()
535 {
536 return $this->options;
537 }
538
539 /**
540 * {@inheritdoc}
541 */
542 public function hasOption($name)
543 {
544 return array_key_exists($name, $this->options);
545 }
546
547 /**
548 * {@inheritdoc}
549 */
550 public function getOption($name, $default = null)
551 {
552 return array_key_exists($name, $this->options) ? $this->options[$name] : $default;
553 }
554
555 /**
556 * {@inheritdoc}
557 */
558 public function setAttribute($name, $value)
559 {
560 if ($this->locked) {
561 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
562 }
563
564 $this->attributes[$name] = $value;
565
566 return $this;
567 }
568
569 /**
570 * {@inheritdoc}
571 */
572 public function setAttributes(array $attributes)
573 {
574 if ($this->locked) {
575 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
576 }
577
578 $this->attributes = $attributes;
579
580 return $this;
581 }
582
583 /**
584 * {@inheritdoc}
585 */
586 public function setDataMapper(DataMapperInterface $dataMapper = null)
587 {
588 if ($this->locked) {
589 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
590 }
591
592 $this->dataMapper = $dataMapper;
593
594 return $this;
595 }
596
597 /**
598 * {@inheritdoc}
599 */
600 public function setDisabled($disabled)
601 {
602 if ($this->locked) {
603 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
604 }
605
606 $this->disabled = (Boolean) $disabled;
607
608 return $this;
609 }
610
611 /**
612 * {@inheritdoc}
613 */
614 public function setEmptyData($emptyData)
615 {
616 if ($this->locked) {
617 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
618 }
619
620 $this->emptyData = $emptyData;
621
622 return $this;
623 }
624
625 /**
626 * {@inheritdoc}
627 */
628 public function setErrorBubbling($errorBubbling)
629 {
630 if ($this->locked) {
631 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
632 }
633
634 $this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
635
636 return $this;
637 }
638
639 /**
640 * {@inheritdoc}
641 */
642 public function setRequired($required)
643 {
644 if ($this->locked) {
645 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
646 }
647
648 $this->required = (Boolean) $required;
649
650 return $this;
651 }
652
653 /**
654 * {@inheritdoc}
655 */
656 public function setPropertyPath($propertyPath)
657 {
658 if ($this->locked) {
659 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
660 }
661
662 if (null !== $propertyPath && !$propertyPath instanceof PropertyPathInterface) {
663 $propertyPath = new PropertyPath($propertyPath);
664 }
665
666 $this->propertyPath = $propertyPath;
667
668 return $this;
669 }
670
671 /**
672 * {@inheritdoc}
673 */
674 public function setMapped($mapped)
675 {
676 if ($this->locked) {
677 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
678 }
679
680 $this->mapped = $mapped;
681
682 return $this;
683 }
684
685 /**
686 * {@inheritdoc}
687 */
688 public function setByReference($byReference)
689 {
690 if ($this->locked) {
691 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
692 }
693
694 $this->byReference = $byReference;
695
696 return $this;
697 }
698
699 /**
700 * {@inheritdoc}
701 */
702 public function setInheritData($inheritData)
703 {
704 if ($this->locked) {
705 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
706 }
707
708 $this->inheritData = $inheritData;
709
710 return $this;
711 }
712
713 /**
714 * Alias of {@link setInheritData()}.
715 *
716 * @param Boolean $inheritData Whether the form should inherit its parent's data.
717 *
718 * @return FormConfigBuilder The configuration object.
719 *
720 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
721 * {@link setInheritData()} instead.
722 */
723 public function setVirtual($inheritData)
724 {
725 // Uncomment this as soon as the deprecation note should be shown
726 // trigger_error('setVirtual() is deprecated since version 2.3 and will be removed in 3.0. Use setInheritData() instead.', E_USER_DEPRECATED);
727
728 $this->setInheritData($inheritData);
729 }
730
731 /**
732 * {@inheritdoc}
733 */
734 public function setCompound($compound)
735 {
736 if ($this->locked) {
737 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
738 }
739
740 $this->compound = $compound;
741
742 return $this;
743 }
744
745 /**
746 * {@inheritdoc}
747 */
748 public function setType(ResolvedFormTypeInterface $type)
749 {
750 if ($this->locked) {
751 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
752 }
753
754 $this->type = $type;
755
756 return $this;
757 }
758
759 /**
760 * {@inheritdoc}
761 */
762 public function setData($data)
763 {
764 if ($this->locked) {
765 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
766 }
767
768 $this->data = $data;
769
770 return $this;
771 }
772
773 /**
774 * {@inheritdoc}
775 */
776 public function setDataLocked($locked)
777 {
778 if ($this->locked) {
779 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
780 }
781
782 $this->dataLocked = $locked;
783
784 return $this;
785 }
786
787 /**
788 * {@inheritdoc}
789 */
790 public function setFormFactory(FormFactoryInterface $formFactory)
791 {
792 if ($this->locked) {
793 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
794 }
795
796 $this->formFactory = $formFactory;
797
798 return $this;
799 }
800
801 /**
802 * {@inheritdoc}
803 */
804 public function setAction($action)
805 {
806 if ($this->locked) {
807 throw new BadMethodCallException('The config builder cannot be modified anymore.');
808 }
809
810 $this->action = $action;
811
812 return $this;
813 }
814
815 /**
816 * {@inheritdoc}
817 */
818 public function setMethod($method)
819 {
820 if ($this->locked) {
821 throw new BadMethodCallException('The config builder cannot be modified anymore.');
822 }
823
824 $upperCaseMethod = strtoupper($method);
825
826 if (!in_array($upperCaseMethod, self::$allowedMethods)) {
827 throw new InvalidArgumentException(sprintf(
828 'The form method is "%s", but should be one of "%s".',
829 $method,
830 implode('", "', self::$allowedMethods)
831 ));
832 }
833
834 $this->method = $upperCaseMethod;
835
836 return $this;
837 }
838
839 /**
840 * {@inheritdoc}
841 */
842 public function setRequestHandler(RequestHandlerInterface $requestHandler)
843 {
844 if ($this->locked) {
845 throw new BadMethodCallException('The config builder cannot be modified anymore.');
846 }
847
848 $this->requestHandler = $requestHandler;
849
850 return $this;
851 }
852
853 /**
854 * {@inheritdoc}
855 */
856 public function setAutoInitialize($initialize)
857 {
858 $this->autoInitialize = (Boolean) $initialize;
859
860 return $this;
861 }
862
863 /**
864 * {@inheritdoc}
865 */
866 public function getFormConfig()
867 {
868 if ($this->locked) {
869 throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
870 }
871
872 // This method should be idempotent, so clone the builder
873 $config = clone $this;
874 $config->locked = true;
875
876 return $config;
877 }
878
879 /**
880 * Validates whether the given variable is a valid form name.
881 *
882 * @param string|integer $name The tested form name.
883 *
884 * @throws UnexpectedTypeException If the name is not a string or an integer.
885 * @throws InvalidArgumentException If the name contains invalid characters.
886 */
887 public static function validateName($name)
888 {
889 if (null !== $name && !is_string($name) && !is_int($name)) {
890 throw new UnexpectedTypeException($name, 'string, integer or null');
891 }
892
893 if (!self::isValidName($name)) {
894 throw new InvalidArgumentException(sprintf(
895 'The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").',
896 $name
897 ));
898 }
899 }
900
901 /**
902 * Returns whether the given variable contains a valid form name.
903 *
904 * A name is accepted if it
905 *
906 * * is empty
907 * * starts with a letter, digit or underscore
908 * * contains only letters, digits, numbers, underscores ("_"),
909 * hyphens ("-") and colons (":")
910 *
911 * @param string $name The tested form name.
912 *
913 * @return Boolean Whether the name is valid.
914 */
915 public static function isValidName($name)
916 {
917 return '' === $name || null === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name);
918 }
919}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormConfigBuilderInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormConfigBuilderInterface.php
new file mode 100644
index 00000000..62d12c09
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormConfigBuilderInterface.php
@@ -0,0 +1,287 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface FormConfigBuilderInterface extends FormConfigInterface
20{
21 /**
22 * Adds an event listener to an event on this form.
23 *
24 * @param string $eventName The name of the event to listen to.
25 * @param callable $listener The listener to execute.
26 * @param integer $priority The priority of the listener. Listeners
27 * with a higher priority are called before
28 * listeners with a lower priority.
29 *
30 * @return self The configuration object.
31 */
32 public function addEventListener($eventName, $listener, $priority = 0);
33
34 /**
35 * Adds an event subscriber for events on this form.
36 *
37 * @param EventSubscriberInterface $subscriber The subscriber to attach.
38 *
39 * @return self The configuration object.
40 */
41 public function addEventSubscriber(EventSubscriberInterface $subscriber);
42
43 /**
44 * Appends / prepends a transformer to the view transformer chain.
45 *
46 * The transform method of the transformer is used to convert data from the
47 * normalized to the view format.
48 * The reverseTransform method of the transformer is used to convert from the
49 * view to the normalized format.
50 *
51 * @param DataTransformerInterface $viewTransformer
52 * @param Boolean $forcePrepend if set to true, prepend instead of appending
53 *
54 * @return self The configuration object.
55 */
56 public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false);
57
58 /**
59 * Clears the view transformers.
60 *
61 * @return self The configuration object.
62 */
63 public function resetViewTransformers();
64
65 /**
66 * Prepends / appends a transformer to the normalization transformer chain.
67 *
68 * The transform method of the transformer is used to convert data from the
69 * model to the normalized format.
70 * The reverseTransform method of the transformer is used to convert from the
71 * normalized to the model format.
72 *
73 * @param DataTransformerInterface $modelTransformer
74 * @param Boolean $forceAppend if set to true, append instead of prepending
75 *
76 * @return self The configuration object.
77 */
78 public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false);
79
80 /**
81 * Clears the normalization transformers.
82 *
83 * @return self The configuration object.
84 */
85 public function resetModelTransformers();
86
87 /**
88 * Sets the value for an attribute.
89 *
90 * @param string $name The name of the attribute
91 * @param string $value The value of the attribute
92 *
93 * @return self The configuration object.
94 */
95 public function setAttribute($name, $value);
96
97 /**
98 * Sets the attributes.
99 *
100 * @param array $attributes The attributes.
101 *
102 * @return self The configuration object.
103 */
104 public function setAttributes(array $attributes);
105
106 /**
107 * Sets the data mapper used by the form.
108 *
109 * @param DataMapperInterface $dataMapper
110 *
111 * @return self The configuration object.
112 */
113 public function setDataMapper(DataMapperInterface $dataMapper = null);
114
115 /**
116 * Set whether the form is disabled.
117 *
118 * @param Boolean $disabled Whether the form is disabled
119 *
120 * @return self The configuration object.
121 */
122 public function setDisabled($disabled);
123
124 /**
125 * Sets the data used for the client data when no value is submitted.
126 *
127 * @param mixed $emptyData The empty data.
128 *
129 * @return self The configuration object.
130 */
131 public function setEmptyData($emptyData);
132
133 /**
134 * Sets whether errors bubble up to the parent.
135 *
136 * @param Boolean $errorBubbling
137 *
138 * @return self The configuration object.
139 */
140 public function setErrorBubbling($errorBubbling);
141
142 /**
143 * Sets whether this field is required to be filled out when submitted.
144 *
145 * @param Boolean $required
146 *
147 * @return self The configuration object.
148 */
149 public function setRequired($required);
150
151 /**
152 * Sets the property path that the form should be mapped to.
153 *
154 * @param null|string|\Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath
155 * The property path or null if the path should be set
156 * automatically based on the form's name.
157 *
158 * @return self The configuration object.
159 */
160 public function setPropertyPath($propertyPath);
161
162 /**
163 * Sets whether the form should be mapped to an element of its
164 * parent's data.
165 *
166 * @param Boolean $mapped Whether the form should be mapped.
167 *
168 * @return self The configuration object.
169 */
170 public function setMapped($mapped);
171
172 /**
173 * Sets whether the form's data should be modified by reference.
174 *
175 * @param Boolean $byReference Whether the data should be
176 * modified by reference.
177 *
178 * @return self The configuration object.
179 */
180 public function setByReference($byReference);
181
182 /**
183 * Sets whether the form should read and write the data of its parent.
184 *
185 * @param Boolean $inheritData Whether the form should inherit its parent's data.
186 *
187 * @return self The configuration object.
188 */
189 public function setInheritData($inheritData);
190
191 /**
192 * Sets whether the form should be compound.
193 *
194 * @param Boolean $compound Whether the form should be compound.
195 *
196 * @return self The configuration object.
197 *
198 * @see FormConfigInterface::getCompound()
199 */
200 public function setCompound($compound);
201
202 /**
203 * Set the types.
204 *
205 * @param ResolvedFormTypeInterface $type The type of the form.
206 *
207 * @return self The configuration object.
208 */
209 public function setType(ResolvedFormTypeInterface $type);
210
211 /**
212 * Sets the initial data of the form.
213 *
214 * @param array $data The data of the form in application format.
215 *
216 * @return self The configuration object.
217 */
218 public function setData($data);
219
220 /**
221 * Locks the form's data to the data passed in the configuration.
222 *
223 * A form with locked data is restricted to the data passed in
224 * this configuration. The data can only be modified then by
225 * submitting the form.
226 *
227 * @param Boolean $locked Whether to lock the default data.
228 *
229 * @return self The configuration object.
230 */
231 public function setDataLocked($locked);
232
233 /**
234 * Sets the form factory used for creating new forms.
235 *
236 * @param FormFactoryInterface $formFactory The form factory.
237 */
238 public function setFormFactory(FormFactoryInterface $formFactory);
239
240 /**
241 * Sets the target URL of the form.
242 *
243 * @param string $action The target URL of the form.
244 *
245 * @return self The configuration object.
246 */
247 public function setAction($action);
248
249 /**
250 * Sets the HTTP method used by the form.
251 *
252 * @param string $method The HTTP method of the form.
253 *
254 * @return self The configuration object.
255 */
256 public function setMethod($method);
257
258 /**
259 * Sets the request handler used by the form.
260 *
261 * @param RequestHandlerInterface $requestHandler
262 *
263 * @return self The configuration object.
264 */
265 public function setRequestHandler(RequestHandlerInterface $requestHandler);
266
267 /**
268 * Sets whether the form should be initialized automatically.
269 *
270 * Should be set to true only for root forms.
271 *
272 * @param Boolean $initialize True to initialize the form automatically,
273 * false to suppress automatic initialization.
274 * In the second case, you need to call
275 * {@link FormInterface::initialize()} manually.
276 *
277 * @return self The configuration object.
278 */
279 public function setAutoInitialize($initialize);
280
281 /**
282 * Builds and returns the form configuration.
283 *
284 * @return FormConfigInterface
285 */
286 public function getFormConfig();
287}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormConfigInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormConfigInterface.php
new file mode 100644
index 00000000..576fcd81
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormConfigInterface.php
@@ -0,0 +1,243 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * The configuration of a {@link Form} object.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface FormConfigInterface
20{
21 /**
22 * Returns the event dispatcher used to dispatch form events.
23 *
24 * @return \Symfony\Component\EventDispatcher\EventDispatcherInterface The dispatcher.
25 */
26 public function getEventDispatcher();
27
28 /**
29 * Returns the name of the form used as HTTP parameter.
30 *
31 * @return string The form name.
32 */
33 public function getName();
34
35 /**
36 * Returns the property path that the form should be mapped to.
37 *
38 * @return null|\Symfony\Component\PropertyAccess\PropertyPathInterface The property path.
39 */
40 public function getPropertyPath();
41
42 /**
43 * Returns whether the form should be mapped to an element of its
44 * parent's data.
45 *
46 * @return Boolean Whether the form is mapped.
47 */
48 public function getMapped();
49
50 /**
51 * Returns whether the form's data should be modified by reference.
52 *
53 * @return Boolean Whether to modify the form's data by reference.
54 */
55 public function getByReference();
56
57 /**
58 * Returns whether the form should read and write the data of its parent.
59 *
60 * @return Boolean Whether the form should inherit its parent's data.
61 */
62 public function getInheritData();
63
64 /**
65 * Returns whether the form is compound.
66 *
67 * This property is independent of whether the form actually has
68 * children. A form can be compound and have no children at all, like
69 * for example an empty collection form.
70 *
71 * @return Boolean Whether the form is compound.
72 */
73 public function getCompound();
74
75 /**
76 * Returns the form types used to construct the form.
77 *
78 * @return ResolvedFormTypeInterface The form's type.
79 */
80 public function getType();
81
82 /**
83 * Returns the view transformers of the form.
84 *
85 * @return DataTransformerInterface[] An array of {@link DataTransformerInterface} instances.
86 */
87 public function getViewTransformers();
88
89 /**
90 * Returns the model transformers of the form.
91 *
92 * @return DataTransformerInterface[] An array of {@link DataTransformerInterface} instances.
93 */
94 public function getModelTransformers();
95
96 /**
97 * Returns the data mapper of the form.
98 *
99 * @return DataMapperInterface The data mapper.
100 */
101 public function getDataMapper();
102
103 /**
104 * Returns whether the form is required.
105 *
106 * @return Boolean Whether the form is required.
107 */
108 public function getRequired();
109
110 /**
111 * Returns whether the form is disabled.
112 *
113 * @return Boolean Whether the form is disabled.
114 */
115 public function getDisabled();
116
117 /**
118 * Returns whether errors attached to the form will bubble to its parent.
119 *
120 * @return Boolean Whether errors will bubble up.
121 */
122 public function getErrorBubbling();
123
124 /**
125 * Returns the data that should be returned when the form is empty.
126 *
127 * @return mixed The data returned if the form is empty.
128 */
129 public function getEmptyData();
130
131 /**
132 * Returns additional attributes of the form.
133 *
134 * @return array An array of key-value combinations.
135 */
136 public function getAttributes();
137
138 /**
139 * Returns whether the attribute with the given name exists.
140 *
141 * @param string $name The attribute name.
142 *
143 * @return Boolean Whether the attribute exists.
144 */
145 public function hasAttribute($name);
146
147 /**
148 * Returns the value of the given attribute.
149 *
150 * @param string $name The attribute name.
151 * @param mixed $default The value returned if the attribute does not exist.
152 *
153 * @return mixed The attribute value.
154 */
155 public function getAttribute($name, $default = null);
156
157 /**
158 * Returns the initial data of the form.
159 *
160 * @return mixed The initial form data.
161 */
162 public function getData();
163
164 /**
165 * Returns the class of the form data or null if the data is scalar or an array.
166 *
167 * @return string The data class or null.
168 */
169 public function getDataClass();
170
171 /**
172 * Returns whether the form's data is locked.
173 *
174 * A form with locked data is restricted to the data passed in
175 * this configuration. The data can only be modified then by
176 * submitting the form.
177 *
178 * @return Boolean Whether the data is locked.
179 */
180 public function getDataLocked();
181
182 /**
183 * Returns the form factory used for creating new forms.
184 *
185 * @return FormFactoryInterface The form factory.
186 */
187 public function getFormFactory();
188
189 /**
190 * Returns the target URL of the form.
191 *
192 * @return string The target URL of the form.
193 */
194 public function getAction();
195
196 /**
197 * Returns the HTTP method used by the form.
198 *
199 * @return string The HTTP method of the form.
200 */
201 public function getMethod();
202
203 /**
204 * Returns the request handler used by the form.
205 *
206 * @return RequestHandlerInterface The request handler.
207 */
208 public function getRequestHandler();
209
210 /**
211 * Returns whether the form should be initialized upon creation.
212 *
213 * @return Boolean Returns true if the form should be initialized
214 * when created, false otherwise.
215 */
216 public function getAutoInitialize();
217
218 /**
219 * Returns all options passed during the construction of the form.
220 *
221 * @return array The passed options.
222 */
223 public function getOptions();
224
225 /**
226 * Returns whether a specific option exists.
227 *
228 * @param string $name The option name,
229 *
230 * @return Boolean Whether the option exists.
231 */
232 public function hasOption($name);
233
234 /**
235 * Returns the value of a specific option.
236 *
237 * @param string $name The option name.
238 * @param mixed $default The value returned if the option does not exist.
239 *
240 * @return mixed The option value.
241 */
242 public function getOption($name, $default = null);
243}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormError.php b/vendor/symfony/form/Symfony/Component/Form/FormError.php
new file mode 100644
index 00000000..343165ca
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormError.php
@@ -0,0 +1,105 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * Wraps errors in forms
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class FormError
20{
21 /**
22 * @var string
23 */
24 private $message;
25
26 /**
27 * The template for the error message
28 * @var string
29 */
30 protected $messageTemplate;
31
32 /**
33 * The parameters that should be substituted in the message template
34 * @var array
35 */
36 protected $messageParameters;
37
38 /**
39 * The value for error message pluralization
40 * @var integer|null
41 */
42 protected $messagePluralization;
43
44 /**
45 * Constructor
46 *
47 * Any array key in $messageParameters will be used as a placeholder in
48 * $messageTemplate.
49 *
50 * @param string $message The translated error message
51 * @param string|null $messageTemplate The template for the error message
52 * @param array $messageParameters The parameters that should be
53 * substituted in the message template.
54 * @param integer|null $messagePluralization The value for error message pluralization
55 *
56 * @see \Symfony\Component\Translation\Translator
57 */
58 public function __construct($message, $messageTemplate = null, array $messageParameters = array(), $messagePluralization = null)
59 {
60 $this->message = $message;
61 $this->messageTemplate = $messageTemplate ?: $message;
62 $this->messageParameters = $messageParameters;
63 $this->messagePluralization = $messagePluralization;
64 }
65
66 /**
67 * Returns the error message
68 *
69 * @return string
70 */
71 public function getMessage()
72 {
73 return $this->message;
74 }
75
76 /**
77 * Returns the error message template
78 *
79 * @return string
80 */
81 public function getMessageTemplate()
82 {
83 return $this->messageTemplate;
84 }
85
86 /**
87 * Returns the parameters to be inserted in the message template
88 *
89 * @return array
90 */
91 public function getMessageParameters()
92 {
93 return $this->messageParameters;
94 }
95
96 /**
97 * Returns the value for error message pluralization.
98 *
99 * @return integer|null
100 */
101 public function getMessagePluralization()
102 {
103 return $this->messagePluralization;
104 }
105}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormEvent.php b/vendor/symfony/form/Symfony/Component/Form/FormEvent.php
new file mode 100644
index 00000000..57cebade
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormEvent.php
@@ -0,0 +1,65 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\EventDispatcher\Event;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class FormEvent extends Event
20{
21 private $form;
22 protected $data;
23
24 /**
25 * Constructs an event.
26 *
27 * @param FormInterface $form The associated form
28 * @param mixed $data The data
29 */
30 public function __construct(FormInterface $form, $data)
31 {
32 $this->form = $form;
33 $this->data = $data;
34 }
35
36 /**
37 * Returns the form at the source of the event.
38 *
39 * @return FormInterface
40 */
41 public function getForm()
42 {
43 return $this->form;
44 }
45
46 /**
47 * Returns the data associated with this event.
48 *
49 * @return mixed
50 */
51 public function getData()
52 {
53 return $this->data;
54 }
55
56 /**
57 * Allows updating with some filtered data.
58 *
59 * @param mixed $data
60 */
61 public function setData($data)
62 {
63 $this->data = $data;
64 }
65}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormEvents.php b/vendor/symfony/form/Symfony/Component/Form/FormEvents.php
new file mode 100644
index 00000000..6c4efc5b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormEvents.php
@@ -0,0 +1,49 @@
1<?php
2/*
3 * This file is part of the Symfony package.
4 *
5 * (c) Fabien Potencier <fabien@symfony.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11namespace Symfony\Component\Form;
12
13/**
14 * @author Bernhard Schussek <bschussek@gmail.com>
15 */
16final class FormEvents
17{
18 const PRE_SUBMIT = 'form.pre_bind';
19
20 const SUBMIT = 'form.bind';
21
22 const POST_SUBMIT = 'form.post_bind';
23
24 const PRE_SET_DATA = 'form.pre_set_data';
25
26 const POST_SET_DATA = 'form.post_set_data';
27
28 /**
29 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
30 * {@link PRE_SUBMIT} instead.
31 */
32 const PRE_BIND = 'form.pre_bind';
33
34 /**
35 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
36 * {@link SUBMIT} instead.
37 */
38 const BIND = 'form.bind';
39
40 /**
41 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
42 * {@link POST_SUBMIT} instead.
43 */
44 const POST_BIND = 'form.post_bind';
45
46 private function __construct()
47 {
48 }
49}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormExtensionInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormExtensionInterface.php
new file mode 100644
index 00000000..a67055b7
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormExtensionInterface.php
@@ -0,0 +1,63 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * Interface for extensions which provide types, type extensions and a guesser.
16 */
17interface FormExtensionInterface
18{
19 /**
20 * Returns a type by name.
21 *
22 * @param string $name The name of the type
23 *
24 * @return FormTypeInterface The type
25 *
26 * @throws Exception\InvalidArgumentException if the given type is not supported by this extension
27 */
28 public function getType($name);
29
30 /**
31 * Returns whether the given type is supported.
32 *
33 * @param string $name The name of the type
34 *
35 * @return Boolean Whether the type is supported by this extension
36 */
37 public function hasType($name);
38
39 /**
40 * Returns the extensions for the given type.
41 *
42 * @param string $name The name of the type
43 *
44 * @return FormTypeExtensionInterface[] An array of extensions as FormTypeExtensionInterface instances
45 */
46 public function getTypeExtensions($name);
47
48 /**
49 * Returns whether this extension provides type extensions for the given type.
50 *
51 * @param string $name The name of the type
52 *
53 * @return Boolean Whether the given type has extensions
54 */
55 public function hasTypeExtensions($name);
56
57 /**
58 * Returns the type guesser provided by this extension.
59 *
60 * @return FormTypeGuesserInterface|null The type guesser
61 */
62 public function getTypeGuesser();
63}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormFactory.php b/vendor/symfony/form/Symfony/Component/Form/FormFactory.php
new file mode 100644
index 00000000..a5fd9cc0
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormFactory.php
@@ -0,0 +1,156 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\UnexpectedTypeException;
15
16class FormFactory implements FormFactoryInterface
17{
18 /**
19 * @var FormRegistryInterface
20 */
21 private $registry;
22
23 /**
24 * @var ResolvedFormTypeFactoryInterface
25 */
26 private $resolvedTypeFactory;
27
28 public function __construct(FormRegistryInterface $registry, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
29 {
30 $this->registry = $registry;
31 $this->resolvedTypeFactory = $resolvedTypeFactory;
32 }
33
34 /**
35 * {@inheritdoc}
36 */
37 public function create($type = 'form', $data = null, array $options = array())
38 {
39 return $this->createBuilder($type, $data, $options)->getForm();
40 }
41
42 /**
43 * {@inheritdoc}
44 */
45 public function createNamed($name, $type = 'form', $data = null, array $options = array())
46 {
47 return $this->createNamedBuilder($name, $type, $data, $options)->getForm();
48 }
49
50 /**
51 * {@inheritdoc}
52 */
53 public function createForProperty($class, $property, $data = null, array $options = array())
54 {
55 return $this->createBuilderForProperty($class, $property, $data, $options)->getForm();
56 }
57
58 /**
59 * {@inheritdoc}
60 */
61 public function createBuilder($type = 'form', $data = null, array $options = array())
62 {
63 $name = $type instanceof FormTypeInterface || $type instanceof ResolvedFormTypeInterface
64 ? $type->getName()
65 : $type;
66
67 return $this->createNamedBuilder($name, $type, $data, $options);
68 }
69
70 /**
71 * {@inheritdoc}
72 */
73 public function createNamedBuilder($name, $type = 'form', $data = null, array $options = array())
74 {
75 if (null !== $data && !array_key_exists('data', $options)) {
76 $options['data'] = $data;
77 }
78
79 if ($type instanceof FormTypeInterface) {
80 $type = $this->resolveType($type);
81 } elseif (is_string($type)) {
82 $type = $this->registry->getType($type);
83 } elseif (!$type instanceof ResolvedFormTypeInterface) {
84 throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface');
85 }
86
87 return $type->createBuilder($this, $name, $options);
88 }
89
90 /**
91 * {@inheritdoc}
92 */
93 public function createBuilderForProperty($class, $property, $data = null, array $options = array())
94 {
95 if (null === $guesser = $this->registry->getTypeGuesser()) {
96 return $this->createNamedBuilder($property, 'text', $data, $options);
97 }
98
99 $typeGuess = $guesser->guessType($class, $property);
100 $maxLengthGuess = $guesser->guessMaxLength($class, $property);
101 $requiredGuess = $guesser->guessRequired($class, $property);
102 $patternGuess = $guesser->guessPattern($class, $property);
103
104 $type = $typeGuess ? $typeGuess->getType() : 'text';
105
106 $maxLength = $maxLengthGuess ? $maxLengthGuess->getValue() : null;
107 $pattern = $patternGuess ? $patternGuess->getValue() : null;
108
109 if (null !== $pattern) {
110 $options = array_merge(array('pattern' => $pattern), $options);
111 }
112
113 if (null !== $maxLength) {
114 $options = array_merge(array('max_length' => $maxLength), $options);
115 }
116
117 if ($requiredGuess) {
118 $options = array_merge(array('required' => $requiredGuess->getValue()), $options);
119 }
120
121 // user options may override guessed options
122 if ($typeGuess) {
123 $options = array_merge($typeGuess->getOptions(), $options);
124 }
125
126 return $this->createNamedBuilder($property, $type, $data, $options);
127 }
128
129 /**
130 * Wraps a type into a ResolvedFormTypeInterface implementation and connects
131 * it with its parent type.
132 *
133 * @param FormTypeInterface $type The type to resolve.
134 *
135 * @return ResolvedFormTypeInterface The resolved type.
136 */
137 private function resolveType(FormTypeInterface $type)
138 {
139 $parentType = $type->getParent();
140
141 if ($parentType instanceof FormTypeInterface) {
142 $parentType = $this->resolveType($parentType);
143 } elseif (null !== $parentType) {
144 $parentType = $this->registry->getType($parentType);
145 }
146
147 return $this->resolvedTypeFactory->createResolvedType(
148 $type,
149 // Type extensions are not supported for unregistered type instances,
150 // i.e. type instances that are passed to the FormFactory directly,
151 // nor for their parents, if getParent() also returns a type instance.
152 array(),
153 $parentType
154 );
155 }
156}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormFactoryBuilder.php b/vendor/symfony/form/Symfony/Component/Form/FormFactoryBuilder.php
new file mode 100644
index 00000000..10383e84
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormFactoryBuilder.php
@@ -0,0 +1,162 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * The default implementation of FormFactoryBuilderInterface.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class FormFactoryBuilder implements FormFactoryBuilderInterface
20{
21 /**
22 * @var ResolvedFormTypeFactoryInterface
23 */
24 private $resolvedTypeFactory;
25
26 /**
27 * @var array
28 */
29 private $extensions = array();
30
31 /**
32 * @var array
33 */
34 private $types = array();
35
36 /**
37 * @var array
38 */
39 private $typeExtensions = array();
40
41 /**
42 * @var array
43 */
44 private $typeGuessers = array();
45
46 /**
47 * {@inheritdoc}
48 */
49 public function setResolvedTypeFactory(ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
50 {
51 $this->resolvedTypeFactory = $resolvedTypeFactory;
52
53 return $this;
54 }
55
56 /**
57 * {@inheritdoc}
58 */
59 public function addExtension(FormExtensionInterface $extension)
60 {
61 $this->extensions[] = $extension;
62
63 return $this;
64 }
65
66 /**
67 * {@inheritdoc}
68 */
69 public function addExtensions(array $extensions)
70 {
71 $this->extensions = array_merge($this->extensions, $extensions);
72
73 return $this;
74 }
75
76 /**
77 * {@inheritdoc}
78 */
79 public function addType(FormTypeInterface $type)
80 {
81 $this->types[$type->getName()] = $type;
82
83 return $this;
84 }
85
86 /**
87 * {@inheritdoc}
88 */
89 public function addTypes(array $types)
90 {
91 foreach ($types as $type) {
92 $this->types[$type->getName()] = $type;
93 }
94
95 return $this;
96 }
97
98 /**
99 * {@inheritdoc}
100 */
101 public function addTypeExtension(FormTypeExtensionInterface $typeExtension)
102 {
103 $this->typeExtensions[$typeExtension->getExtendedType()][] = $typeExtension;
104
105 return $this;
106 }
107
108 /**
109 * {@inheritdoc}
110 */
111 public function addTypeExtensions(array $typeExtensions)
112 {
113 foreach ($typeExtensions as $typeExtension) {
114 $this->typeExtensions[$typeExtension->getExtendedType()][] = $typeExtension;
115 }
116
117 return $this;
118 }
119
120 /**
121 * {@inheritdoc}
122 */
123 public function addTypeGuesser(FormTypeGuesserInterface $typeGuesser)
124 {
125 $this->typeGuessers[] = $typeGuesser;
126
127 return $this;
128 }
129
130 /**
131 * {@inheritdoc}
132 */
133 public function addTypeGuessers(array $typeGuessers)
134 {
135 $this->typeGuessers = array_merge($this->typeGuessers, $typeGuessers);
136
137 return $this;
138 }
139
140 /**
141 * {@inheritdoc}
142 */
143 public function getFormFactory()
144 {
145 $extensions = $this->extensions;
146
147 if (count($this->types) > 0 || count($this->typeExtensions) > 0 || count($this->typeGuessers) > 0) {
148 if (count($this->typeGuessers) > 1) {
149 $typeGuesser = new FormTypeGuesserChain($this->typeGuessers);
150 } else {
151 $typeGuesser = isset($this->typeGuessers[0]) ? $this->typeGuessers[0] : null;
152 }
153
154 $extensions[] = new PreloadedExtension($this->types, $this->typeExtensions, $typeGuesser);
155 }
156
157 $resolvedTypeFactory = $this->resolvedTypeFactory ?: new ResolvedFormTypeFactory();
158 $registry = new FormRegistry($extensions, $resolvedTypeFactory);
159
160 return new FormFactory($registry, $resolvedTypeFactory);
161 }
162}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormFactoryBuilderInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormFactoryBuilderInterface.php
new file mode 100644
index 00000000..9370c573
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormFactoryBuilderInterface.php
@@ -0,0 +1,108 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * A builder for FormFactoryInterface objects.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface FormFactoryBuilderInterface
20{
21 /**
22 * Sets the factory for creating ResolvedFormTypeInterface instances.
23 *
24 * @param ResolvedFormTypeFactoryInterface $resolvedTypeFactory
25 *
26 * @return FormFactoryBuilderInterface The builder.
27 */
28 public function setResolvedTypeFactory(ResolvedFormTypeFactoryInterface $resolvedTypeFactory);
29
30 /**
31 * Adds an extension to be loaded by the factory.
32 *
33 * @param FormExtensionInterface $extension The extension.
34 *
35 * @return FormFactoryBuilderInterface The builder.
36 */
37 public function addExtension(FormExtensionInterface $extension);
38
39 /**
40 * Adds a list of extensions to be loaded by the factory.
41 *
42 * @param array $extensions The extensions.
43 *
44 * @return FormFactoryBuilderInterface The builder.
45 */
46 public function addExtensions(array $extensions);
47
48 /**
49 * Adds a form type to the factory.
50 *
51 * @param FormTypeInterface $type The form type.
52 *
53 * @return FormFactoryBuilderInterface The builder.
54 */
55 public function addType(FormTypeInterface $type);
56
57 /**
58 * Adds a list of form types to the factory.
59 *
60 * @param array $types The form types.
61 *
62 * @return FormFactoryBuilderInterface The builder.
63 */
64 public function addTypes(array $types);
65
66 /**
67 * Adds a form type extension to the factory.
68 *
69 * @param FormTypeExtensionInterface $typeExtension The form type extension.
70 *
71 * @return FormFactoryBuilderInterface The builder.
72 */
73 public function addTypeExtension(FormTypeExtensionInterface $typeExtension);
74
75 /**
76 * Adds a list of form type extensions to the factory.
77 *
78 * @param array $typeExtensions The form type extensions.
79 *
80 * @return FormFactoryBuilderInterface The builder.
81 */
82 public function addTypeExtensions(array $typeExtensions);
83
84 /**
85 * Adds a type guesser to the factory.
86 *
87 * @param FormTypeGuesserInterface $typeGuesser The type guesser.
88 *
89 * @return FormFactoryBuilderInterface The builder.
90 */
91 public function addTypeGuesser(FormTypeGuesserInterface $typeGuesser);
92
93 /**
94 * Adds a list of type guessers to the factory.
95 *
96 * @param array $typeGuessers The type guessers.
97 *
98 * @return FormFactoryBuilderInterface The builder.
99 */
100 public function addTypeGuessers(array $typeGuessers);
101
102 /**
103 * Builds and returns the factory.
104 *
105 * @return FormFactoryInterface The form factory.
106 */
107 public function getFormFactory();
108}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormFactoryInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormFactoryInterface.php
new file mode 100644
index 00000000..31c46b55
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormFactoryInterface.php
@@ -0,0 +1,109 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17interface FormFactoryInterface
18{
19 /**
20 * Returns a form.
21 *
22 * @see createBuilder()
23 *
24 * @param string|FormTypeInterface $type The type of the form
25 * @param mixed $data The initial data
26 * @param array $options The options
27 *
28 * @return FormInterface The form named after the type
29 *
30 * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the given type
31 */
32 public function create($type = 'form', $data = null, array $options = array());
33
34 /**
35 * Returns a form.
36 *
37 * @see createNamedBuilder()
38 *
39 * @param string|integer $name The name of the form
40 * @param string|FormTypeInterface $type The type of the form
41 * @param mixed $data The initial data
42 * @param array $options The options
43 *
44 * @return FormInterface The form
45 *
46 * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the given type
47 */
48 public function createNamed($name, $type = 'form', $data = null, array $options = array());
49
50 /**
51 * Returns a form for a property of a class.
52 *
53 * @see createBuilderForProperty()
54 *
55 * @param string $class The fully qualified class name
56 * @param string $property The name of the property to guess for
57 * @param mixed $data The initial data
58 * @param array $options The options for the builder
59 *
60 * @return FormInterface The form named after the property
61 *
62 * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the form type
63 */
64 public function createForProperty($class, $property, $data = null, array $options = array());
65
66 /**
67 * Returns a form builder.
68 *
69 * @param string|FormTypeInterface $type The type of the form
70 * @param mixed $data The initial data
71 * @param array $options The options
72 *
73 * @return FormBuilderInterface The form builder
74 *
75 * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the given type
76 */
77 public function createBuilder($type = 'form', $data = null, array $options = array());
78
79 /**
80 * Returns a form builder.
81 *
82 * @param string|integer $name The name of the form
83 * @param string|FormTypeInterface $type The type of the form
84 * @param mixed $data The initial data
85 * @param array $options The options
86 *
87 * @return FormBuilderInterface The form builder
88 *
89 * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the given type
90 */
91 public function createNamedBuilder($name, $type = 'form', $data = null, array $options = array());
92
93 /**
94 * Returns a form builder for a property of a class.
95 *
96 * If any of the 'max_length', 'required' and type options can be guessed,
97 * and are not provided in the options argument, the guessed value is used.
98 *
99 * @param string $class The fully qualified class name
100 * @param string $property The name of the property to guess for
101 * @param mixed $data The initial data
102 * @param array $options The options for the builder
103 *
104 * @return FormBuilderInterface The form builder named after the property
105 *
106 * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the form type
107 */
108 public function createBuilderForProperty($class, $property, $data = null, array $options = array());
109}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormInterface.php
new file mode 100644
index 00000000..5a852e86
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormInterface.php
@@ -0,0 +1,288 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * A form group bundling multiple forms in a hierarchical structure.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface FormInterface extends \ArrayAccess, \Traversable, \Countable
20{
21 /**
22 * Sets the parent form.
23 *
24 * @param FormInterface|null $parent The parent form or null if it's the root.
25 *
26 * @return FormInterface The form instance
27 *
28 * @throws Exception\AlreadySubmittedException If the form has already been submitted.
29 * @throws Exception\LogicException When trying to set a parent for a form with
30 * an empty name.
31 */
32 public function setParent(FormInterface $parent = null);
33
34 /**
35 * Returns the parent form.
36 *
37 * @return FormInterface|null The parent form or null if there is none.
38 */
39 public function getParent();
40
41 /**
42 * Adds a child to the form.
43 *
44 * @param FormInterface|string|integer $child The FormInterface instance or the name of the child.
45 * @param string|null $type The child's type, if a name was passed.
46 * @param array $options The child's options, if a name was passed.
47 *
48 * @return FormInterface The form instance
49 *
50 * @throws Exception\AlreadySubmittedException If the form has already been submitted.
51 * @throws Exception\LogicException When trying to add a child to a non-compound form.
52 * @throws Exception\UnexpectedTypeException If $child or $type has an unexpected type.
53 */
54 public function add($child, $type = null, array $options = array());
55
56 /**
57 * Returns the child with the given name.
58 *
59 * @param string $name The name of the child
60 *
61 * @return FormInterface The child form
62 *
63 * @throws \OutOfBoundsException If the named child does not exist.
64 */
65 public function get($name);
66
67 /**
68 * Returns whether a child with the given name exists.
69 *
70 * @param string $name The name of the child
71 *
72 * @return Boolean
73 */
74 public function has($name);
75
76 /**
77 * Removes a child from the form.
78 *
79 * @param string $name The name of the child to remove
80 *
81 * @return FormInterface The form instance
82 *
83 * @throws Exception\AlreadySubmittedException If the form has already been submitted.
84 */
85 public function remove($name);
86
87 /**
88 * Returns all children in this group.
89 *
90 * @return FormInterface[] An array of FormInterface instances
91 */
92 public function all();
93
94 /**
95 * Returns all errors.
96 *
97 * @return FormError[] An array of FormError instances that occurred during validation
98 */
99 public function getErrors();
100
101 /**
102 * Updates the form with default data.
103 *
104 * @param mixed $modelData The data formatted as expected for the underlying object
105 *
106 * @return FormInterface The form instance
107 *
108 * @throws Exception\AlreadySubmittedException If the form has already been submitted.
109 * @throws Exception\LogicException If listeners try to call setData in a cycle. Or if
110 * the view data does not match the expected type
111 * according to {@link FormConfigInterface::getDataClass}.
112 */
113 public function setData($modelData);
114
115 /**
116 * Returns the data in the format needed for the underlying object.
117 *
118 * @return mixed
119 */
120 public function getData();
121
122 /**
123 * Returns the normalized data of the field.
124 *
125 * @return mixed When the field is not submitted, the default data is returned.
126 * When the field is submitted, the normalized submitted data is
127 * returned if the field is valid, null otherwise.
128 */
129 public function getNormData();
130
131 /**
132 * Returns the data transformed by the value transformer.
133 *
134 * @return mixed
135 */
136 public function getViewData();
137
138 /**
139 * Returns the extra data.
140 *
141 * @return array The submitted data which do not belong to a child
142 */
143 public function getExtraData();
144
145 /**
146 * Returns the form's configuration.
147 *
148 * @return FormConfigInterface The configuration.
149 */
150 public function getConfig();
151
152 /**
153 * Returns whether the form is submitted.
154 *
155 * @return Boolean true if the form is submitted, false otherwise
156 */
157 public function isSubmitted();
158
159 /**
160 * Returns the name by which the form is identified in forms.
161 *
162 * @return string The name of the form.
163 */
164 public function getName();
165
166 /**
167 * Returns the property path that the form is mapped to.
168 *
169 * @return \Symfony\Component\PropertyAccess\PropertyPathInterface The property path.
170 */
171 public function getPropertyPath();
172
173 /**
174 * Adds an error to this form.
175 *
176 * @param FormError $error
177 *
178 * @return FormInterface The form instance
179 */
180 public function addError(FormError $error);
181
182 /**
183 * Returns whether the form and all children are valid.
184 *
185 * If the form is not submitted, this method always returns false.
186 *
187 * @return Boolean
188 */
189 public function isValid();
190
191 /**
192 * Returns whether the form is required to be filled out.
193 *
194 * If the form has a parent and the parent is not required, this method
195 * will always return false. Otherwise the value set with setRequired()
196 * is returned.
197 *
198 * @return Boolean
199 */
200 public function isRequired();
201
202 /**
203 * Returns whether this form is disabled.
204 *
205 * The content of a disabled form is displayed, but not allowed to be
206 * modified. The validation of modified disabled forms should fail.
207 *
208 * Forms whose parents are disabled are considered disabled regardless of
209 * their own state.
210 *
211 * @return Boolean
212 */
213 public function isDisabled();
214
215 /**
216 * Returns whether the form is empty.
217 *
218 * @return Boolean
219 */
220 public function isEmpty();
221
222 /**
223 * Returns whether the data in the different formats is synchronized.
224 *
225 * @return Boolean
226 */
227 public function isSynchronized();
228
229 /**
230 * Initializes the form tree.
231 *
232 * Should be called on the root form after constructing the tree.
233 *
234 * @return FormInterface The form instance.
235 */
236 public function initialize();
237
238 /**
239 * Inspects the given request and calls {@link submit()} if the form was
240 * submitted.
241 *
242 * Internally, the request is forwarded to the configured
243 * {@link RequestHandlerInterface} instance, which determines whether to
244 * submit the form or not.
245 *
246 * @param mixed $request The request to handle.
247 *
248 * @return FormInterface The form instance.
249 */
250 public function handleRequest($request = null);
251
252 /**
253 * Submits data to the form, transforms and validates it.
254 *
255 * @param null|string|array $submittedData The submitted data.
256 * @param Boolean $clearMissing Whether to set fields to NULL
257 * when they are missing in the
258 * submitted data.
259 *
260 * @return FormInterface The form instance
261 *
262 * @throws Exception\AlreadySubmittedException If the form has already been submitted.
263 */
264 public function submit($submittedData, $clearMissing = true);
265
266 /**
267 * Returns the root of the form tree.
268 *
269 * @return FormInterface The root of the tree
270 */
271 public function getRoot();
272
273 /**
274 * Returns whether the field is the root of the form tree.
275 *
276 * @return Boolean
277 */
278 public function isRoot();
279
280 /**
281 * Creates a view.
282 *
283 * @param FormView $parent The parent view
284 *
285 * @return FormView The view
286 */
287 public function createView(FormView $parent = null);
288}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormRegistry.php b/vendor/symfony/form/Symfony/Component/Form/FormRegistry.php
new file mode 100644
index 00000000..0267a565
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormRegistry.php
@@ -0,0 +1,180 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\ExceptionInterface;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16use Symfony\Component\Form\Exception\InvalidArgumentException;
17
18/**
19 * The central registry of the Form component.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class FormRegistry implements FormRegistryInterface
24{
25 /**
26 * Extensions
27 *
28 * @var FormExtensionInterface[] An array of FormExtensionInterface
29 */
30 private $extensions = array();
31
32 /**
33 * @var array
34 */
35 private $types = array();
36
37 /**
38 * @var FormTypeGuesserInterface|false|null
39 */
40 private $guesser = false;
41
42 /**
43 * @var ResolvedFormTypeFactoryInterface
44 */
45 private $resolvedTypeFactory;
46
47 /**
48 * Constructor.
49 *
50 * @param FormExtensionInterface[] $extensions An array of FormExtensionInterface
51 * @param ResolvedFormTypeFactoryInterface $resolvedTypeFactory The factory for resolved form types.
52 *
53 * @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface
54 */
55 public function __construct(array $extensions, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
56 {
57 foreach ($extensions as $extension) {
58 if (!$extension instanceof FormExtensionInterface) {
59 throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormExtensionInterface');
60 }
61 }
62
63 $this->extensions = $extensions;
64 $this->resolvedTypeFactory = $resolvedTypeFactory;
65 }
66
67 /**
68 * {@inheritdoc}
69 */
70 public function getType($name)
71 {
72 if (!is_string($name)) {
73 throw new UnexpectedTypeException($name, 'string');
74 }
75
76 if (!isset($this->types[$name])) {
77 /** @var FormTypeInterface $type */
78 $type = null;
79
80 foreach ($this->extensions as $extension) {
81 /* @var FormExtensionInterface $extension */
82 if ($extension->hasType($name)) {
83 $type = $extension->getType($name);
84 break;
85 }
86 }
87
88 if (!$type) {
89 throw new InvalidArgumentException(sprintf('Could not load type "%s"', $name));
90 }
91
92 $this->resolveAndAddType($type);
93 }
94
95 return $this->types[$name];
96 }
97
98 /**
99 * Wraps a type into a ResolvedFormTypeInterface implementation and connects
100 * it with its parent type.
101 *
102 * @param FormTypeInterface $type The type to resolve.
103 *
104 * @return ResolvedFormTypeInterface The resolved type.
105 */
106 private function resolveAndAddType(FormTypeInterface $type)
107 {
108 $parentType = $type->getParent();
109
110 if ($parentType instanceof FormTypeInterface) {
111 $this->resolveAndAddType($parentType);
112 $parentType = $parentType->getName();
113 }
114
115 $typeExtensions = array();
116
117 foreach ($this->extensions as $extension) {
118 /* @var FormExtensionInterface $extension */
119 $typeExtensions = array_merge(
120 $typeExtensions,
121 $extension->getTypeExtensions($type->getName())
122 );
123 }
124
125 $this->types[$type->getName()] = $this->resolvedTypeFactory->createResolvedType(
126 $type,
127 $typeExtensions,
128 $parentType ? $this->getType($parentType) : null
129 );
130 }
131
132 /**
133 * {@inheritdoc}
134 */
135 public function hasType($name)
136 {
137 if (isset($this->types[$name])) {
138 return true;
139 }
140
141 try {
142 $this->getType($name);
143 } catch (ExceptionInterface $e) {
144 return false;
145 }
146
147 return true;
148 }
149
150 /**
151 * {@inheritdoc}
152 */
153 public function getTypeGuesser()
154 {
155 if (false === $this->guesser) {
156 $guessers = array();
157
158 foreach ($this->extensions as $extension) {
159 /* @var FormExtensionInterface $extension */
160 $guesser = $extension->getTypeGuesser();
161
162 if ($guesser) {
163 $guessers[] = $guesser;
164 }
165 }
166
167 $this->guesser = !empty($guessers) ? new FormTypeGuesserChain($guessers) : null;
168 }
169
170 return $this->guesser;
171 }
172
173 /**
174 * {@inheritdoc}
175 */
176 public function getExtensions()
177 {
178 return $this->extensions;
179 }
180}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormRegistryInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormRegistryInterface.php
new file mode 100644
index 00000000..16cd9384
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormRegistryInterface.php
@@ -0,0 +1,57 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * The central registry of the Form component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface FormRegistryInterface
20{
21 /**
22 * Returns a form type by name.
23 *
24 * This methods registers the type extensions from the form extensions.
25 *
26 * @param string $name The name of the type
27 *
28 * @return ResolvedFormTypeInterface The type
29 *
30 * @throws Exception\UnexpectedTypeException if the passed name is not a string
31 * @throws Exception\InvalidArgumentException if the type can not be retrieved from any extension
32 */
33 public function getType($name);
34
35 /**
36 * Returns whether the given form type is supported.
37 *
38 * @param string $name The name of the type
39 *
40 * @return Boolean Whether the type is supported
41 */
42 public function hasType($name);
43
44 /**
45 * Returns the guesser responsible for guessing types.
46 *
47 * @return FormTypeGuesserInterface|null
48 */
49 public function getTypeGuesser();
50
51 /**
52 * Returns the extensions loaded by the framework.
53 *
54 * @return array
55 */
56 public function getExtensions();
57}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormRenderer.php b/vendor/symfony/form/Symfony/Component/Form/FormRenderer.php
new file mode 100644
index 00000000..09b01056
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormRenderer.php
@@ -0,0 +1,304 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\LogicException;
15use Symfony\Component\Form\Exception\BadMethodCallException;
16use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
17
18/**
19 * Renders a form into HTML using a rendering engine.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class FormRenderer implements FormRendererInterface
24{
25 const CACHE_KEY_VAR = 'unique_block_prefix';
26
27 /**
28 * @var FormRendererEngineInterface
29 */
30 private $engine;
31
32 /**
33 * @var CsrfProviderInterface
34 */
35 private $csrfProvider;
36
37 /**
38 * @var array
39 */
40 private $blockNameHierarchyMap = array();
41
42 /**
43 * @var array
44 */
45 private $hierarchyLevelMap = array();
46
47 /**
48 * @var array
49 */
50 private $variableStack = array();
51
52 public function __construct(FormRendererEngineInterface $engine, CsrfProviderInterface $csrfProvider = null)
53 {
54 $this->engine = $engine;
55 $this->csrfProvider = $csrfProvider;
56 }
57
58 /**
59 * {@inheritdoc}
60 */
61 public function getEngine()
62 {
63 return $this->engine;
64 }
65
66 /**
67 * {@inheritdoc}
68 */
69 public function setTheme(FormView $view, $themes)
70 {
71 $this->engine->setTheme($view, $themes);
72 }
73
74 /**
75 * {@inheritdoc}
76 */
77 public function renderCsrfToken($intention)
78 {
79 if (null === $this->csrfProvider) {
80 throw new BadMethodCallException('CSRF token can only be generated if a CsrfProviderInterface is injected in the constructor.');
81 }
82
83 return $this->csrfProvider->generateCsrfToken($intention);
84 }
85
86 /**
87 * {@inheritdoc}
88 */
89 public function renderBlock(FormView $view, $blockName, array $variables = array())
90 {
91 $resource = $this->engine->getResourceForBlockName($view, $blockName);
92
93 if (!$resource) {
94 throw new LogicException(sprintf('No block "%s" found while rendering the form.', $blockName));
95 }
96
97 $viewCacheKey = $view->vars[self::CACHE_KEY_VAR];
98
99 // The variables are cached globally for a view (instead of for the
100 // current suffix)
101 if (!isset($this->variableStack[$viewCacheKey])) {
102 $this->variableStack[$viewCacheKey] = array();
103
104 // The default variable scope contains all view variables, merged with
105 // the variables passed explicitly to the helper
106 $scopeVariables = $view->vars;
107
108 $varInit = true;
109 } else {
110 // Reuse the current scope and merge it with the explicitly passed variables
111 $scopeVariables = end($this->variableStack[$viewCacheKey]);
112
113 $varInit = false;
114 }
115
116 // Merge the passed with the existing attributes
117 if (isset($variables['attr']) && isset($scopeVariables['attr'])) {
118 $variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']);
119 }
120
121 // Merge the passed with the exist *label* attributes
122 if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) {
123 $variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']);
124 }
125
126 // Do not use array_replace_recursive(), otherwise array variables
127 // cannot be overwritten
128 $variables = array_replace($scopeVariables, $variables);
129
130 $this->variableStack[$viewCacheKey][] = $variables;
131
132 // Do the rendering
133 $html = $this->engine->renderBlock($view, $resource, $blockName, $variables);
134
135 // Clear the stack
136 array_pop($this->variableStack[$viewCacheKey]);
137
138 if ($varInit) {
139 unset($this->variableStack[$viewCacheKey]);
140 }
141
142 return $html;
143 }
144
145 /**
146 * {@inheritdoc}
147 */
148 public function searchAndRenderBlock(FormView $view, $blockNameSuffix, array $variables = array())
149 {
150 $renderOnlyOnce = 'row' === $blockNameSuffix || 'widget' === $blockNameSuffix;
151
152 if ($renderOnlyOnce && $view->isRendered()) {
153 return '';
154 }
155
156 // The cache key for storing the variables and types
157 $viewCacheKey = $view->vars[self::CACHE_KEY_VAR];
158 $viewAndSuffixCacheKey = $viewCacheKey.$blockNameSuffix;
159
160 // In templates, we have to deal with two kinds of block hierarchies:
161 //
162 // +---------+ +---------+
163 // | Theme B | -------> | Theme A |
164 // +---------+ +---------+
165 //
166 // form_widget -------> form_widget
167 // ^
168 // |
169 // choice_widget -----> choice_widget
170 //
171 // The first kind of hierarchy is the theme hierarchy. This allows to
172 // override the block "choice_widget" from Theme A in the extending
173 // Theme B. This kind of inheritance needs to be supported by the
174 // template engine and, for example, offers "parent()" or similar
175 // functions to fall back from the custom to the parent implementation.
176 //
177 // The second kind of hierarchy is the form type hierarchy. This allows
178 // to implement a custom "choice_widget" block (no matter in which theme),
179 // or to fallback to the block of the parent type, which would be
180 // "form_widget" in this example (again, no matter in which theme).
181 // If the designer wants to explicitly fallback to "form_widget" in his
182 // custom "choice_widget", for example because he only wants to wrap
183 // a <div> around the original implementation, he can simply call the
184 // widget() function again to render the block for the parent type.
185 //
186 // The second kind is implemented in the following blocks.
187 if (!isset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey])) {
188 // INITIAL CALL
189 // Calculate the hierarchy of template blocks and start on
190 // the bottom level of the hierarchy (= "_<id>_<section>" block)
191 $blockNameHierarchy = array();
192 foreach ($view->vars['block_prefixes'] as $blockNamePrefix) {
193 $blockNameHierarchy[] = $blockNamePrefix.'_'.$blockNameSuffix;
194 }
195 $hierarchyLevel = count($blockNameHierarchy) - 1;
196
197 $hierarchyInit = true;
198 } else {
199 // RECURSIVE CALL
200 // If a block recursively calls searchAndRenderBlock() again, resume rendering
201 // using the parent type in the hierarchy.
202 $blockNameHierarchy = $this->blockNameHierarchyMap[$viewAndSuffixCacheKey];
203 $hierarchyLevel = $this->hierarchyLevelMap[$viewAndSuffixCacheKey] - 1;
204
205 $hierarchyInit = false;
206 }
207
208 // The variables are cached globally for a view (instead of for the
209 // current suffix)
210 if (!isset($this->variableStack[$viewCacheKey])) {
211 $this->variableStack[$viewCacheKey] = array();
212
213 // The default variable scope contains all view variables, merged with
214 // the variables passed explicitly to the helper
215 $scopeVariables = $view->vars;
216
217 $varInit = true;
218 } else {
219 // Reuse the current scope and merge it with the explicitly passed variables
220 $scopeVariables = end($this->variableStack[$viewCacheKey]);
221
222 $varInit = false;
223 }
224
225 // Load the resource where this block can be found
226 $resource = $this->engine->getResourceForBlockNameHierarchy($view, $blockNameHierarchy, $hierarchyLevel);
227
228 // Update the current hierarchy level to the one at which the resource was
229 // found. For example, if looking for "choice_widget", but only a resource
230 // is found for its parent "form_widget", then the level is updated here
231 // to the parent level.
232 $hierarchyLevel = $this->engine->getResourceHierarchyLevel($view, $blockNameHierarchy, $hierarchyLevel);
233
234 // The actually existing block name in $resource
235 $blockName = $blockNameHierarchy[$hierarchyLevel];
236
237 // Escape if no resource exists for this block
238 if (!$resource) {
239 throw new LogicException(sprintf(
240 'Unable to render the form as none of the following blocks exist: "%s".',
241 implode('", "', array_reverse($blockNameHierarchy))
242 ));
243 }
244
245 // Merge the passed with the existing attributes
246 if (isset($variables['attr']) && isset($scopeVariables['attr'])) {
247 $variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']);
248 }
249
250 // Merge the passed with the exist *label* attributes
251 if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) {
252 $variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']);
253 }
254
255 // Do not use array_replace_recursive(), otherwise array variables
256 // cannot be overwritten
257 $variables = array_replace($scopeVariables, $variables);
258
259 // In order to make recursive calls possible, we need to store the block hierarchy,
260 // the current level of the hierarchy and the variables so that this method can
261 // resume rendering one level higher of the hierarchy when it is called recursively.
262 //
263 // We need to store these values in maps (associative arrays) because within a
264 // call to widget() another call to widget() can be made, but for a different view
265 // object. These nested calls should not override each other.
266 $this->blockNameHierarchyMap[$viewAndSuffixCacheKey] = $blockNameHierarchy;
267 $this->hierarchyLevelMap[$viewAndSuffixCacheKey] = $hierarchyLevel;
268
269 // We also need to store the variables for the view so that we can render other
270 // blocks for the same view using the same variables as in the outer block.
271 $this->variableStack[$viewCacheKey][] = $variables;
272
273 // Do the rendering
274 $html = $this->engine->renderBlock($view, $resource, $blockName, $variables);
275
276 // Clear the stack
277 array_pop($this->variableStack[$viewCacheKey]);
278
279 // Clear the caches if they were filled for the first time within
280 // this function call
281 if ($hierarchyInit) {
282 unset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey]);
283 unset($this->hierarchyLevelMap[$viewAndSuffixCacheKey]);
284 }
285
286 if ($varInit) {
287 unset($this->variableStack[$viewCacheKey]);
288 }
289
290 if ($renderOnlyOnce) {
291 $view->setRendered();
292 }
293
294 return $html;
295 }
296
297 /**
298 * {@inheritdoc}
299 */
300 public function humanize($text)
301 {
302 return ucfirst(trim(strtolower(preg_replace(array('/([A-Z])/', '/[_\s]+/'), array('_$1', ' '), $text))));
303 }
304}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormRendererEngineInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormRendererEngineInterface.php
new file mode 100644
index 00000000..e06824ec
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormRendererEngineInterface.php
@@ -0,0 +1,150 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * Adapter for rendering form templates with a specific templating engine.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface FormRendererEngineInterface
20{
21 /**
22 * Sets the theme(s) to be used for rendering a view and its children.
23 *
24 * @param FormView $view The view to assign the theme(s) to.
25 * @param mixed $themes The theme(s). The type of these themes
26 * is open to the implementation.
27 */
28 public function setTheme(FormView $view, $themes);
29
30 /**
31 * Returns the resource for a block name.
32 *
33 * The resource is first searched in the themes attached to $view, then
34 * in the themes of its parent view and so on, until a resource was found.
35 *
36 * The type of the resource is decided by the implementation. The resource
37 * is later passed to {@link renderBlock()} by the rendering algorithm.
38 *
39 * @param FormView $view The view for determining the used themes.
40 * First the themes attached directly to the
41 * view with {@link setTheme()} are considered,
42 * then the ones of its parent etc.
43 * @param string $blockName The name of the block to render.
44 *
45 * @return mixed The renderer resource or false, if none was found.
46 */
47 public function getResourceForBlockName(FormView $view, $blockName);
48
49 /**
50 * Returns the resource for a block hierarchy.
51 *
52 * A block hierarchy is an array which starts with the root of the hierarchy
53 * and continues with the child of that root, the child of that child etc.
54 * The following is an example for a block hierarchy:
55 *
56 * <code>
57 * form_widget
58 * text_widget
59 * url_widget
60 * </code>
61 *
62 * In this example, "url_widget" is the most specific block, while the other
63 * blocks are its ancestors in the hierarchy.
64 *
65 * The second parameter $hierarchyLevel determines the level of the hierarchy
66 * that should be rendered. For example, if $hierarchyLevel is 2 for the
67 * above hierarchy, the engine will first look for the block "url_widget",
68 * then, if that does not exist, for the block "text_widget" etc.
69 *
70 * The type of the resource is decided by the implementation. The resource
71 * is later passed to {@link renderBlock()} by the rendering algorithm.
72 *
73 * @param FormView $view The view for determining the
74 * used themes. First the themes
75 * attached directly to the view
76 * with {@link setTheme()} are
77 * considered, then the ones of
78 * its parent etc.
79 * @param array $blockNameHierarchy The block name hierarchy, with
80 * the root block at the beginning.
81 * @param integer $hierarchyLevel The level in the hierarchy at
82 * which to start looking. Level 0
83 * indicates the root block, i.e.
84 * the first element of
85 * $blockNameHierarchy.
86 *
87 * @return mixed The renderer resource or false, if none was found.
88 */
89 public function getResourceForBlockNameHierarchy(FormView $view, array $blockNameHierarchy, $hierarchyLevel);
90
91 /**
92 * Returns the hierarchy level at which a resource can be found.
93 *
94 * A block hierarchy is an array which starts with the root of the hierarchy
95 * and continues with the child of that root, the child of that child etc.
96 * The following is an example for a block hierarchy:
97 *
98 * <code>
99 * form_widget
100 * text_widget
101 * url_widget
102 * </code>
103 *
104 * The second parameter $hierarchyLevel determines the level of the hierarchy
105 * that should be rendered.
106 *
107 * If we call this method with the hierarchy level 2, the engine will first
108 * look for a resource for block "url_widget". If such a resource exists,
109 * the method returns 2. Otherwise it tries to find a resource for block
110 * "text_widget" (at level 1) and, again, returns 1 if a resource was found.
111 * The method continues to look for resources until the root level was
112 * reached and nothing was found. In this case false is returned.
113 *
114 * The type of the resource is decided by the implementation. The resource
115 * is later passed to {@link renderBlock()} by the rendering algorithm.
116 *
117 * @param FormView $view The view for determining the
118 * used themes. First the themes
119 * attached directly to the view
120 * with {@link setTheme()} are
121 * considered, then the ones of
122 * its parent etc.
123 * @param array $blockNameHierarchy The block name hierarchy, with
124 * the root block at the beginning.
125 * @param integer $hierarchyLevel The level in the hierarchy at
126 * which to start looking. Level 0
127 * indicates the root block, i.e.
128 * the first element of
129 * $blockNameHierarchy.
130 *
131 * @return integer|Boolean The hierarchy level or false, if no resource was found.
132 */
133 public function getResourceHierarchyLevel(FormView $view, array $blockNameHierarchy, $hierarchyLevel);
134
135 /**
136 * Renders a block in the given renderer resource.
137 *
138 * The resource can be obtained by calling {@link getResourceForBlock()}
139 * or {@link getResourceForBlockHierarchy()}. The type of the resource is
140 * decided by the implementation.
141 *
142 * @param FormView $view The view to render.
143 * @param mixed $resource The renderer resource.
144 * @param string $blockName The name of the block to render.
145 * @param array $variables The variables to pass to the template.
146 *
147 * @return string The HTML markup.
148 */
149 public function renderBlock(FormView $view, $resource, $blockName, array $variables = array());
150}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormRendererInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormRendererInterface.php
new file mode 100644
index 00000000..848e7125
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormRendererInterface.php
@@ -0,0 +1,103 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * Renders a form into HTML.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface FormRendererInterface
20{
21 /**
22 * Returns the engine used by this renderer.
23 *
24 * @return FormRendererEngineInterface The renderer engine.
25 */
26 public function getEngine();
27
28 /**
29 * Sets the theme(s) to be used for rendering a view and its children.
30 *
31 * @param FormView $view The view to assign the theme(s) to.
32 * @param mixed $themes The theme(s). The type of these themes
33 * is open to the implementation.
34 */
35 public function setTheme(FormView $view, $themes);
36
37 /**
38 * Renders a named block of the form theme.
39 *
40 * @param FormView $view The view for which to render the block.
41 * @param string $blockName The name of the block.
42 * @param array $variables The variables to pass to the template.
43 *
44 * @return string The HTML markup
45 */
46 public function renderBlock(FormView $view, $blockName, array $variables = array());
47
48 /**
49 * Searches and renders a block for a given name suffix.
50 *
51 * The block is searched by combining the block names stored in the
52 * form view with the given suffix. If a block name is found, that
53 * block is rendered.
54 *
55 * If this method is called recursively, the block search is continued
56 * where a block was found before.
57 *
58 * @param FormView $view The view for which to render the block.
59 * @param string $blockNameSuffix The suffix of the block name.
60 * @param array $variables The variables to pass to the template.
61 *
62 * @return string The HTML markup
63 */
64 public function searchAndRenderBlock(FormView $view, $blockNameSuffix, array $variables = array());
65
66 /**
67 * Renders a CSRF token.
68 *
69 * Use this helper for CSRF protection without the overhead of creating a
70 * form.
71 *
72 * <code>
73 * <input type="hidden" name="token" value="<?php $renderer->renderCsrfToken('rm_user_'.$user->getId()) ?>">
74 * </code>
75 *
76 * Check the token in your action using the same intention.
77 *
78 * <code>
79 * $csrfProvider = $this->get('form.csrf_provider');
80 * if (!$csrfProvider->isCsrfTokenValid('rm_user_'.$user->getId(), $token)) {
81 * throw new \RuntimeException('CSRF attack detected.');
82 * }
83 * </code>
84 *
85 * @param string $intention The intention of the protected action
86 *
87 * @return string A CSRF token
88 */
89 public function renderCsrfToken($intention);
90
91 /**
92 * Makes a technical name human readable.
93 *
94 * Sequences of underscores are replaced by single spaces. The first letter
95 * of the resulting string is capitalized, while all other letters are
96 * turned to lowercase.
97 *
98 * @param string $text The text to humanize.
99 *
100 * @return string The humanized text.
101 */
102 public function humanize($text);
103}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormTypeExtensionInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormTypeExtensionInterface.php
new file mode 100644
index 00000000..9866b28b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormTypeExtensionInterface.php
@@ -0,0 +1,75 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\OptionsResolver\OptionsResolverInterface;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface FormTypeExtensionInterface
20{
21 /**
22 * Builds the form.
23 *
24 * This method is called after the extended type has built the form to
25 * further modify it.
26 *
27 * @see FormTypeInterface::buildForm()
28 *
29 * @param FormBuilderInterface $builder The form builder
30 * @param array $options The options
31 */
32 public function buildForm(FormBuilderInterface $builder, array $options);
33
34 /**
35 * Builds the view.
36 *
37 * This method is called after the extended type has built the view to
38 * further modify it.
39 *
40 * @see FormTypeInterface::buildView()
41 *
42 * @param FormView $view The view
43 * @param FormInterface $form The form
44 * @param array $options The options
45 */
46 public function buildView(FormView $view, FormInterface $form, array $options);
47
48 /**
49 * Finishes the view.
50 *
51 * This method is called after the extended type has finished the view to
52 * further modify it.
53 *
54 * @see FormTypeInterface::finishView()
55 *
56 * @param FormView $view The view
57 * @param FormInterface $form The form
58 * @param array $options The options
59 */
60 public function finishView(FormView $view, FormInterface $form, array $options);
61
62 /**
63 * Overrides the default options from the extended type.
64 *
65 * @param OptionsResolverInterface $resolver The resolver for the options.
66 */
67 public function setDefaultOptions(OptionsResolverInterface $resolver);
68
69 /**
70 * Returns the name of the type being extended.
71 *
72 * @return string The name of the type being extended
73 */
74 public function getExtendedType();
75}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormTypeGuesserChain.php b/vendor/symfony/form/Symfony/Component/Form/FormTypeGuesserChain.php
new file mode 100644
index 00000000..c7f8ece3
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormTypeGuesserChain.php
@@ -0,0 +1,104 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Guess\Guess;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16
17class FormTypeGuesserChain implements FormTypeGuesserInterface
18{
19 private $guessers = array();
20
21 /**
22 * Constructor.
23 *
24 * @param array $guessers Guessers as instances of FormTypeGuesserInterface
25 *
26 * @throws UnexpectedTypeException if any guesser does not implement FormTypeGuesserInterface
27 */
28 public function __construct(array $guessers)
29 {
30 foreach ($guessers as $guesser) {
31 if (!$guesser instanceof FormTypeGuesserInterface) {
32 throw new UnexpectedTypeException($guesser, 'Symfony\Component\Form\FormTypeGuesserInterface');
33 }
34
35 if ($guesser instanceof self) {
36 $this->guessers = array_merge($this->guessers, $guesser->guessers);
37 } else {
38 $this->guessers[] = $guesser;
39 }
40 }
41 }
42
43 /**
44 * {@inheritDoc}
45 */
46 public function guessType($class, $property)
47 {
48 return $this->guess(function ($guesser) use ($class, $property) {
49 return $guesser->guessType($class, $property);
50 });
51 }
52
53 /**
54 * {@inheritDoc}
55 */
56 public function guessRequired($class, $property)
57 {
58 return $this->guess(function ($guesser) use ($class, $property) {
59 return $guesser->guessRequired($class, $property);
60 });
61 }
62
63 /**
64 * {@inheritDoc}
65 */
66 public function guessMaxLength($class, $property)
67 {
68 return $this->guess(function ($guesser) use ($class, $property) {
69 return $guesser->guessMaxLength($class, $property);
70 });
71 }
72
73 /**
74 * {@inheritDoc}
75 */
76 public function guessPattern($class, $property)
77 {
78 return $this->guess(function ($guesser) use ($class, $property) {
79 return $guesser->guessPattern($class, $property);
80 });
81 }
82
83 /**
84 * Executes a closure for each guesser and returns the best guess from the
85 * return values
86 *
87 * @param \Closure $closure The closure to execute. Accepts a guesser
88 * as argument and should return a Guess instance
89 *
90 * @return Guess The guess with the highest confidence
91 */
92 private function guess(\Closure $closure)
93 {
94 $guesses = array();
95
96 foreach ($this->guessers as $guesser) {
97 if ($guess = $closure($guesser)) {
98 $guesses[] = $guess;
99 }
100 }
101
102 return Guess::getBestGuess($guesses);
103 }
104}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormTypeGuesserInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormTypeGuesserInterface.php
new file mode 100644
index 00000000..e8b603fa
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormTypeGuesserInterface.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17interface FormTypeGuesserInterface
18{
19 /**
20 * Returns a field guess for a property name of a class
21 *
22 * @param string $class The fully qualified class name
23 * @param string $property The name of the property to guess for
24 *
25 * @return Guess\TypeGuess A guess for the field's type and options
26 */
27 public function guessType($class, $property);
28
29 /**
30 * Returns a guess whether a property of a class is required
31 *
32 * @param string $class The fully qualified class name
33 * @param string $property The name of the property to guess for
34 *
35 * @return Guess\Guess A guess for the field's required setting
36 */
37 public function guessRequired($class, $property);
38
39 /**
40 * Returns a guess about the field's maximum length
41 *
42 * @param string $class The fully qualified class name
43 * @param string $property The name of the property to guess for
44 *
45 * @return Guess\Guess A guess for the field's maximum length
46 */
47 public function guessMaxLength($class, $property);
48
49 /**
50 * Returns a guess about the field's pattern
51 *
52 * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below
53 * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess.
54 * Example:
55 * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5)
56 * @link https://github.com/symfony/symfony/pull/3927
57 *
58 * @param string $class The fully qualified class name
59 * @param string $property The name of the property to guess for
60 *
61 * @return Guess\Guess A guess for the field's required pattern
62 */
63 public function guessPattern($class, $property);
64}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormTypeInterface.php b/vendor/symfony/form/Symfony/Component/Form/FormTypeInterface.php
new file mode 100644
index 00000000..bcef73c6
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormTypeInterface.php
@@ -0,0 +1,95 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\OptionsResolver\OptionsResolverInterface;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface FormTypeInterface
20{
21 /**
22 * Builds the form.
23 *
24 * This method is called for each type in the hierarchy starting form the
25 * top most type. Type extensions can further modify the form.
26 *
27 * @see FormTypeExtensionInterface::buildForm()
28 *
29 * @param FormBuilderInterface $builder The form builder
30 * @param array $options The options
31 */
32 public function buildForm(FormBuilderInterface $builder, array $options);
33
34 /**
35 * Builds the form view.
36 *
37 * This method is called for each type in the hierarchy starting form the
38 * top most type. Type extensions can further modify the view.
39 *
40 * A view of a form is built before the views of the child forms are built.
41 * This means that you cannot access child views in this method. If you need
42 * to do so, move your logic to {@link finishView()} instead.
43 *
44 * @see FormTypeExtensionInterface::buildView()
45 *
46 * @param FormView $view The view
47 * @param FormInterface $form The form
48 * @param array $options The options
49 */
50 public function buildView(FormView $view, FormInterface $form, array $options);
51
52 /**
53 * Finishes the form view.
54 *
55 * This method gets called for each type in the hierarchy starting form the
56 * top most type. Type extensions can further modify the view.
57 *
58 * When this method is called, views of the form's children have already
59 * been built and finished and can be accessed. You should only implement
60 * such logic in this method that actually accesses child views. For everything
61 * else you are recommended to implement {@link buildView()} instead.
62 *
63 * @see FormTypeExtensionInterface::finishView()
64 *
65 * @param FormView $view The view
66 * @param FormInterface $form The form
67 * @param array $options The options
68 */
69 public function finishView(FormView $view, FormInterface $form, array $options);
70
71 /**
72 * Sets the default options for this type.
73 *
74 * @param OptionsResolverInterface $resolver The resolver for the options.
75 */
76 public function setDefaultOptions(OptionsResolverInterface $resolver);
77
78 /**
79 * Returns the name of the parent type.
80 *
81 * You can also return a type instance from this method, although doing so
82 * is discouraged because it leads to a performance penalty. The support
83 * for returning type instances may be dropped from future releases.
84 *
85 * @return string|null|FormTypeInterface The name of the parent type if any, null otherwise.
86 */
87 public function getParent();
88
89 /**
90 * Returns the name of this type.
91 *
92 * @return string The name of this type
93 */
94 public function getName();
95}
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormView.php b/vendor/symfony/form/Symfony/Component/Form/FormView.php
new file mode 100644
index 00000000..1f53ec6a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/FormView.php
@@ -0,0 +1,159 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\BadMethodCallException;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
20{
21 /**
22 * The variables assigned to this view.
23 * @var array
24 */
25 public $vars = array(
26 'value' => null,
27 'attr' => array(),
28 );
29
30 /**
31 * The parent view.
32 * @var FormView
33 */
34 public $parent;
35
36 /**
37 * The child views.
38 * @var array
39 */
40 public $children = array();
41
42 /**
43 * Is the form attached to this renderer rendered?
44 *
45 * Rendering happens when either the widget or the row method was called.
46 * Row implicitly includes widget, however certain rendering mechanisms
47 * have to skip widget rendering when a row is rendered.
48 *
49 * @var Boolean
50 */
51 private $rendered = false;
52
53 public function __construct(FormView $parent = null)
54 {
55 $this->parent = $parent;
56 }
57
58 /**
59 * Returns whether the view was already rendered.
60 *
61 * @return Boolean Whether this view's widget is rendered.
62 */
63 public function isRendered()
64 {
65 $hasChildren = 0 < count($this->children);
66
67 if (true === $this->rendered || !$hasChildren) {
68 return $this->rendered;
69 }
70
71 if ($hasChildren) {
72 foreach ($this->children as $child) {
73 if (!$child->isRendered()) {
74 return false;
75 }
76 }
77
78 return $this->rendered = true;
79 }
80
81 return false;
82 }
83
84 /**
85 * Marks the view as rendered.
86 *
87 * @return FormView The view object.
88 */
89 public function setRendered()
90 {
91 $this->rendered = true;
92
93 return $this;
94 }
95
96 /**
97 * Returns a child by name (implements \ArrayAccess).
98 *
99 * @param string $name The child name
100 *
101 * @return FormView The child view
102 */
103 public function offsetGet($name)
104 {
105 return $this->children[$name];
106 }
107
108 /**
109 * Returns whether the given child exists (implements \ArrayAccess).
110 *
111 * @param string $name The child name
112 *
113 * @return Boolean Whether the child view exists
114 */
115 public function offsetExists($name)
116 {
117 return isset($this->children[$name]);
118 }
119
120 /**
121 * Implements \ArrayAccess.
122 *
123 * @throws BadMethodCallException always as setting a child by name is not allowed
124 */
125 public function offsetSet($name, $value)
126 {
127 throw new BadMethodCallException('Not supported');
128 }
129
130 /**
131 * Removes a child (implements \ArrayAccess).
132 *
133 * @param string $name The child name
134 */
135 public function offsetUnset($name)
136 {
137 unset($this->children[$name]);
138 }
139
140 /**
141 * Returns an iterator to iterate over children (implements \IteratorAggregate)
142 *
143 * @return \ArrayIterator The iterator
144 */
145 public function getIterator()
146 {
147 return new \ArrayIterator($this->children);
148 }
149
150 /**
151 * Implements \Countable.
152 *
153 * @return integer The number of children views
154 */
155 public function count()
156 {
157 return count($this->children);
158 }
159}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Forms.php b/vendor/symfony/form/Symfony/Component/Form/Forms.php
new file mode 100644
index 00000000..c949c1f4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Forms.php
@@ -0,0 +1,185 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Extension\Core\CoreExtension;
15
16/**
17 * Entry point of the Form component.
18 *
19 * Use this class to conveniently create new form factories:
20 *
21 * <code>
22 * use Symfony\Component\Form\Forms;
23 *
24 * $formFactory = Forms::createFormFactory();
25 *
26 * $form = $formFactory->createBuilder()
27 * ->add('firstName', 'text')
28 * ->add('lastName', 'text')
29 * ->add('age', 'integer')
30 * ->add('gender', 'choice', array(
31 * 'choices' => array('m' => 'Male', 'f' => 'Female'),
32 * ))
33 * ->getForm();
34 * </code>
35 *
36 * You can also add custom extensions to the form factory:
37 *
38 * <code>
39 * $formFactory = Forms::createFormFactoryBuilder()
40 * ->addExtension(new AcmeExtension())
41 * ->getFormFactory();
42 * </code>
43 *
44 * If you create custom form types or type extensions, it is
45 * generally recommended to create your own extensions that lazily
46 * load these types and type extensions. In projects where performance
47 * does not matter that much, you can also pass them directly to the
48 * form factory:
49 *
50 * <code>
51 * $formFactory = Forms::createFormFactoryBuilder()
52 * ->addType(new PersonType())
53 * ->addType(new PhoneNumberType())
54 * ->addTypeExtension(new FormTypeHelpTextExtension())
55 * ->getFormFactory();
56 * </code>
57 *
58 * Support for CSRF protection is provided by the CsrfExtension.
59 * This extension needs a CSRF provider with a strong secret
60 * (e.g. a 20 character long random string). The default
61 * implementation for this is DefaultCsrfProvider:
62 *
63 * <code>
64 * use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
65 * use Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider;
66 *
67 * $secret = 'V8a5Z97e...';
68 * $formFactory = Forms::createFormFactoryBuilder()
69 * ->addExtension(new CsrfExtension(new DefaultCsrfProvider($secret)))
70 * ->getFormFactory();
71 * </code>
72 *
73 * Support for the HttpFoundation is provided by the
74 * HttpFoundationExtension. You are also advised to load the CSRF
75 * extension with the driver for HttpFoundation's Session class:
76 *
77 * <code>
78 * use Symfony\Component\HttpFoundation\Session\Session;
79 * use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension;
80 * use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
81 * use Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider;
82 *
83 * $session = new Session();
84 * $secret = 'V8a5Z97e...';
85 * $formFactory = Forms::createFormFactoryBuilder()
86 * ->addExtension(new HttpFoundationExtension())
87 * ->addExtension(new CsrfExtension(new SessionCsrfProvider($session, $secret)))
88 * ->getFormFactory();
89 * </code>
90 *
91 * Support for the Validator component is provided by ValidatorExtension.
92 * This extension needs a validator object to function properly:
93 *
94 * <code>
95 * use Symfony\Component\Validator\Validation;
96 * use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
97 *
98 * $validator = Validation::createValidator();
99 * $formFactory = Forms::createFormFactoryBuilder()
100 * ->addExtension(new ValidatorExtension($validator))
101 * ->getFormFactory();
102 * </code>
103 *
104 * Support for the Templating component is provided by TemplatingExtension.
105 * This extension needs a PhpEngine object for rendering forms. As second
106 * argument you should pass the names of the default themes. Here is an
107 * example for using the default layout with "<div>" tags:
108 *
109 * <code>
110 * use Symfony\Component\Form\Extension\Templating\TemplatingExtension;
111 *
112 * $formFactory = Forms::createFormFactoryBuilder()
113 * ->addExtension(new TemplatingExtension($engine, null, array(
114 * 'FrameworkBundle:Form',
115 * )))
116 * ->getFormFactory();
117 * </code>
118 *
119 * The next example shows how to include the "<table>" layout:
120 *
121 * <code>
122 * use Symfony\Component\Form\Extension\Templating\TemplatingExtension;
123 *
124 * $formFactory = Forms::createFormFactoryBuilder()
125 * ->addExtension(new TemplatingExtension($engine, null, array(
126 * 'FrameworkBundle:Form',
127 * 'FrameworkBundle:FormTable',
128 * )))
129 * ->getFormFactory();
130 * </code>
131 *
132 * If you also loaded the CsrfExtension, you should pass the CSRF provider
133 * to the extension so that you can render CSRF tokens in your templates
134 * more easily:
135 *
136 * <code>
137 * use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
138 * use Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider;
139 * use Symfony\Component\Form\Extension\Templating\TemplatingExtension;
140 *
141 *
142 * $secret = 'V8a5Z97e...';
143 * $csrfProvider = new DefaultCsrfProvider($secret);
144 * $formFactory = Forms::createFormFactoryBuilder()
145 * ->addExtension(new CsrfExtension($csrfProvider))
146 * ->addExtension(new TemplatingExtension($engine, $csrfProvider, array(
147 * 'FrameworkBundle:Form',
148 * )))
149 * ->getFormFactory();
150 * </code>
151 *
152 * @author Bernhard Schussek <bschussek@gmail.com>
153 */
154final class Forms
155{
156 /**
157 * Creates a form factory with the default configuration.
158 *
159 * @return FormFactoryInterface The form factory.
160 */
161 public static function createFormFactory()
162 {
163 return self::createFormFactoryBuilder()->getFormFactory();
164 }
165
166 /**
167 * Creates a form factory builder with the default configuration.
168 *
169 * @return FormFactoryBuilderInterface The form factory builder.
170 */
171 public static function createFormFactoryBuilder()
172 {
173 $builder = new FormFactoryBuilder();
174 $builder->addExtension(new CoreExtension());
175
176 return $builder;
177 }
178
179 /**
180 * This class cannot be instantiated.
181 */
182 private function __construct()
183 {
184 }
185}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Guess/Guess.php b/vendor/symfony/form/Symfony/Component/Form/Guess/Guess.php
new file mode 100644
index 00000000..b33c3d80
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Guess/Guess.php
@@ -0,0 +1,113 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Guess;
13
14use Symfony\Component\Form\Exception\InvalidArgumentException;
15
16/**
17 * Base class for guesses made by TypeGuesserInterface implementation
18 *
19 * Each instance contains a confidence value about the correctness of the guess.
20 * Thus an instance with confidence HIGH_CONFIDENCE is more likely to be
21 * correct than an instance with confidence LOW_CONFIDENCE.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25abstract class Guess
26{
27 /**
28 * Marks an instance with a value that is extremely likely to be correct
29 * @var integer
30 */
31 const VERY_HIGH_CONFIDENCE = 3;
32
33 /**
34 * Marks an instance with a value that is very likely to be correct
35 * @var integer
36 */
37 const HIGH_CONFIDENCE = 2;
38
39 /**
40 * Marks an instance with a value that is likely to be correct
41 * @var integer
42 */
43 const MEDIUM_CONFIDENCE = 1;
44
45 /**
46 * Marks an instance with a value that may be correct
47 * @var integer
48 */
49 const LOW_CONFIDENCE = 0;
50
51 /**
52 * The confidence about the correctness of the value
53 *
54 * One of VERY_HIGH_CONFIDENCE, HIGH_CONFIDENCE, MEDIUM_CONFIDENCE
55 * and LOW_CONFIDENCE.
56 *
57 * @var integer
58 */
59 private $confidence;
60
61 /**
62 * Returns the guess most likely to be correct from a list of guesses
63 *
64 * If there are multiple guesses with the same, highest confidence, the
65 * returned guess is any of them.
66 *
67 * @param array $guesses A list of guesses
68 *
69 * @return Guess The guess with the highest confidence
70 */
71 public static function getBestGuess(array $guesses)
72 {
73 $result = null;
74 $maxConfidence = -1;
75
76 foreach ($guesses as $guess) {
77 if ($maxConfidence < $confidence = $guess->getConfidence()) {
78 $maxConfidence = $confidence;
79 $result = $guess;
80 }
81 }
82
83 return $result;
84 }
85
86 /**
87 * Constructor
88 *
89 * @param integer $confidence The confidence
90 *
91 * @throws InvalidArgumentException if the given value of confidence is unknown
92 */
93 public function __construct($confidence)
94 {
95 if (self::VERY_HIGH_CONFIDENCE !== $confidence && self::HIGH_CONFIDENCE !== $confidence &&
96 self::MEDIUM_CONFIDENCE !== $confidence && self::LOW_CONFIDENCE !== $confidence) {
97 throw new InvalidArgumentException('The confidence should be one of the constants defined in Guess.');
98 }
99
100 $this->confidence = $confidence;
101 }
102
103 /**
104 * Returns the confidence that the guessed value is correct
105 *
106 * @return integer One of the constants VERY_HIGH_CONFIDENCE,
107 * HIGH_CONFIDENCE, MEDIUM_CONFIDENCE and LOW_CONFIDENCE
108 */
109 public function getConfidence()
110 {
111 return $this->confidence;
112 }
113}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Guess/TypeGuess.php b/vendor/symfony/form/Symfony/Component/Form/Guess/TypeGuess.php
new file mode 100644
index 00000000..3241e603
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Guess/TypeGuess.php
@@ -0,0 +1,70 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Guess;
13
14/**
15 * Contains a guessed class name and a list of options for creating an instance
16 * of that class
17 *
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class TypeGuess extends Guess
21{
22 /**
23 * The guessed field type
24 * @var string
25 */
26 private $type;
27
28 /**
29 * The guessed options for creating an instance of the guessed class
30 * @var array
31 */
32 private $options;
33
34 /**
35 * Constructor
36 *
37 * @param string $type The guessed field type
38 * @param array $options The options for creating instances of the
39 * guessed class
40 * @param integer $confidence The confidence that the guessed class name
41 * is correct
42 */
43 public function __construct($type, array $options, $confidence)
44 {
45 parent::__construct($confidence);
46
47 $this->type = $type;
48 $this->options = $options;
49 }
50
51 /**
52 * Returns the guessed field type
53 *
54 * @return string
55 */
56 public function getType()
57 {
58 return $this->type;
59 }
60
61 /**
62 * Returns the guessed options for creating instances of the guessed type
63 *
64 * @return array
65 */
66 public function getOptions()
67 {
68 return $this->options;
69 }
70}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Guess/ValueGuess.php b/vendor/symfony/form/Symfony/Component/Form/Guess/ValueGuess.php
new file mode 100644
index 00000000..2e3333ba
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Guess/ValueGuess.php
@@ -0,0 +1,50 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Guess;
13
14/**
15 * Contains a guessed value
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class ValueGuess extends Guess
20{
21 /**
22 * The guessed value
23 * @var array
24 */
25 private $value;
26
27 /**
28 * Constructor
29 *
30 * @param string $value The guessed value
31 * @param integer $confidence The confidence that the guessed class name
32 * is correct
33 */
34 public function __construct($value, $confidence)
35 {
36 parent::__construct($confidence);
37
38 $this->value = $value;
39 }
40
41 /**
42 * Returns the guessed value
43 *
44 * @return mixed
45 */
46 public function getValue()
47 {
48 return $this->value;
49 }
50}
diff --git a/vendor/symfony/form/Symfony/Component/Form/LICENSE b/vendor/symfony/form/Symfony/Component/Form/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/form/Symfony/Component/Form/NativeRequestHandler.php b/vendor/symfony/form/Symfony/Component/Form/NativeRequestHandler.php
new file mode 100644
index 00000000..aaa4e4c0
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/NativeRequestHandler.php
@@ -0,0 +1,194 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\UnexpectedTypeException;
15use Symfony\Component\Form\FormInterface;
16use Symfony\Component\Form\RequestHandlerInterface;
17
18/**
19 * A request handler using PHP's super globals $_GET, $_POST and $_SERVER.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class NativeRequestHandler implements RequestHandlerInterface
24{
25 /**
26 * The allowed keys of the $_FILES array.
27 *
28 * @var array
29 */
30 private static $fileKeys = array(
31 'error',
32 'name',
33 'size',
34 'tmp_name',
35 'type',
36 );
37
38 /**
39 * {@inheritdoc}
40 */
41 public function handleRequest(FormInterface $form, $request = null)
42 {
43 if (null !== $request) {
44 throw new UnexpectedTypeException($request, 'null');
45 }
46
47 $name = $form->getName();
48 $method = $form->getConfig()->getMethod();
49
50 if ($method !== self::getRequestMethod()) {
51 return;
52 }
53
54 if ('GET' === $method) {
55 if ('' === $name) {
56 $data = $_GET;
57 } else {
58 // Don't submit GET requests if the form's name does not exist
59 // in the request
60 if (!isset($_GET[$name])) {
61 return;
62 }
63
64 $data = $_GET[$name];
65 }
66 } else {
67 $fixedFiles = array();
68 foreach ($_FILES as $name => $file) {
69 $fixedFiles[$name] = self::stripEmptyFiles(self::fixPhpFilesArray($file));
70 }
71
72 if ('' === $name) {
73 $params = $_POST;
74 $files = $fixedFiles;
75 } else {
76 $default = $form->getConfig()->getCompound() ? array() : null;
77 $params = isset($_POST[$name]) ? $_POST[$name] : $default;
78 $files = isset($fixedFiles[$name]) ? $fixedFiles[$name] : $default;
79 }
80
81 if (is_array($params) && is_array($files)) {
82 $data = array_replace_recursive($params, $files);
83 } else {
84 $data = $params ?: $files;
85 }
86 }
87
88 // Don't auto-submit the form unless at least one field is present.
89 if ('' === $name && count(array_intersect_key($data, $form->all())) <= 0) {
90 return;
91 }
92
93 $form->submit($data, 'PATCH' !== $method);
94 }
95
96 /**
97 * Returns the method used to submit the request to the server.
98 *
99 * @return string The request method.
100 */
101 private static function getRequestMethod()
102 {
103 $method = isset($_SERVER['REQUEST_METHOD'])
104 ? strtoupper($_SERVER['REQUEST_METHOD'])
105 : 'GET';
106
107 if ('POST' === $method && isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
108 $method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
109 }
110
111 return $method;
112 }
113
114 /**
115 * Fixes a malformed PHP $_FILES array.
116 *
117 * PHP has a bug that the format of the $_FILES array differs, depending on
118 * whether the uploaded file fields had normal field names or array-like
119 * field names ("normal" vs. "parent[child]").
120 *
121 * This method fixes the array to look like the "normal" $_FILES array.
122 *
123 * It's safe to pass an already converted array, in which case this method
124 * just returns the original array unmodified.
125 *
126 * This method is identical to {@link Symfony\Component\HttpFoundation\FileBag::fixPhpFilesArray}
127 * and should be kept as such in order to port fixes quickly and easily.
128 *
129 * @param array $data
130 *
131 * @return array
132 */
133 private static function fixPhpFilesArray($data)
134 {
135 if (!is_array($data)) {
136 return $data;
137 }
138
139 $keys = array_keys($data);
140 sort($keys);
141
142 if (self::$fileKeys !== $keys || !isset($data['name']) || !is_array($data['name'])) {
143 return $data;
144 }
145
146 $files = $data;
147 foreach (self::$fileKeys as $k) {
148 unset($files[$k]);
149 }
150
151 foreach (array_keys($data['name']) as $key) {
152 $files[$key] = self::fixPhpFilesArray(array(
153 'error' => $data['error'][$key],
154 'name' => $data['name'][$key],
155 'type' => $data['type'][$key],
156 'tmp_name' => $data['tmp_name'][$key],
157 'size' => $data['size'][$key]
158 ));
159 }
160
161 return $files;
162 }
163
164 /**
165 * Sets empty uploaded files to NULL in the given uploaded files array.
166 *
167 * @param mixed $data The file upload data.
168 *
169 * @return array|null Returns the stripped upload data.
170 */
171 private static function stripEmptyFiles($data)
172 {
173 if (!is_array($data)) {
174 return $data;
175 }
176
177 $keys = array_keys($data);
178 sort($keys);
179
180 if (self::$fileKeys === $keys) {
181 if (UPLOAD_ERR_NO_FILE === $data['error']) {
182 return null;
183 }
184
185 return $data;
186 }
187
188 foreach ($data as $key => $value) {
189 $data[$key] = self::stripEmptyFiles($value);
190 }
191
192 return $data;
193 }
194}
diff --git a/vendor/symfony/form/Symfony/Component/Form/PreloadedExtension.php b/vendor/symfony/form/Symfony/Component/Form/PreloadedExtension.php
new file mode 100644
index 00000000..2d3e9efb
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/PreloadedExtension.php
@@ -0,0 +1,97 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\InvalidArgumentException;
15
16/**
17 * A form extension with preloaded types, type exceptions and type guessers.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class PreloadedExtension implements FormExtensionInterface
22{
23 /**
24 * @var array
25 */
26 private $types = array();
27
28 /**
29 * @var array
30 */
31 private $typeExtensions = array();
32
33 /**
34 * @var FormTypeGuesserInterface
35 */
36 private $typeGuesser;
37
38 /**
39 * Creates a new preloaded extension.
40 *
41 * @param array $types The types that the extension should support.
42 * @param array $typeExtensions The type extensions that the extension should support.
43 * @param FormTypeGuesserInterface|null $typeGuesser The guesser that the extension should support.
44 */
45 public function __construct(array $types, array $typeExtensions, FormTypeGuesserInterface $typeGuesser = null)
46 {
47 $this->types = $types;
48 $this->typeExtensions = $typeExtensions;
49 $this->typeGuesser = $typeGuesser;
50 }
51
52 /**
53 * {@inheritdoc}
54 */
55 public function getType($name)
56 {
57 if (!isset($this->types[$name])) {
58 throw new InvalidArgumentException(sprintf('The type "%s" can not be loaded by this extension', $name));
59 }
60
61 return $this->types[$name];
62 }
63
64 /**
65 * {@inheritdoc}
66 */
67 public function hasType($name)
68 {
69 return isset($this->types[$name]);
70 }
71
72 /**
73 * {@inheritdoc}
74 */
75 public function getTypeExtensions($name)
76 {
77 return isset($this->typeExtensions[$name])
78 ? $this->typeExtensions[$name]
79 : array();
80 }
81
82 /**
83 * {@inheritdoc}
84 */
85 public function hasTypeExtensions($name)
86 {
87 return !empty($this->typeExtensions[$name]);
88 }
89
90 /**
91 * {@inheritdoc}
92 */
93 public function getTypeGuesser()
94 {
95 return $this->typeGuesser;
96 }
97}
diff --git a/vendor/symfony/form/Symfony/Component/Form/README.md b/vendor/symfony/form/Symfony/Component/Form/README.md
new file mode 100644
index 00000000..7bfff7fd
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/README.md
@@ -0,0 +1,26 @@
1Form Component
2==============
3
4Form provides tools for defining forms, rendering and mapping request data to
5related models. Furthermore it provides integration with the Validation
6component.
7
8Resources
9---------
10
11Silex integration:
12
13https://github.com/fabpot/Silex/blob/master/src/Silex/Provider/FormServiceProvider.php
14
15Documentation:
16
17http://symfony.com/doc/2.3/book/forms.html
18
19Resources
20---------
21
22You can run the unit tests with the following command:
23
24 $ cd path/to/Symfony/Component/Form/
25 $ composer.phar install --dev
26 $ phpunit
diff --git a/vendor/symfony/form/Symfony/Component/Form/RequestHandlerInterface.php b/vendor/symfony/form/Symfony/Component/Form/RequestHandlerInterface.php
new file mode 100644
index 00000000..d0a58e69
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/RequestHandlerInterface.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * Submits forms if they were submitted.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface RequestHandlerInterface
20{
21 /**
22 * Submits a form if it was submitted.
23 *
24 * @param FormInterface $form The form to submit.
25 * @param mixed $request The current request.
26 */
27 public function handleRequest(FormInterface $form, $request = null);
28}
diff --git a/vendor/symfony/form/Symfony/Component/Form/ResolvedFormType.php b/vendor/symfony/form/Symfony/Component/Form/ResolvedFormType.php
new file mode 100644
index 00000000..47d43553
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/ResolvedFormType.php
@@ -0,0 +1,284 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14use Symfony\Component\Form\Exception\InvalidArgumentException;
15use Symfony\Component\Form\Exception\UnexpectedTypeException;
16use Symfony\Component\EventDispatcher\EventDispatcher;
17use Symfony\Component\OptionsResolver\OptionsResolver;
18
19/**
20 * A wrapper for a form type and its extensions.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class ResolvedFormType implements ResolvedFormTypeInterface
25{
26 /**
27 * @var FormTypeInterface
28 */
29 private $innerType;
30
31 /**
32 * @var array
33 */
34 private $typeExtensions;
35
36 /**
37 * @var ResolvedFormTypeInterface
38 */
39 private $parent;
40
41 /**
42 * @var OptionsResolver
43 */
44 private $optionsResolver;
45
46 public function __construct(FormTypeInterface $innerType, array $typeExtensions = array(), ResolvedFormTypeInterface $parent = null)
47 {
48 if (!preg_match('/^[a-z0-9_]*$/i', $innerType->getName())) {
49 throw new InvalidArgumentException(sprintf(
50 'The "%s" form type name ("%s") is not valid. Names must only contain letters, numbers, and "_".',
51 get_class($innerType),
52 $innerType->getName()
53 ));
54 }
55
56 foreach ($typeExtensions as $extension) {
57 if (!$extension instanceof FormTypeExtensionInterface) {
58 throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface');
59 }
60 }
61
62 $this->innerType = $innerType;
63 $this->typeExtensions = $typeExtensions;
64 $this->parent = $parent;
65 }
66
67 /**
68 * {@inheritdoc}
69 */
70 public function getName()
71 {
72 return $this->innerType->getName();
73 }
74
75 /**
76 * {@inheritdoc}
77 */
78 public function getParent()
79 {
80 return $this->parent;
81 }
82
83 /**
84 * {@inheritdoc}
85 */
86 public function getInnerType()
87 {
88 return $this->innerType;
89 }
90
91 /**
92 * {@inheritdoc}
93 */
94 public function getTypeExtensions()
95 {
96 // BC
97 if ($this->innerType instanceof AbstractType) {
98 return $this->innerType->getExtensions();
99 }
100
101 return $this->typeExtensions;
102 }
103
104 /**
105 * {@inheritdoc}
106 */
107 public function createBuilder(FormFactoryInterface $factory, $name, array $options = array())
108 {
109 $options = $this->getOptionsResolver()->resolve($options);
110
111 // Should be decoupled from the specific option at some point
112 $dataClass = isset($options['data_class']) ? $options['data_class'] : null;
113
114 $builder = $this->newBuilder($name, $dataClass, $factory, $options);
115 $builder->setType($this);
116
117 $this->buildForm($builder, $options);
118
119 return $builder;
120 }
121
122 /**
123 * {@inheritdoc}
124 */
125 public function createView(FormInterface $form, FormView $parent = null)
126 {
127 $options = $form->getConfig()->getOptions();
128
129 $view = $this->newView($parent);
130
131 $this->buildView($view, $form, $options);
132
133 foreach ($form as $name => $child) {
134 /* @var FormInterface $child */
135 $view->children[$name] = $child->createView($view);
136 }
137
138 $this->finishView($view, $form, $options);
139
140 return $view;
141 }
142
143 /**
144 * Configures a form builder for the type hierarchy.
145 *
146 * This method is protected in order to allow implementing classes
147 * to change or call it in re-implementations of {@link createBuilder()}.
148 *
149 * @param FormBuilderInterface $builder The builder to configure.
150 * @param array $options The options used for the configuration.
151 */
152 public function buildForm(FormBuilderInterface $builder, array $options)
153 {
154 if (null !== $this->parent) {
155 $this->parent->buildForm($builder, $options);
156 }
157
158 $this->innerType->buildForm($builder, $options);
159
160 foreach ($this->typeExtensions as $extension) {
161 /* @var FormTypeExtensionInterface $extension */
162 $extension->buildForm($builder, $options);
163 }
164 }
165
166 /**
167 * Configures a form view for the type hierarchy.
168 *
169 * This method is protected in order to allow implementing classes
170 * to change or call it in re-implementations of {@link createView()}.
171 *
172 * It is called before the children of the view are built.
173 *
174 * @param FormView $view The form view to configure.
175 * @param FormInterface $form The form corresponding to the view.
176 * @param array $options The options used for the configuration.
177 */
178 public function buildView(FormView $view, FormInterface $form, array $options)
179 {
180 if (null !== $this->parent) {
181 $this->parent->buildView($view, $form, $options);
182 }
183
184 $this->innerType->buildView($view, $form, $options);
185
186 foreach ($this->typeExtensions as $extension) {
187 /* @var FormTypeExtensionInterface $extension */
188 $extension->buildView($view, $form, $options);
189 }
190 }
191
192 /**
193 * Finishes a form view for the type hierarchy.
194 *
195 * This method is protected in order to allow implementing classes
196 * to change or call it in re-implementations of {@link createView()}.
197 *
198 * It is called after the children of the view have been built.
199 *
200 * @param FormView $view The form view to configure.
201 * @param FormInterface $form The form corresponding to the view.
202 * @param array $options The options used for the configuration.
203 */
204 public function finishView(FormView $view, FormInterface $form, array $options)
205 {
206 if (null !== $this->parent) {
207 $this->parent->finishView($view, $form, $options);
208 }
209
210 $this->innerType->finishView($view, $form, $options);
211
212 foreach ($this->typeExtensions as $extension) {
213 /* @var FormTypeExtensionInterface $extension */
214 $extension->finishView($view, $form, $options);
215 }
216 }
217
218 /**
219 * Returns the configured options resolver used for this type.
220 *
221 * This method is protected in order to allow implementing classes
222 * to change or call it in re-implementations of {@link createBuilder()}.
223 *
224 * @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver.
225 */
226 public function getOptionsResolver()
227 {
228 if (null === $this->optionsResolver) {
229 if (null !== $this->parent) {
230 $this->optionsResolver = clone $this->parent->getOptionsResolver();
231 } else {
232 $this->optionsResolver = new OptionsResolver();
233 }
234
235 $this->innerType->setDefaultOptions($this->optionsResolver);
236
237 foreach ($this->typeExtensions as $extension) {
238 /* @var FormTypeExtensionInterface $extension */
239 $extension->setDefaultOptions($this->optionsResolver);
240 }
241 }
242
243 return $this->optionsResolver;
244 }
245
246 /**
247 * Creates a new builder instance.
248 *
249 * Override this method if you want to customize the builder class.
250 *
251 * @param string $name The name of the builder.
252 * @param string $dataClass The data class.
253 * @param FormFactoryInterface $factory The current form factory.
254 * @param array $options The builder options.
255 *
256 * @return FormBuilderInterface The new builder instance.
257 */
258 protected function newBuilder($name, $dataClass, FormFactoryInterface $factory, array $options)
259 {
260 if ($this->innerType instanceof ButtonTypeInterface) {
261 return new ButtonBuilder($name, $options);
262 }
263
264 if ($this->innerType instanceof SubmitButtonTypeInterface) {
265 return new SubmitButtonBuilder($name, $options);
266 }
267
268 return new FormBuilder($name, $dataClass, new EventDispatcher(), $factory, $options);
269 }
270
271 /**
272 * Creates a new view instance.
273 *
274 * Override this method if you want to customize the view class.
275 *
276 * @param FormView|null $parent The parent view, if available.
277 *
278 * @return FormView A new view instance.
279 */
280 protected function newView(FormView $parent = null)
281 {
282 return new FormView($parent);
283 }
284}
diff --git a/vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeFactory.php b/vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeFactory.php
new file mode 100644
index 00000000..d93d1c06
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeFactory.php
@@ -0,0 +1,26 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class ResolvedFormTypeFactory implements ResolvedFormTypeFactoryInterface
18{
19 /**
20 * {@inheritdoc}
21 */
22 public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null)
23 {
24 return new ResolvedFormType($type, $typeExtensions, $parent);
25 }
26}
diff --git a/vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeFactoryInterface.php b/vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeFactoryInterface.php
new file mode 100644
index 00000000..f0ec2330
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeFactoryInterface.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * Creates ResolvedFormTypeInterface instances.
16 *
17 * This interface allows you to use your custom ResolvedFormTypeInterface
18 * implementation, within which you can customize the concrete FormBuilderInterface
19 * implementations or FormView subclasses that are used by the framework.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23interface ResolvedFormTypeFactoryInterface
24{
25 /**
26 * Resolves a form type.
27 *
28 * @param FormTypeInterface $type
29 * @param array $typeExtensions
30 * @param ResolvedFormTypeInterface $parent
31 *
32 * @return ResolvedFormTypeInterface
33 *
34 * @throws Exception\UnexpectedTypeException if the types parent {@link FormTypeInterface::getParent()} is not a string
35 * @throws Exception\InvalidArgumentException if the types parent can not be retrieved from any extension
36 */
37 public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null);
38}
diff --git a/vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeInterface.php b/vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeInterface.php
new file mode 100644
index 00000000..c999bcdc
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/ResolvedFormTypeInterface.php
@@ -0,0 +1,106 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * A wrapper for a form type and its extensions.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface ResolvedFormTypeInterface
20{
21 /**
22 * Returns the name of the type.
23 *
24 * @return string The type name.
25 */
26 public function getName();
27
28 /**
29 * Returns the parent type.
30 *
31 * @return ResolvedFormTypeInterface The parent type or null.
32 */
33 public function getParent();
34
35 /**
36 * Returns the wrapped form type.
37 *
38 * @return FormTypeInterface The wrapped form type.
39 */
40 public function getInnerType();
41
42 /**
43 * Returns the extensions of the wrapped form type.
44 *
45 * @return FormTypeExtensionInterface[] An array of {@link FormTypeExtensionInterface} instances.
46 */
47 public function getTypeExtensions();
48
49 /**
50 * Creates a new form builder for this type.
51 *
52 * @param FormFactoryInterface $factory The form factory.
53 * @param string $name The name for the builder.
54 * @param array $options The builder options.
55 *
56 * @return FormBuilderInterface The created form builder.
57 */
58 public function createBuilder(FormFactoryInterface $factory, $name, array $options = array());
59
60 /**
61 * Creates a new form view for a form of this type.
62 *
63 * @param FormInterface $form The form to create a view for.
64 * @param FormView $parent The parent view or null.
65 *
66 * @return FormView The created form view.
67 */
68 public function createView(FormInterface $form, FormView $parent = null);
69
70 /**
71 * Configures a form builder for the type hierarchy.
72 *
73 * @param FormBuilderInterface $builder The builder to configure.
74 * @param array $options The options used for the configuration.
75 */
76 public function buildForm(FormBuilderInterface $builder, array $options);
77
78 /**
79 * Configures a form view for the type hierarchy.
80 *
81 * It is called before the children of the view are built.
82 *
83 * @param FormView $view The form view to configure.
84 * @param FormInterface $form The form corresponding to the view.
85 * @param array $options The options used for the configuration.
86 */
87 public function buildView(FormView $view, FormInterface $form, array $options);
88
89 /**
90 * Finishes a form view for the type hierarchy.
91 *
92 * It is called after the children of the view have been built.
93 *
94 * @param FormView $view The form view to configure.
95 * @param FormInterface $form The form corresponding to the view.
96 * @param array $options The options used for the configuration.
97 */
98 public function finishView(FormView $view, FormInterface $form, array $options);
99
100 /**
101 * Returns the configured options resolver used for this type.
102 *
103 * @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver.
104 */
105 public function getOptionsResolver();
106}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/config/validation.xml b/vendor/symfony/form/Symfony/Component/Form/Resources/config/validation.xml
new file mode 100644
index 00000000..2f2364bd
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/config/validation.xml
@@ -0,0 +1,13 @@
1<?xml version="1.0" ?>
2
3<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
6
7 <class name="Symfony\Component\Form\Form">
8 <constraint name="Symfony\Component\Form\Extension\Validator\Constraints\Form" />
9 <property name="children">
10 <constraint name="Valid" />
11 </property>
12 </class>
13</constraint-mapping>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ar.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ar.xlf
new file mode 100644
index 00000000..990b039d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ar.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>هذا النموذج يجب الا يحتوى على اى حقول اضاÙية.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>مساحة المل٠المرسل كبيرة. من Ùضلك حاول ارسال مل٠اصغر.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>قيمة رمز الموقع غير صحيحة. من Ùضلك اعد ارسال النموذج.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.bg.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.bg.xlf
new file mode 100644
index 00000000..6f00bde9
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.bg.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Тази форма не Ñ‚Ñ€Ñбва да Ñъдържа допълнителни полета.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>КачениÑÑ‚ файл е твърде голÑм. МолÑ, опитайте да качите по-малък файл.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Ðевалиден CSRF токен. МолÑ, опитайте да изпратите формата отново.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ca.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ca.xlf
new file mode 100644
index 00000000..3a2fa484
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ca.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Aquest formulari no hauria de contenir camps addicionals.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>L'arxiu pujat és massa gran. Per favor, pugi un arxiu més petit.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>El token CSRF no és vàlid. Per favor, provi d'enviar novament el formulari.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.cs.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.cs.xlf
new file mode 100644
index 00000000..776da494
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.cs.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Tato skupina polí nesmí obsahovat další pole.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Nahraný soubor je příliš velký. Nahrajte prosím menší soubor.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF token je neplatný. Zkuste prosím znovu odeslat formulář.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.da.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.da.xlf
new file mode 100644
index 00000000..c2dd4601
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.da.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Feltgruppen må ikke indeholde ekstra felter.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Den oploadede fil var for stor. Opload venligst en mindre fil.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF nøglen er ugyldig.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.de.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.de.xlf
new file mode 100644
index 00000000..c801d677
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.de.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Dieses Formular sollte keine zusätzlichen Felder enthalten.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Die hochgeladene Datei ist zu groß. Versuchen Sie bitte eine kleinere Datei hochzuladen.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Das CSRF-Token ist ungültig. Versuchen Sie bitte das Formular erneut zu senden.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.el.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.el.xlf
new file mode 100644
index 00000000..ba2ced74
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.el.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Αυτή η φόÏμα δεν Ï€Ïέπει να πεÏιέχει επιπλέον πεδία.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Το αÏχείο είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿. ΠαÏακαλοÏμε Ï€Ïοσπαθήστε να ανεβάσετε ένα μικÏότεÏο αÏχείο.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Το CSRF token δεν είναι έγκυÏο. ΠαÏακαλοÏμε δοκιμάστε να υποβάλετε τη φόÏμα ξανά.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.en.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.en.xlf
new file mode 100644
index 00000000..b8542d31
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.en.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>This form should not contain extra fields.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>The uploaded file was too large. Please try to upload a smaller file.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>The CSRF token is invalid. Please try to resubmit the form.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.es.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.es.xlf
new file mode 100644
index 00000000..ebfacfd4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.es.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Este formulario no debería contener campos adicionales.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>El archivo subido es demasiado grande. Por favor, suba un archivo más pequeño.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>El token CSRF no es válido. Por favor, pruebe de enviar nuevamente el formulario</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.et.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.et.xlf
new file mode 100644
index 00000000..1a9867fa
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.et.xlf
@@ -0,0 +1,19 @@
1<?xml version='1.0'?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Väljade grupp ei tohiks sisalda lisaväljasid.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Üleslaaditud fail oli liiga suur. Palun proovi uuesti väiksema failiga.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF-märgis on vigane. Palun proovi vormi uuesti esitada.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.eu.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.eu.xlf
new file mode 100644
index 00000000..a07f786c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.eu.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Formulario honek ez luke aparteko eremurik eduki behar.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Igotako fitxategia handiegia da. Mesedez saiatu fitxategi txikiago bat igotzen.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid.</source>
15 <target>CSFR tokena ez da egokia.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fa.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fa.xlf
new file mode 100644
index 00000000..468d2f6f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fa.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>این Ùرم نباید Ùیلد اضاÙÛŒ داشته باشد.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Ùایل بارگذاری شده بسیار بزرگ است. لطÙا Ùایل کوچکتری را بارگزاری کنید.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>مقدار CSRF نامعتبر است. لطÙا Ùرم را مجددا ارسال Ùرمایید..</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fi.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fi.xlf
new file mode 100644
index 00000000..d223bb05
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fi.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This field group should not contain extra fields.</source>
7 <target>Tämä kenttäryhmä ei voi sisältää ylimääräisiä kenttiä.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Ladattu tiedosto on liian iso. Ole hyvä ja lataa pienempi tiedosto.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF tarkiste on virheellinen. Olen hyvä ja yritä lähettää lomake uudestaan.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fr.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fr.xlf
new file mode 100644
index 00000000..21f90101
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.fr.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Ce formulaire ne doit pas contenir des champs supplémentaires.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Le fichier téléchargé est trop volumineux. Merci d'essayer d'envoyer un fichier plus petit.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Le jeton CSRF est invalide. Veuillez renvoyer le formulaire.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.gl.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.gl.xlf
new file mode 100644
index 00000000..db23fe2b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.gl.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Este formulario non debería conter campos adicionais.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>O arquivo subido é demasiado grande. Por favor, suba un arquivo máis pequeno.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>O token CSRF non é válido. Por favor, probe a enviar novamente o formulario</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.he.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.he.xlf
new file mode 100644
index 00000000..5198738d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.he.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>הטופס ×œ× ×¦×¨×™×š להכיל שדות נוספי×.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>הקובץ שהועלה גדול מדי. נסה להעלות קובץ קטן יותר.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid.</source>
15 <target>×סימון CSRF ×ינו חוקי.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hr.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hr.xlf
new file mode 100644
index 00000000..8d0bd292
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hr.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Ovaj obrazac ne smije sadržavati dodatna polja.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Prenesena datoteka je prevelika. Molim pokušajte prenijeti manju datoteku.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF vrijednost nije ispravna. Pokušajte ponovo poslati obrazac.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hu.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hu.xlf
new file mode 100644
index 00000000..d1491e7e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hu.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Ez a mezőcsoport nem tartalmazhat extra mezőket.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>A feltöltött fájl túl nagy. Kérem próbáljon egy kisebb fájlt feltölteni.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Érvénytelen CSRF token. Kérem próbálja újra elküldeni az űrlapot.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hy.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hy.xlf
new file mode 100644
index 00000000..5a6091f8
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.hy.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Ô±ÕµÕ½ Õ±Ö‡Õ¨ Õ¹ÕºÕ¥Õ¿Ö„ Õ§ ÕºÕ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ« Õ¬Ö€Õ¡ÖÕ¸Ö‚ÖÕ«Õ¹ Õ¿Õ¸Õ²Õ¥Ö€.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>ÕŽÕ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¾Õ¡Õ® Ö†Õ¡ÕµÕ¬Õ¨ Õ¹Õ¡ÖƒÕ¡Õ¦Õ¡Õ¶Ö Õ´Õ¥Õ® Õ§: Ô½Õ¶Õ¤Ö€Õ¾Õ¸Ö‚Õ´ Õ§ Õ¾Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¥Õ¬ Õ¡Õ¾Õ¥Õ¬Õ« ÖƒÕ¸Ö„Ö€ Õ¹Õ¡ÖƒÕ½Õ« Ö†Õ¡ÕµÕ¬.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF Õ¡Ö€ÕªÕ¥Ö„Õ¨ Õ¡Õ¶Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬Õ« Õ§: Õ“Õ¸Ö€Õ±Õ¥Ö„ Õ¶Õ¸Ö€Õ«Ö Õ¸Ö‚Õ²Õ¡Ö€Õ¯Õ¥Õ¬ Õ±Ö‡Õ¨.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.id.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.id.xlf
new file mode 100644
index 00000000..b067d984
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.id.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Gabungan kolom tidak boleh mengandung kolom tambahan.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Berkas yang di unggah terlalu besar. Silahkan coba unggah berkas yang lebih kecil.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF-Token tidak sah. Silahkan coba kirim ulang formulir.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.it.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.it.xlf
new file mode 100644
index 00000000..aa15264d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.it.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Questo form non dovrebbe contenere nessun campo extra.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Il file caricato è troppo grande. Per favore caricare un file più piccolo.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Il token CSRF non è valido. Provare a reinviare il form.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ja.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ja.xlf
new file mode 100644
index 00000000..4559af17
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ja.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>フィールドグループã«è¿½åŠ ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’å«ã‚“ã§ã¯ãªã‚Šã¾ã›ã‚“.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>アップロードã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ãŒå¤§ãã™ãŽã¾ã™ã€‚å°ã•ãªãƒ•ã‚¡ã‚¤ãƒ«ã§å†åº¦ã‚¢ãƒƒãƒ—ロードã—ã¦ãã ã•ã„.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid.</source>
15 <target>CSRFトークンãŒç„¡åŠ¹ã§ã™.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lb.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lb.xlf
new file mode 100644
index 00000000..a111ffe3
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lb.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Dës Feldergrupp sollt keng zousätzlech Felder enthalen.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>De geschécktene Fichier ass ze grouss. Versicht wann ech gelift ee méi klenge Fichier eropzelueden.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Den CSRF-Token ass ongëlteg. Versicht wann ech gelift de Formulaire nach eng Kéier ze schécken.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lt.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lt.xlf
new file mode 100644
index 00000000..25f30887
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lt.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Forma negali turėti papildomų laukų.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Įkelta byla yra per didelė. bandykite įkelti mažesnę.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF kodas nepriimtinas. Bandykite siųsti formos užklausą dar kartą.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lv.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lv.xlf
new file mode 100644
index 00000000..9cdfb2cd
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.lv.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Å ajÄ veidlapÄ nevajadzÄ“tu bÅ«t papildus ievades laukiem.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>AugÅ¡upielÄdÄ“tÄ faila izmÄ“rs bija par lielu. LÅ«dzu mÄ“Ä£iniet augÅ¡upielÄdÄ“t mazÄka izmÄ“ra failu.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Dotais CSRF talons nav derīgs. Lūdzu mēģiniet vēlreiz iesniegt veidlapu.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.mn.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.mn.xlf
new file mode 100644
index 00000000..002b01c1
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.mn.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Форм нÑмÑлт талбар багтаах боломжгүй.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Upload хийÑÑн файл Ñ…ÑÑ‚Ñрхий том байна. Бага Ñ…ÑмжÑÑÑ‚Ñй файл оруулна уу.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF token буруу байна. Формоо дахин илгÑÑÐ½Ñ Ò¯Ò¯.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.nb.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.nb.xlf
new file mode 100644
index 00000000..5e36bd5f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.nb.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Feltgruppen må ikke inneholde ekstra felter.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Den opplastede file var for stor. Vennligst last opp en mindre fil.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid.</source>
15 <target>CSRF nøkkelen er ugyldig.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.nl.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.nl.xlf
new file mode 100644
index 00000000..3d737d79
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.nl.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Dit formulier mag geen extra velden bevatten.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Het geüploade bestand is te groot. Probeer een kleiner bestand te uploaden.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>De CSRF-token is ongeldig. Probeer het formulier opnieuw te versturen.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pl.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pl.xlf
new file mode 100644
index 00000000..64def2a6
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pl.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Ten formularz nie powinien zawierać dodatkowych pól.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Wgrany plik był za duży. Proszę spróbować wgrać mniejszy plik.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Token CSRF jest nieprawidłowy. Proszę spróbować wysłać formularz ponownie.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pt.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pt.xlf
new file mode 100644
index 00000000..554a810c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pt.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Este formulário não deveria conter campos extra.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>O arquivo enviado é muito grande. Por favor, tente enviar um ficheiro mais pequeno.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>O token CSRF é inválido. Por favor submeta o formulário novamente.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf
new file mode 100644
index 00000000..9ae4d719
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Este formulário não deve conter campos adicionais.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>O arquivo enviado é muito grande. Por favor, tente enviar um arquivo menor.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>O token CSRF é inválido. Por favor, tente reenviar o formulário.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ro.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ro.xlf
new file mode 100644
index 00000000..25abab3b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ro.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Aceast formular nu ar trebui să conțină câmpuri suplimentare.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Fișierul încărcat a fost prea mare. Vă rugăm sa încărcați un fișier mai mic.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>Token-ul CSRF este invalid. Vă rugăm să trimiteți formularul incă o dată.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ru.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ru.xlf
new file mode 100644
index 00000000..8d829f1b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ru.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Эта форма не должна Ñодержать дополнительных полей.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Загруженный файл Ñлишком большой. ПожалуйÑта, попробуйте загрузить файл меньшего размера.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF значение недопуÑтимо. ПожалуйÑта, попробуйте повторить отправку формы.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sk.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sk.xlf
new file mode 100644
index 00000000..638d0cc4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sk.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Polia by nemali obsahovaÅ¥ ÄalÅ¡ie prvky.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Odoslaný súbor je príliš veľký. Prosím odošlite súbor s menšou veľkosťou.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF token je neplatný. Prosím skúste znovu odoslať formulár.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sl.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sl.xlf
new file mode 100644
index 00000000..103124d0
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sl.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>To podroÄje ne sme vsebovati dodatnih polj.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Naložena datoteka je prevelika. Prosim, poizkusite naložiti manjšo.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF vrednost je napaÄna. Prosimo, ponovno poÅ¡ljite obrazec.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf
new file mode 100644
index 00000000..ff7f550a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Овај формулар не треба да Ñадржи додатна поља.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Отпремљена датотека је била превелика. Молим покушајте отпремање мање датотеке.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF вредноÑÑ‚ је невалидна. Покушајте поново.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf
new file mode 100644
index 00000000..6c4be358
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Ovaj formular ne treba da sadrži dodatna polja.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Otpremljena datoteka je bila prevelika. Molim pokušajte otpremanje manje datoteke.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF vrednost je nevalidna. Pokušajte ponovo.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff> \ No newline at end of file
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sv.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sv.xlf
new file mode 100644
index 00000000..4e2518b1
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.sv.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Formuläret kan inte innehålla extra fält.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Den uppladdade filen var för stor. Försök ladda upp en mindre fil.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid.</source>
15 <target>CSRF-symbolen är inte giltig.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ua.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ua.xlf
new file mode 100644
index 00000000..4c739fac
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.ua.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>Ð¦Ñ Ñ„Ð¾Ñ€Ð¼Ð° не повинна міÑтити додаткових полів.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>Завантажений файл занадто великий. Будь-лаÑка, Ñпробуйте завантажити файл меншого розміру.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½ÐµÐ´Ð¾Ð¿ÑƒÑтиме. Будь-лаÑка, Ñпробуйте відправити форму знову.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf
new file mode 100644
index 00000000..8bdf7fb5
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="28">
6 <source>This form should not contain extra fields.</source>
7 <target>该表å•ä¸­ä¸å¯æœ‰é¢å¤–字段.</target>
8 </trans-unit>
9 <trans-unit id="29">
10 <source>The uploaded file was too large. Please try to upload a smaller file.</source>
11 <target>上传文件太大, 请é‡æ–°å°è¯•ä¸Šä¼ ä¸€ä¸ªè¾ƒå°çš„文件.</target>
12 </trans-unit>
13 <trans-unit id="30">
14 <source>The CSRF token is invalid. Please try to resubmit the form.</source>
15 <target>CSRF 验è¯ç¬¦æ— æ•ˆï¼Œ 请é‡æ–°æ交.</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/form/Symfony/Component/Form/ReversedTransformer.php b/vendor/symfony/form/Symfony/Component/Form/ReversedTransformer.php
new file mode 100644
index 00000000..7069705f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/ReversedTransformer.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * Reverses a transformer
16 *
17 * When the transform() method is called, the reversed transformer's
18 * reverseTransform() method is called and vice versa.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class ReversedTransformer implements DataTransformerInterface
23{
24 /**
25 * The reversed transformer
26 * @var DataTransformerInterface
27 */
28 protected $reversedTransformer;
29
30 /**
31 * Reverses this transformer
32 *
33 * @param DataTransformerInterface $reversedTransformer
34 */
35 public function __construct(DataTransformerInterface $reversedTransformer)
36 {
37 $this->reversedTransformer = $reversedTransformer;
38 }
39
40 /**
41 * {@inheritDoc}
42 */
43 public function transform($value)
44 {
45 return $this->reversedTransformer->reverseTransform($value);
46 }
47
48 /**
49 * {@inheritDoc}
50 */
51 public function reverseTransform($value)
52 {
53 return $this->reversedTransformer->transform($value);
54 }
55}
diff --git a/vendor/symfony/form/Symfony/Component/Form/SubmitButton.php b/vendor/symfony/form/Symfony/Component/Form/SubmitButton.php
new file mode 100644
index 00000000..47d4be0e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/SubmitButton.php
@@ -0,0 +1,52 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * A button that submits the form.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class SubmitButton extends Button implements ClickableInterface
20{
21 /**
22 * @var Boolean
23 */
24 private $clicked = false;
25
26 /**
27 * {@inheritdoc}
28 */
29 public function isClicked()
30 {
31 return $this->clicked;
32 }
33
34 /**
35 * Submits data to the button.
36 *
37 * @param null|string $submittedData The data.
38 * @param Boolean $clearMissing Not used.
39 *
40 * @return SubmitButton The button instance
41 *
42 * @throws Exception\AlreadySubmittedException If the form has already been submitted.
43 */
44 public function submit($submittedData, $clearMissing = true)
45 {
46 parent::submit($submittedData, $clearMissing);
47
48 $this->clicked = null !== $submittedData;
49
50 return $this;
51 }
52}
diff --git a/vendor/symfony/form/Symfony/Component/Form/SubmitButtonBuilder.php b/vendor/symfony/form/Symfony/Component/Form/SubmitButtonBuilder.php
new file mode 100644
index 00000000..088fb748
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/SubmitButtonBuilder.php
@@ -0,0 +1,30 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * A builder for {@link SubmitButton} instances.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class SubmitButtonBuilder extends ButtonBuilder
20{
21 /**
22 * Creates the button.
23 *
24 * @return Button The button
25 */
26 public function getForm()
27 {
28 return new SubmitButton($this->getFormConfig());
29 }
30}
diff --git a/vendor/symfony/form/Symfony/Component/Form/SubmitButtonTypeInterface.php b/vendor/symfony/form/Symfony/Component/Form/SubmitButtonTypeInterface.php
new file mode 100644
index 00000000..f7ac13f7
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/SubmitButtonTypeInterface.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form;
13
14/**
15 * A type that should be converted into a {@link SubmitButton} instance.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface SubmitButtonTypeInterface extends FormTypeInterface
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Test/DeprecationErrorHandler.php b/vendor/symfony/form/Symfony/Component/Form/Test/DeprecationErrorHandler.php
new file mode 100644
index 00000000..36417f74
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Test/DeprecationErrorHandler.php
@@ -0,0 +1,42 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Test;
13
14use Symfony\Component\Form\FormEvent;
15
16class DeprecationErrorHandler
17{
18 public static function handle($errorNumber, $message, $file, $line, $context)
19 {
20 if ($errorNumber & E_USER_DEPRECATED) {
21 return true;
22 }
23
24 return \PHPUnit_Util_ErrorHandler::handleError($errorNumber, $message, $file, $line);
25 }
26
27 public static function handleBC($errorNumber, $message, $file, $line, $context)
28 {
29 if ($errorNumber & E_USER_DEPRECATED) {
30 return true;
31 }
32
33 return false;
34 }
35
36 public static function preBind($listener, FormEvent $event)
37 {
38 set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handle'));
39 $listener->preBind($event);
40 restore_error_handler();
41 }
42}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Test/FormBuilderInterface.php b/vendor/symfony/form/Symfony/Component/Form/Test/FormBuilderInterface.php
new file mode 100644
index 00000000..711cecd0
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Test/FormBuilderInterface.php
@@ -0,0 +1,16 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Test;
13
14interface FormBuilderInterface extends \Iterator, \Symfony\Component\Form\FormBuilderInterface
15{
16}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Test/FormIntegrationTestCase.php b/vendor/symfony/form/Symfony/Component/Form/Test/FormIntegrationTestCase.php
new file mode 100644
index 00000000..68e5f244
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Test/FormIntegrationTestCase.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Test;
13
14use Symfony\Component\Form\Forms;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19abstract class FormIntegrationTestCase extends \PHPUnit_Framework_TestCase
20{
21 /**
22 * @var \Symfony\Component\Form\FormFactoryInterface
23 */
24 protected $factory;
25
26 protected function setUp()
27 {
28 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
29 $this->markTestSkipped('The "EventDispatcher" component is not available');
30 }
31
32 $this->factory = Forms::createFormFactoryBuilder()
33 ->addExtensions($this->getExtensions())
34 ->getFormFactory();
35 }
36
37 protected function getExtensions()
38 {
39 return array();
40 }
41}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Test/FormInterface.php b/vendor/symfony/form/Symfony/Component/Form/Test/FormInterface.php
new file mode 100644
index 00000000..22a83fd7
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Test/FormInterface.php
@@ -0,0 +1,16 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Test;
13
14interface FormInterface extends \Iterator, \Symfony\Component\Form\FormInterface
15{
16}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Test/FormPerformanceTestCase.php b/vendor/symfony/form/Symfony/Component/Form/Test/FormPerformanceTestCase.php
new file mode 100644
index 00000000..573f4e91
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Test/FormPerformanceTestCase.php
@@ -0,0 +1,70 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Test;
13
14/**
15 * Base class for performance tests.
16 *
17 * Copied from Doctrine 2's OrmPerformanceTestCase.
18 *
19 * @author robo
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22abstract class FormPerformanceTestCase extends FormIntegrationTestCase
23{
24 /**
25 * @var integer
26 */
27 protected $maxRunningTime = 0;
28
29 /**
30 */
31 protected function runTest()
32 {
33 $s = microtime(true);
34 parent::runTest();
35 $time = microtime(true) - $s;
36
37 if ($this->maxRunningTime != 0 && $time > $this->maxRunningTime) {
38 $this->fail(
39 sprintf(
40 'expected running time: <= %s but was: %s',
41
42 $this->maxRunningTime,
43 $time
44 )
45 );
46 }
47 }
48
49 /**
50 * @param integer $maxRunningTime
51 * @throws \InvalidArgumentException
52 */
53 public function setMaxRunningTime($maxRunningTime)
54 {
55 if (is_integer($maxRunningTime) && $maxRunningTime >= 0) {
56 $this->maxRunningTime = $maxRunningTime;
57 } else {
58 throw new \InvalidArgumentException;
59 }
60 }
61
62 /**
63 * @return integer
64 * @since Method available since Release 2.3.0
65 */
66 public function getMaxRunningTime()
67 {
68 return $this->maxRunningTime;
69 }
70}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Test/TypeTestCase.php b/vendor/symfony/form/Symfony/Component/Form/Test/TypeTestCase.php
new file mode 100644
index 00000000..9d51a9ee
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Test/TypeTestCase.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Test;
13
14use Symfony\Component\Form\FormBuilder;
15use Symfony\Component\EventDispatcher\EventDispatcher;
16
17abstract class TypeTestCase extends FormIntegrationTestCase
18{
19 /**
20 * @var FormBuilder
21 */
22 protected $builder;
23
24 /**
25 * @var EventDispatcher
26 */
27 protected $dispatcher;
28
29 protected function setUp()
30 {
31 parent::setUp();
32
33 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
34 $this->builder = new FormBuilder(null, null, $this->dispatcher, $this->factory);
35 }
36
37 public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual)
38 {
39 self::assertEquals($expected->format('c'), $actual->format('c'));
40 }
41}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php
new file mode 100644
index 00000000..ee9ed8f2
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php
@@ -0,0 +1,732 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\FormError;
15use Symfony\Component\Form\Tests\Fixtures\AlternatingRowType;
16
17abstract class AbstractDivLayoutTest extends AbstractLayoutTest
18{
19 public function testRow()
20 {
21 $form = $this->factory->createNamed('name', 'text');
22 $form->addError(new FormError('[trans]Error![/trans]'));
23 $view = $form->createView();
24 $html = $this->renderRow($view);
25
26 $this->assertMatchesXpath($html,
27'/div
28 [
29 ./label[@for="name"]
30 /following-sibling::ul
31 [./li[.="[trans]Error![/trans]"]]
32 [count(./li)=1]
33 /following-sibling::input[@id="name"]
34 ]
35'
36 );
37 }
38
39 public function testRowOverrideVariables()
40 {
41 $view = $this->factory->createNamed('name', 'text')->createView();
42 $html = $this->renderRow($view, array(
43 'attr' => array('class' => 'my&class'),
44 'label' => 'foo&bar',
45 'label_attr' => array('class' => 'my&label&class'),
46 ));
47
48 $this->assertMatchesXpath($html,
49'/div
50 [
51 ./label[@for="name"][@class="my&label&class required"][.="[trans]foo&bar[/trans]"]
52 /following-sibling::input[@id="name"][@class="my&class"]
53 ]
54'
55 );
56 }
57
58 public function testRepeatedRow()
59 {
60 $form = $this->factory->createNamed('name', 'repeated');
61 $form->addError(new FormError('[trans]Error![/trans]'));
62 $view = $form->createView();
63 $html = $this->renderRow($view);
64
65 // The errors of the form are not rendered by intention!
66 // In practice, repeated fields cannot have errors as all errors
67 // on them are mapped to the first child.
68 // (see RepeatedTypeValidatorExtension)
69
70 $this->assertMatchesXpath($html,
71'/div
72 [
73 ./label[@for="name_first"]
74 /following-sibling::input[@id="name_first"]
75 ]
76/following-sibling::div
77 [
78 ./label[@for="name_second"]
79 /following-sibling::input[@id="name_second"]
80 ]
81'
82 );
83 }
84
85 public function testButtonRow()
86 {
87 $form = $this->factory->createNamed('name', 'button');
88 $view = $form->createView();
89 $html = $this->renderRow($view);
90
91 $this->assertMatchesXpath($html,
92'/div
93 [
94 ./button[@type="button"][@name="name"]
95 ]
96 [count(//label)=0]
97'
98 );
99 }
100
101 public function testRest()
102 {
103 $view = $this->factory->createNamedBuilder('name', 'form')
104 ->add('field1', 'text')
105 ->add('field2', 'repeated')
106 ->add('field3', 'text')
107 ->add('field4', 'text')
108 ->getForm()
109 ->createView();
110
111 // Render field2 row -> does not implicitly call renderWidget because
112 // it is a repeated field!
113 $this->renderRow($view['field2']);
114
115 // Render field3 widget
116 $this->renderWidget($view['field3']);
117
118 // Rest should only contain field1 and field4
119 $html = $this->renderRest($view);
120
121 $this->assertMatchesXpath($html,
122'/div
123 [
124 ./label[@for="name_field1"]
125 /following-sibling::input[@type="text"][@id="name_field1"]
126 ]
127/following-sibling::div
128 [
129 ./label[@for="name_field4"]
130 /following-sibling::input[@type="text"][@id="name_field4"]
131 ]
132 [count(../div)=2]
133 [count(..//label)=2]
134 [count(..//input)=3]
135/following-sibling::input
136 [@type="hidden"]
137 [@id="name__token"]
138'
139 );
140 }
141
142 public function testRestWithChildrenForms()
143 {
144 $child1 = $this->factory->createNamedBuilder('child1', 'form')
145 ->add('field1', 'text')
146 ->add('field2', 'text');
147
148 $child2 = $this->factory->createNamedBuilder('child2', 'form')
149 ->add('field1', 'text')
150 ->add('field2', 'text');
151
152 $view = $this->factory->createNamedBuilder('parent', 'form')
153 ->add($child1)
154 ->add($child2)
155 ->getForm()
156 ->createView();
157
158 // Render child1.field1 row
159 $this->renderRow($view['child1']['field1']);
160
161 // Render child2.field2 widget (remember that widget don't render label)
162 $this->renderWidget($view['child2']['field2']);
163
164 // Rest should only contain child1.field2 and child2.field1
165 $html = $this->renderRest($view);
166
167 $this->assertMatchesXpath($html,
168'/div
169 [
170 ./label[not(@for)]
171 /following-sibling::div[@id="parent_child1"]
172 [
173 ./div
174 [
175 ./label[@for="parent_child1_field2"]
176 /following-sibling::input[@id="parent_child1_field2"]
177 ]
178 ]
179 ]
180
181/following-sibling::div
182 [
183 ./label[not(@for)]
184 /following-sibling::div[@id="parent_child2"]
185 [
186 ./div
187 [
188 ./label[@for="parent_child2_field1"]
189 /following-sibling::input[@id="parent_child2_field1"]
190 ]
191 ]
192 ]
193 [count(//label)=4]
194 [count(//input[@type="text"])=2]
195/following-sibling::input[@type="hidden"][@id="parent__token"]
196'
197 );
198 }
199
200 public function testRestAndRepeatedWithRow()
201 {
202 $view = $this->factory->createNamedBuilder('name', 'form')
203 ->add('first', 'text')
204 ->add('password', 'repeated')
205 ->getForm()
206 ->createView();
207
208 $this->renderRow($view['password']);
209
210 $html = $this->renderRest($view);
211
212 $this->assertMatchesXpath($html,
213'/div
214 [
215 ./label[@for="name_first"]
216 /following-sibling::input[@type="text"][@id="name_first"]
217 ]
218 [count(.//input)=1]
219/following-sibling::input
220 [@type="hidden"]
221 [@id="name__token"]
222'
223 );
224 }
225
226 public function testRestAndRepeatedWithRowPerChild()
227 {
228 $view = $this->factory->createNamedBuilder('name', 'form')
229 ->add('first', 'text')
230 ->add('password', 'repeated')
231 ->getForm()
232 ->createView();
233
234 $this->renderRow($view['password']['first']);
235 $this->renderRow($view['password']['second']);
236
237 $html = $this->renderRest($view);
238
239 $this->assertMatchesXpath($html,
240'/div
241 [
242 ./label[@for="name_first"]
243 /following-sibling::input[@type="text"][@id="name_first"]
244 ]
245 [count(.//input)=1]
246 [count(.//label)=1]
247/following-sibling::input
248 [@type="hidden"]
249 [@id="name__token"]
250'
251 );
252 }
253
254 public function testRestAndRepeatedWithWidgetPerChild()
255 {
256 $view = $this->factory->createNamedBuilder('name', 'form')
257 ->add('first', 'text')
258 ->add('password', 'repeated')
259 ->getForm()
260 ->createView();
261
262 // The password form is considered as rendered as all its children
263 // are rendered
264 $this->renderWidget($view['password']['first']);
265 $this->renderWidget($view['password']['second']);
266
267 $html = $this->renderRest($view);
268
269 $this->assertMatchesXpath($html,
270'/div
271 [
272 ./label[@for="name_first"]
273 /following-sibling::input[@type="text"][@id="name_first"]
274 ]
275 [count(//input)=2]
276 [count(//label)=1]
277/following-sibling::input
278 [@type="hidden"]
279 [@id="name__token"]
280'
281 );
282 }
283
284 public function testCollection()
285 {
286 $form = $this->factory->createNamed('name', 'collection', array('a', 'b'), array(
287 'type' => 'text',
288 ));
289
290 $this->assertWidgetMatchesXpath($form->createView(), array(),
291'/div
292 [
293 ./div[./input[@type="text"][@value="a"]]
294 /following-sibling::div[./input[@type="text"][@value="b"]]
295 ]
296 [count(./div[./input])=2]
297'
298 );
299 }
300
301 // https://github.com/symfony/symfony/issues/5038
302 public function testCollectionWithAlternatingRowTypes()
303 {
304 $data = array(
305 array('title' => 'a'),
306 array('title' => 'b'),
307 );
308 $form = $this->factory->createNamed('name', 'collection', $data, array(
309 'type' => new AlternatingRowType(),
310 ));
311
312 $this->assertWidgetMatchesXpath($form->createView(), array(),
313'/div
314 [
315 ./div[./div/div/input[@type="text"][@value="a"]]
316 /following-sibling::div[./div/div/textarea[.="b"]]
317 ]
318 [count(./div[./div/div/input])=1]
319 [count(./div[./div/div/textarea])=1]
320'
321 );
322 }
323
324 public function testEmptyCollection()
325 {
326 $form = $this->factory->createNamed('name', 'collection', array(), array(
327 'type' => 'text',
328 ));
329
330 $this->assertWidgetMatchesXpath($form->createView(), array(),
331'/div
332 [./input[@type="hidden"][@id="name__token"]]
333 [count(./div)=0]
334'
335 );
336 }
337
338 public function testCollectionRow()
339 {
340 $collection = $this->factory->createNamedBuilder(
341 'collection',
342 'collection',
343 array('a', 'b'),
344 array('type' => 'text')
345 );
346
347 $form = $this->factory->createNamedBuilder('form', 'form')
348 ->add($collection)
349 ->getForm();
350
351 $this->assertWidgetMatchesXpath($form->createView(), array(),
352'/div
353 [
354 ./div
355 [
356 ./label[not(@for)]
357 /following-sibling::div
358 [
359 ./div
360 [
361 ./label[@for="form_collection_0"]
362 /following-sibling::input[@type="text"][@value="a"]
363 ]
364 /following-sibling::div
365 [
366 ./label[@for="form_collection_1"]
367 /following-sibling::input[@type="text"][@value="b"]
368 ]
369 ]
370 ]
371 /following-sibling::input[@type="hidden"][@id="form__token"]
372 ]
373 [count(.//input)=3]
374'
375 );
376 }
377
378 public function testForm()
379 {
380 $form = $this->factory->createNamedBuilder('name', 'form')
381 ->setMethod('PUT')
382 ->setAction('http://example.com')
383 ->add('firstName', 'text')
384 ->add('lastName', 'text')
385 ->getForm();
386
387 // include ampersands everywhere to validate escaping
388 $html = $this->renderForm($form->createView(), array(
389 'id' => 'my&id',
390 'attr' => array('class' => 'my&class'),
391 ));
392
393 $this->assertMatchesXpath($html,
394'/form
395 [
396 ./input[@type="hidden"][@name="_method"][@value="PUT"]
397 /following-sibling::div
398 [
399 ./div
400 [
401 ./label[@for="name_firstName"]
402 /following-sibling::input[@type="text"][@id="name_firstName"]
403 ]
404 /following-sibling::div
405 [
406 ./label[@for="name_lastName"]
407 /following-sibling::input[@type="text"][@id="name_lastName"]
408 ]
409 /following-sibling::input[@type="hidden"][@id="name__token"]
410 ]
411 [count(.//input)=3]
412 [@id="my&id"]
413 [@class="my&class"]
414 ]
415 [@method="post"]
416 [@action="http://example.com"]
417 [@class="my&class"]
418'
419 );
420 }
421
422 public function testFormWidget()
423 {
424 $form = $this->factory->createNamedBuilder('name', 'form')
425 ->add('firstName', 'text')
426 ->add('lastName', 'text')
427 ->getForm();
428
429 $this->assertWidgetMatchesXpath($form->createView(), array(),
430'/div
431 [
432 ./div
433 [
434 ./label[@for="name_firstName"]
435 /following-sibling::input[@type="text"][@id="name_firstName"]
436 ]
437 /following-sibling::div
438 [
439 ./label[@for="name_lastName"]
440 /following-sibling::input[@type="text"][@id="name_lastName"]
441 ]
442 /following-sibling::input[@type="hidden"][@id="name__token"]
443 ]
444 [count(.//input)=3]
445'
446 );
447 }
448
449 // https://github.com/symfony/symfony/issues/2308
450 public function testNestedFormError()
451 {
452 $form = $this->factory->createNamedBuilder('name', 'form')
453 ->add($this->factory
454 ->createNamedBuilder('child', 'form', null, array('error_bubbling' => false))
455 ->add('grandChild', 'form')
456 )
457 ->getForm();
458
459 $form->get('child')->addError(new FormError('[trans]Error![/trans]'));
460
461 $this->assertWidgetMatchesXpath($form->createView(), array(),
462'/div
463 [
464 ./div/label
465 /following-sibling::ul[./li[.="[trans]Error![/trans]"]]
466 ]
467 [count(.//li[.="[trans]Error![/trans]"])=1]
468'
469 );
470 }
471
472 public function testCsrf()
473 {
474 $this->csrfProvider->expects($this->any())
475 ->method('generateCsrfToken')
476 ->will($this->returnValue('foo&bar'));
477
478 $form = $this->factory->createNamedBuilder('name', 'form')
479 ->add($this->factory
480 // No CSRF protection on nested forms
481 ->createNamedBuilder('child', 'form')
482 ->add($this->factory->createNamedBuilder('grandchild', 'text'))
483 )
484 ->getForm();
485
486 $this->assertWidgetMatchesXpath($form->createView(), array(),
487'/div
488 [
489 ./div
490 /following-sibling::input[@type="hidden"][@id="name__token"][@value="foo&bar"]
491 ]
492 [count(.//input[@type="hidden"])=1]
493'
494 );
495 }
496
497 public function testRepeated()
498 {
499 $form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
500 'type' => 'text',
501 ));
502
503 $this->assertWidgetMatchesXpath($form->createView(), array(),
504'/div
505 [
506 ./div
507 [
508 ./label[@for="name_first"]
509 /following-sibling::input[@type="text"][@id="name_first"]
510 ]
511 /following-sibling::div
512 [
513 ./label[@for="name_second"]
514 /following-sibling::input[@type="text"][@id="name_second"]
515 ]
516 /following-sibling::input[@type="hidden"][@id="name__token"]
517 ]
518 [count(.//input)=3]
519'
520 );
521 }
522
523 public function testRepeatedWithCustomOptions()
524 {
525 $form = $this->factory->createNamed('name', 'repeated', null, array(
526 // the global required value cannot be overridden
527 'first_options' => array('label' => 'Test', 'required' => false),
528 'second_options' => array('label' => 'Test2')
529 ));
530
531 $this->assertWidgetMatchesXpath($form->createView(), array(),
532'/div
533 [
534 ./div
535 [
536 ./label[@for="name_first"][.="[trans]Test[/trans]"]
537 /following-sibling::input[@type="text"][@id="name_first"][@required="required"]
538 ]
539 /following-sibling::div
540 [
541 ./label[@for="name_second"][.="[trans]Test2[/trans]"]
542 /following-sibling::input[@type="text"][@id="name_second"][@required="required"]
543 ]
544 /following-sibling::input[@type="hidden"][@id="name__token"]
545 ]
546 [count(.//input)=3]
547'
548 );
549 }
550
551 public function testSearchInputName()
552 {
553 $form = $this->factory->createNamedBuilder('full', 'form')
554 ->add('name', 'search')
555 ->getForm();
556
557 $this->assertWidgetMatchesXpath($form->createView(), array(),
558'/div
559 [
560 ./div
561 [
562 ./label[@for="full_name"]
563 /following-sibling::input[@type="search"][@id="full_name"][@name="full[name]"]
564 ]
565 /following-sibling::input[@type="hidden"][@id="full__token"]
566 ]
567 [count(//input)=2]
568'
569 );
570 }
571
572 public function testLabelHasNoId()
573 {
574 $form = $this->factory->createNamed('name', 'text');
575 $html = $this->renderRow($form->createView());
576
577 $this->assertMatchesXpath($html,
578'/div
579 [
580 ./label[@for="name"][not(@id)]
581 /following-sibling::input[@id="name"]
582 ]
583'
584 );
585 }
586
587 public function testLabelIsNotRenderedWhenSetToFalse()
588 {
589 $form = $this->factory->createNamed('name', 'text', null, array(
590 'label' => false
591 ));
592 $html = $this->renderRow($form->createView());
593
594 $this->assertMatchesXpath($html,
595'/div
596 [
597 ./input[@id="name"]
598 ]
599 [count(//label)=0]
600'
601 );
602 }
603
604 /**
605 * @dataProvider themeBlockInheritanceProvider
606 */
607 public function testThemeBlockInheritance($theme)
608 {
609 $view = $this->factory
610 ->createNamed('name', 'email')
611 ->createView()
612 ;
613
614 $this->setTheme($view, $theme);
615
616 $this->assertMatchesXpath(
617 $this->renderWidget($view),
618 '/input[@type="email"][@rel="theme"]'
619 );
620 }
621
622 /**
623 * @dataProvider themeInheritanceProvider
624 */
625 public function testThemeInheritance($parentTheme, $childTheme)
626 {
627 $child = $this->factory->createNamedBuilder('child', 'form')
628 ->add('field', 'text');
629
630 $view = $this->factory->createNamedBuilder('parent', 'form')
631 ->add('field', 'text')
632 ->add($child)
633 ->getForm()
634 ->createView()
635 ;
636
637 $this->setTheme($view, $parentTheme);
638 $this->setTheme($view['child'], $childTheme);
639
640 $this->assertWidgetMatchesXpath($view, array(),
641'/div
642 [
643 ./div
644 [
645 ./label[.="parent"]
646 /following-sibling::input[@type="text"]
647 ]
648 /following-sibling::div
649 [
650 ./label[.="child"]
651 /following-sibling::div
652 [
653 ./div
654 [
655 ./label[.="child"]
656 /following-sibling::input[@type="text"]
657 ]
658 ]
659 ]
660 /following-sibling::input[@type="hidden"]
661 ]
662'
663 );
664 }
665
666 /**
667 * The block "_name_child_label" should be overridden in the theme of the
668 * implemented driver.
669 */
670 public function testCollectionRowWithCustomBlock()
671 {
672 $collection = array('one', 'two', 'three');
673 $form = $this->factory->createNamedBuilder('name', 'collection', $collection)
674 ->getForm();
675
676 $this->assertWidgetMatchesXpath($form->createView(), array(),
677'/div
678 [
679 ./div[./label[.="Custom label: [trans]0[/trans]"]]
680 /following-sibling::div[./label[.="Custom label: [trans]1[/trans]"]]
681 /following-sibling::div[./label[.="Custom label: [trans]2[/trans]"]]
682 ]
683'
684 );
685 }
686
687 public function testFormEndWithRest()
688 {
689 $view = $this->factory->createNamedBuilder('name', 'form')
690 ->add('field1', 'text')
691 ->add('field2', 'text')
692 ->getForm()
693 ->createView();
694
695 $this->renderWidget($view['field1']);
696
697 // Rest should only contain field2
698 $html = $this->renderEnd($view);
699
700 // Insert the start tag, the end tag should be rendered by the helper
701 $this->assertMatchesXpath('<form>' . $html,
702'/form
703 [
704 ./div
705 [
706 ./label[@for="name_field2"]
707 /following-sibling::input[@type="text"][@id="name_field2"]
708 ]
709 /following-sibling::input
710 [@type="hidden"]
711 [@id="name__token"]
712 ]
713'
714 );
715 }
716
717 public function testFormEndWithoutRest()
718 {
719 $view = $this->factory->createNamedBuilder('name', 'form')
720 ->add('field1', 'text')
721 ->add('field2', 'text')
722 ->getForm()
723 ->createView();
724
725 $this->renderWidget($view['field1']);
726
727 // Rest should only contain field2, but isn't rendered
728 $html = $this->renderEnd($view, array('render_rest' => false));
729
730 $this->assertEquals('</form>', $html);
731 }
732}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractExtensionTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractExtensionTest.php
new file mode 100644
index 00000000..c16cb221
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractExtensionTest.php
@@ -0,0 +1,43 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\AbstractExtension;
15use Symfony\Component\Form\Tests\Fixtures\FooType;
16
17class AbstractExtensionTest extends \PHPUnit_Framework_TestCase
18{
19 public function testHasType()
20 {
21 $loader = new ConcreteExtension();
22 $this->assertTrue($loader->hasType('foo'));
23 $this->assertFalse($loader->hasType('bar'));
24 }
25
26 public function testGetType()
27 {
28 $loader = new ConcreteExtension();
29 $this->assertInstanceOf('Symfony\Component\Form\Tests\Fixtures\FooType', $loader->getType('foo'));
30 }
31}
32
33class ConcreteExtension extends AbstractExtension
34{
35 protected function loadTypes()
36 {
37 return array(new FooType());
38 }
39
40 protected function loadTypeGuesser()
41 {
42 }
43}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractFormTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractFormTest.php
new file mode 100644
index 00000000..29118187
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractFormTest.php
@@ -0,0 +1,147 @@
1<?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\FormBuilder;
15use Symfony\Component\EventDispatcher\EventDispatcher;
16use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17
18abstract class AbstractFormTest extends \PHPUnit_Framework_TestCase
19{
20 /**
21 * @var EventDispatcherInterface
22 */
23 protected $dispatcher;
24
25 /**
26 * @var \Symfony\Component\Form\FormFactoryInterface
27 */
28 protected $factory;
29
30 /**
31 * @var \Symfony\Component\Form\FormInterface
32 */
33 protected $form;
34
35 protected function setUp()
36 {
37 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
38 $this->markTestSkipped('The "EventDispatcher" component is not available');
39 }
40
41 // We need an actual dispatcher to use the deprecated
42 // bindRequest() method
43 $this->dispatcher = new EventDispatcher();
44 $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
45 $this->form = $this->createForm();
46 }
47
48 protected function tearDown()
49 {
50 $this->dispatcher = null;
51 $this->factory = null;
52 $this->form = null;
53 }
54
55 /**
56 * @return \Symfony\Component\Form\FormInterface
57 */
58 abstract protected function createForm();
59
60 /**
61 * @param string $name
62 * @param EventDispatcherInterface $dispatcher
63 * @param string $dataClass
64 *
65 * @return FormBuilder
66 */
67 protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null, $dataClass = null)
68 {
69 return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory);
70 }
71
72 /**
73 * @param string $name
74 *
75 * @return \PHPUnit_Framework_MockObject_MockObject
76 */
77 protected function getMockForm($name = 'name')
78 {
79 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
80 $config = $this->getMock('Symfony\Component\Form\FormConfigInterface');
81
82 $form->expects($this->any())
83 ->method('getName')
84 ->will($this->returnValue($name));
85 $form->expects($this->any())
86 ->method('getConfig')
87 ->will($this->returnValue($config));
88
89 return $form;
90 }
91
92 /**
93 * @param string $name
94 *
95 * @return \PHPUnit_Framework_MockObject_MockObject
96 */
97 protected function getValidForm($name)
98 {
99 $form = $this->getMockForm($name);
100
101 $form->expects($this->any())
102 ->method('isValid')
103 ->will($this->returnValue(true));
104
105 return $form;
106 }
107
108 /**
109 * @param string $name
110 *
111 * @return \PHPUnit_Framework_MockObject_MockObject
112 */
113 protected function getInvalidForm($name)
114 {
115 $form = $this->getMockForm($name);
116
117 $form->expects($this->any())
118 ->method('isValid')
119 ->will($this->returnValue(false));
120
121 return $form;
122 }
123
124 /**
125 * @return \PHPUnit_Framework_MockObject_MockObject
126 */
127 protected function getDataMapper()
128 {
129 return $this->getMock('Symfony\Component\Form\DataMapperInterface');
130 }
131
132 /**
133 * @return \PHPUnit_Framework_MockObject_MockObject
134 */
135 protected function getDataTransformer()
136 {
137 return $this->getMock('Symfony\Component\Form\DataTransformerInterface');
138 }
139
140 /**
141 * @return \PHPUnit_Framework_MockObject_MockObject
142 */
143 protected function getFormValidator()
144 {
145 return $this->getMock('Symfony\Component\Form\FormValidatorInterface');
146 }
147}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractLayoutTest.php
new file mode 100644
index 00000000..8f632a2b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractLayoutTest.php
@@ -0,0 +1,1876 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\FormError;
15use Symfony\Component\Form\FormView;
16use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
17
18abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormIntegrationTestCase
19{
20 protected $csrfProvider;
21
22 protected function setUp()
23 {
24 if (!extension_loaded('intl')) {
25 $this->markTestSkipped('The "intl" extension is not available');
26 }
27
28 \Locale::setDefault('en');
29
30 $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
31
32 parent::setUp();
33 }
34
35 protected function getExtensions()
36 {
37 return array(
38 new CsrfExtension($this->csrfProvider),
39 );
40 }
41
42 protected function tearDown()
43 {
44 $this->csrfProvider = null;
45
46 parent::tearDown();
47 }
48
49 protected function assertXpathNodeValue(\DomElement $element, $expression, $nodeValue)
50 {
51 $xpath = new \DOMXPath($element->ownerDocument);
52 $nodeList = $xpath->evaluate($expression);
53 $this->assertEquals(1, $nodeList->length);
54 $this->assertEquals($nodeValue, $nodeList->item(0)->nodeValue);
55 }
56
57 protected function assertMatchesXpath($html, $expression, $count = 1)
58 {
59 $dom = new \DomDocument('UTF-8');
60 try {
61 // Wrap in <root> node so we can load HTML with multiple tags at
62 // the top level
63 $dom->loadXml('<root>'.$html.'</root>');
64 } catch (\Exception $e) {
65 $this->fail(sprintf(
66 "Failed loading HTML:\n\n%s\n\nError: %s",
67 $html,
68 $e->getMessage()
69 ));
70 }
71 $xpath = new \DOMXPath($dom);
72 $nodeList = $xpath->evaluate('/root'.$expression);
73
74 if ($nodeList->length != $count) {
75 $dom->formatOutput = true;
76 $this->fail(sprintf(
77 "Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
78 $expression,
79 $count == 1 ? 'once' : $count.' times',
80 $nodeList->length == 1 ? 'once' : $nodeList->length.' times',
81 // strip away <root> and </root>
82 substr($dom->saveHTML(), 6, -8)
83 ));
84 }
85 }
86
87 protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
88 {
89 // include ampersands everywhere to validate escaping
90 $html = $this->renderWidget($view, array_merge(array(
91 'id' => 'my&id',
92 'attr' => array('class' => 'my&class'),
93 ), $vars));
94
95 $xpath = trim($xpath).'
96 [@id="my&id"]
97 [@class="my&class"]';
98
99 $this->assertMatchesXpath($html, $xpath);
100 }
101
102 abstract protected function renderForm(FormView $view, array $vars = array());
103
104 abstract protected function renderEnctype(FormView $view);
105
106 abstract protected function renderLabel(FormView $view, $label = null, array $vars = array());
107
108 abstract protected function renderErrors(FormView $view);
109
110 abstract protected function renderWidget(FormView $view, array $vars = array());
111
112 abstract protected function renderRow(FormView $view, array $vars = array());
113
114 abstract protected function renderRest(FormView $view, array $vars = array());
115
116 abstract protected function renderStart(FormView $view, array $vars = array());
117
118 abstract protected function renderEnd(FormView $view, array $vars = array());
119
120 abstract protected function setTheme(FormView $view, array $themes);
121
122 public function testEnctype()
123 {
124 $form = $this->factory->createNamedBuilder('name', 'form')
125 ->add('file', 'file')
126 ->getForm();
127
128 $this->assertEquals('enctype="multipart/form-data"', $this->renderEnctype($form->createView()));
129 }
130
131 public function testNoEnctype()
132 {
133 $form = $this->factory->createNamedBuilder('name', 'form')
134 ->add('text', 'text')
135 ->getForm();
136
137 $this->assertEquals('', $this->renderEnctype($form->createView()));
138 }
139
140 public function testLabel()
141 {
142 $form = $this->factory->createNamed('name', 'text');
143 $view = $form->createView();
144 $this->renderWidget($view, array('label' => 'foo'));
145 $html = $this->renderLabel($view);
146
147 $this->assertMatchesXpath($html,
148'/label
149 [@for="name"]
150 [.="[trans]Name[/trans]"]
151'
152 );
153 }
154
155 public function testLabelOnForm()
156 {
157 $form = $this->factory->createNamed('name', 'date');
158 $view = $form->createView();
159 $this->renderWidget($view, array('label' => 'foo'));
160 $html = $this->renderLabel($view);
161
162 $this->assertMatchesXpath($html,
163'/label
164 [@class="required"]
165 [.="[trans]Name[/trans]"]
166'
167 );
168 }
169
170 public function testLabelWithCustomTextPassedAsOption()
171 {
172 $form = $this->factory->createNamed('name', 'text', null, array(
173 'label' => 'Custom label',
174 ));
175 $html = $this->renderLabel($form->createView());
176
177 $this->assertMatchesXpath($html,
178'/label
179 [@for="name"]
180 [.="[trans]Custom label[/trans]"]
181'
182 );
183 }
184
185 public function testLabelWithCustomTextPassedDirectly()
186 {
187 $form = $this->factory->createNamed('name', 'text');
188 $html = $this->renderLabel($form->createView(), 'Custom label');
189
190 $this->assertMatchesXpath($html,
191'/label
192 [@for="name"]
193 [.="[trans]Custom label[/trans]"]
194'
195 );
196 }
197
198 public function testLabelWithCustomTextPassedAsOptionAndDirectly()
199 {
200 $form = $this->factory->createNamed('name', 'text', null, array(
201 'label' => 'Custom label',
202 ));
203 $html = $this->renderLabel($form->createView(), 'Overridden label');
204
205 $this->assertMatchesXpath($html,
206'/label
207 [@for="name"]
208 [.="[trans]Overridden label[/trans]"]
209'
210 );
211 }
212
213 public function testLabelDoesNotRenderFieldAttributes()
214 {
215 $form = $this->factory->createNamed('name', 'text');
216 $html = $this->renderLabel($form->createView(), null, array(
217 'attr' => array(
218 'class' => 'my&class'
219 ),
220 ));
221
222 $this->assertMatchesXpath($html,
223'/label
224 [@for="name"]
225 [@class="required"]
226'
227 );
228 }
229
230 public function testLabelWithCustomAttributesPassedDirectly()
231 {
232 $form = $this->factory->createNamed('name', 'text');
233 $html = $this->renderLabel($form->createView(), null, array(
234 'label_attr' => array(
235 'class' => 'my&class'
236 ),
237 ));
238
239 $this->assertMatchesXpath($html,
240'/label
241 [@for="name"]
242 [@class="my&class required"]
243'
244 );
245 }
246
247 public function testLabelWithCustomTextAndCustomAttributesPassedDirectly()
248 {
249 $form = $this->factory->createNamed('name', 'text');
250 $html = $this->renderLabel($form->createView(), 'Custom label', array(
251 'label_attr' => array(
252 'class' => 'my&class'
253 ),
254 ));
255
256 $this->assertMatchesXpath($html,
257'/label
258 [@for="name"]
259 [@class="my&class required"]
260 [.="[trans]Custom label[/trans]"]
261'
262 );
263 }
264
265 // https://github.com/symfony/symfony/issues/5029
266 public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly()
267 {
268 $form = $this->factory->createNamed('name', 'text', null, array(
269 'label' => 'Custom label',
270 ));
271 $html = $this->renderLabel($form->createView(), null, array(
272 'label_attr' => array(
273 'class' => 'my&class'
274 ),
275 ));
276
277 $this->assertMatchesXpath($html,
278 '/label
279 [@for="name"]
280 [@class="my&class required"]
281 [.="[trans]Custom label[/trans]"]
282'
283 );
284 }
285
286 public function testErrors()
287 {
288 $form = $this->factory->createNamed('name', 'text');
289 $form->addError(new FormError('[trans]Error 1[/trans]'));
290 $form->addError(new FormError('[trans]Error 2[/trans]'));
291 $view = $form->createView();
292 $html = $this->renderErrors($view);
293
294 $this->assertMatchesXpath($html,
295'/ul
296 [
297 ./li[.="[trans]Error 1[/trans]"]
298 /following-sibling::li[.="[trans]Error 2[/trans]"]
299 ]
300 [count(./li)=2]
301'
302 );
303 }
304
305 public function testWidgetById()
306 {
307 $form = $this->factory->createNamed('text_id', 'text');
308 $html = $this->renderWidget($form->createView());
309
310 $this->assertMatchesXpath($html,
311'/div
312 [
313 ./input
314 [@type="text"]
315 [@id="text_id"]
316 ]
317 [@id="container"]
318'
319 );
320 }
321
322 public function testCheckedCheckbox()
323 {
324 $form = $this->factory->createNamed('name', 'checkbox', true);
325
326 $this->assertWidgetMatchesXpath($form->createView(), array(),
327'/input
328 [@type="checkbox"]
329 [@name="name"]
330 [@checked="checked"]
331 [@value="1"]
332'
333 );
334 }
335
336 public function testUncheckedCheckbox()
337 {
338 $form = $this->factory->createNamed('name', 'checkbox', false);
339
340 $this->assertWidgetMatchesXpath($form->createView(), array(),
341'/input
342 [@type="checkbox"]
343 [@name="name"]
344 [not(@checked)]
345'
346 );
347 }
348
349 public function testCheckboxWithValue()
350 {
351 $form = $this->factory->createNamed('name', 'checkbox', false, array(
352 'value' => 'foo&bar',
353 ));
354
355 $this->assertWidgetMatchesXpath($form->createView(), array(),
356'/input
357 [@type="checkbox"]
358 [@name="name"]
359 [@value="foo&bar"]
360'
361 );
362 }
363
364 public function testSingleChoice()
365 {
366 $form = $this->factory->createNamed('name', 'choice', '&a', array(
367 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
368 'multiple' => false,
369 'expanded' => false,
370 ));
371
372 $this->assertWidgetMatchesXpath($form->createView(), array(),
373'/select
374 [@name="name"]
375 [@required="required"]
376 [
377 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
378 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
379 ]
380 [count(./option)=2]
381'
382 );
383 }
384
385 public function testSingleChoiceWithPreferred()
386 {
387 $form = $this->factory->createNamed('name', 'choice', '&a', array(
388 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
389 'preferred_choices' => array('&b'),
390 'multiple' => false,
391 'expanded' => false,
392 ));
393
394 $this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
395'/select
396 [@name="name"]
397 [@required="required"]
398 [
399 ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
400 /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
401 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
402 ]
403 [count(./option)=3]
404'
405 );
406 }
407
408 public function testSingleChoiceWithPreferredAndNoSeparator()
409 {
410 $form = $this->factory->createNamed('name', 'choice', '&a', array(
411 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
412 'preferred_choices' => array('&b'),
413 'multiple' => false,
414 'expanded' => false,
415 ));
416
417 $this->assertWidgetMatchesXpath($form->createView(), array('separator' => null),
418'/select
419 [@name="name"]
420 [@required="required"]
421 [
422 ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
423 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
424 ]
425 [count(./option)=2]
426'
427 );
428 }
429
430 public function testSingleChoiceWithPreferredAndBlankSeparator()
431 {
432 $form = $this->factory->createNamed('name', 'choice', '&a', array(
433 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
434 'preferred_choices' => array('&b'),
435 'multiple' => false,
436 'expanded' => false,
437 ));
438
439 $this->assertWidgetMatchesXpath($form->createView(), array('separator' => ''),
440'/select
441 [@name="name"]
442 [@required="required"]
443 [
444 ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
445 /following-sibling::option[@disabled="disabled"][not(@selected)][.=""]
446 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
447 ]
448 [count(./option)=3]
449'
450 );
451 }
452
453 public function testChoiceWithOnlyPreferred()
454 {
455 $form = $this->factory->createNamed('name', 'choice', '&a', array(
456 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
457 'preferred_choices' => array('&a', '&b'),
458 'multiple' => false,
459 'expanded' => false,
460 ));
461
462 $this->assertWidgetMatchesXpath($form->createView(), array(),
463'/select
464 [count(./option)=2]
465'
466 );
467 }
468
469 public function testSingleChoiceNonRequired()
470 {
471 $form = $this->factory->createNamed('name', 'choice', '&a', array(
472 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
473 'required' => false,
474 'multiple' => false,
475 'expanded' => false,
476 ));
477
478 $this->assertWidgetMatchesXpath($form->createView(), array(),
479'/select
480 [@name="name"]
481 [not(@required)]
482 [
483 ./option[@value=""][.="[trans][/trans]"]
484 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
485 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
486 ]
487 [count(./option)=3]
488'
489 );
490 }
491
492 public function testSingleChoiceNonRequiredNoneSelected()
493 {
494 $form = $this->factory->createNamed('name', 'choice', null, array(
495 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
496 'required' => false,
497 'multiple' => false,
498 'expanded' => false,
499 ));
500
501 $this->assertWidgetMatchesXpath($form->createView(), array(),
502'/select
503 [@name="name"]
504 [not(@required)]
505 [
506 ./option[@value=""][.="[trans][/trans]"]
507 /following-sibling::option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
508 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
509 ]
510 [count(./option)=3]
511'
512 );
513 }
514
515 public function testSingleChoiceWithNonRequiredEmptyValue()
516 {
517 $form = $this->factory->createNamed('name', 'choice', '&a', array(
518 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
519 'multiple' => false,
520 'expanded' => false,
521 'required' => false,
522 'empty_value' => 'Select&Anything&Not&Me',
523 ));
524
525 $this->assertWidgetMatchesXpath($form->createView(), array(),
526'/select
527 [@name="name"]
528 [not(@required)]
529 [
530 ./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Anything&Not&Me[/trans]"]
531 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
532 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
533 ]
534 [count(./option)=3]
535'
536 );
537 }
538
539 public function testSingleChoiceRequiredWithEmptyValue()
540 {
541 $form = $this->factory->createNamed('name', 'choice', '&a', array(
542 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
543 'required' => true,
544 'multiple' => false,
545 'expanded' => false,
546 'empty_value' => 'Test&Me'
547 ));
548
549 $this->assertWidgetMatchesXpath($form->createView(), array(),
550'/select
551 [@name="name"]
552 [@required="required"]
553 [
554 ./option[not(@value)][not(@selected)][@disabled][.="[trans]Test&Me[/trans]"]
555 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
556 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
557 ]
558 [count(./option)=3]
559'
560 );
561 }
562
563 public function testSingleChoiceRequiredWithEmptyValueViaView()
564 {
565 $form = $this->factory->createNamed('name', 'choice', '&a', array(
566 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
567 'required' => true,
568 'multiple' => false,
569 'expanded' => false,
570 ));
571
572 $this->assertWidgetMatchesXpath($form->createView(), array('empty_value' => ''),
573'/select
574 [@name="name"]
575 [@required="required"]
576 [
577 ./option[not(@value)][not(@selected)][@disabled][.="[trans][/trans]"]
578 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
579 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
580 ]
581 [count(./option)=3]
582'
583 );
584 }
585
586 public function testSingleChoiceGrouped()
587 {
588 $form = $this->factory->createNamed('name', 'choice', '&a', array(
589 'choices' => array(
590 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
591 'Group&2' => array('&c' => 'Choice&C'),
592 ),
593 'multiple' => false,
594 'expanded' => false,
595 ));
596
597 $this->assertWidgetMatchesXpath($form->createView(), array(),
598'/select
599 [@name="name"]
600 [./optgroup[@label="[trans]Group&1[/trans]"]
601 [
602 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
603 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
604 ]
605 [count(./option)=2]
606 ]
607 [./optgroup[@label="[trans]Group&2[/trans]"]
608 [./option[@value="&c"][not(@selected)][.="[trans]Choice&C[/trans]"]]
609 [count(./option)=1]
610 ]
611 [count(./optgroup)=2]
612'
613 );
614 }
615
616 public function testMultipleChoice()
617 {
618 $form = $this->factory->createNamed('name', 'choice', array('&a'), array(
619 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
620 'multiple' => true,
621 'expanded' => false,
622 ));
623
624 $this->assertWidgetMatchesXpath($form->createView(), array(),
625'/select
626 [@name="name[]"]
627 [@multiple="multiple"]
628 [
629 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
630 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
631 ]
632 [count(./option)=2]
633'
634 );
635 }
636
637 public function testMultipleChoiceSkipsEmptyValue()
638 {
639 $form = $this->factory->createNamed('name', 'choice', array('&a'), array(
640 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
641 'multiple' => true,
642 'expanded' => false,
643 'empty_value' => 'Test&Me'
644 ));
645
646 $this->assertWidgetMatchesXpath($form->createView(), array(),
647'/select
648 [@name="name[]"]
649 [@multiple="multiple"]
650 [
651 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
652 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
653 ]
654 [count(./option)=2]
655'
656 );
657 }
658
659 public function testMultipleChoiceNonRequired()
660 {
661 $form = $this->factory->createNamed('name', 'choice', array('&a'), array(
662 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
663 'required' => false,
664 'multiple' => true,
665 'expanded' => false,
666 ));
667
668 $this->assertWidgetMatchesXpath($form->createView(), array(),
669'/select
670 [@name="name[]"]
671 [@multiple="multiple"]
672 [
673 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
674 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
675 ]
676 [count(./option)=2]
677'
678 );
679 }
680
681 public function testSingleChoiceExpanded()
682 {
683 $form = $this->factory->createNamed('name', 'choice', '&a', array(
684 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
685 'multiple' => false,
686 'expanded' => true,
687 ));
688
689 $this->assertWidgetMatchesXpath($form->createView(), array(),
690'/div
691 [
692 ./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
693 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
694 /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
695 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
696 /following-sibling::input[@type="hidden"][@id="name__token"]
697 ]
698 [count(./input)=3]
699'
700 );
701 }
702
703 public function testSingleChoiceExpandedWithEmptyValue()
704 {
705 $form = $this->factory->createNamed('name', 'choice', '&a', array(
706 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
707 'multiple' => false,
708 'expanded' => true,
709 'empty_value' => 'Test&Me'
710 ));
711
712 $this->assertWidgetMatchesXpath($form->createView(), array(),
713'/div
714 [
715 ./input[@type="radio"][@name="name"][@id="name_placeholder"][not(@checked)]
716 /following-sibling::label[@for="name_placeholder"][.="[trans]Test&Me[/trans]"]
717 /following-sibling::input[@type="radio"][@name="name"][@id="name_0"][@checked]
718 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
719 /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
720 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
721 /following-sibling::input[@type="hidden"][@id="name__token"]
722 ]
723 [count(./input)=4]
724'
725 );
726 }
727
728 public function testSingleChoiceExpandedWithBooleanValue()
729 {
730 $form = $this->factory->createNamed('name', 'choice', true, array(
731 'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'),
732 'multiple' => false,
733 'expanded' => true,
734 ));
735
736 $this->assertWidgetMatchesXpath($form->createView(), array(),
737'/div
738 [
739 ./input[@type="radio"][@name="name"][@id="name_0"][@checked]
740 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
741 /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
742 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
743 /following-sibling::input[@type="hidden"][@id="name__token"]
744 ]
745 [count(./input)=3]
746'
747 );
748 }
749
750 public function testMultipleChoiceExpanded()
751 {
752 $form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array(
753 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
754 'multiple' => true,
755 'expanded' => true,
756 'required' => true,
757 ));
758
759 $this->assertWidgetMatchesXpath($form->createView(), array(),
760'/div
761 [
762 ./input[@type="checkbox"][@name="name[]"][@id="name_0"][@checked][not(@required)]
763 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
764 /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][not(@checked)][not(@required)]
765 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
766 /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_2"][@checked][not(@required)]
767 /following-sibling::label[@for="name_2"][.="[trans]Choice&C[/trans]"]
768 /following-sibling::input[@type="hidden"][@id="name__token"]
769 ]
770 [count(./input)=4]
771'
772 );
773 }
774
775 public function testCountry()
776 {
777 $form = $this->factory->createNamed('name', 'country', 'AT');
778
779 $this->assertWidgetMatchesXpath($form->createView(), array(),
780'/select
781 [@name="name"]
782 [./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
783 [count(./option)>200]
784'
785 );
786 }
787
788 public function testCountryWithEmptyValue()
789 {
790 $form = $this->factory->createNamed('name', 'country', 'AT', array(
791 'empty_value' => 'Select&Country',
792 'required' => false,
793 ));
794
795 $this->assertWidgetMatchesXpath($form->createView(), array(),
796'/select
797 [@name="name"]
798 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Country[/trans]"]]
799 [./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
800 [count(./option)>201]
801'
802 );
803 }
804
805 public function testDateTime()
806 {
807 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
808 'input' => 'string',
809 'with_seconds' => false,
810 ));
811
812 $this->assertWidgetMatchesXpath($form->createView(), array(),
813'/div
814 [
815 ./div
816 [@id="name_date"]
817 [
818 ./select
819 [@id="name_date_month"]
820 [./option[@value="2"][@selected="selected"]]
821 /following-sibling::select
822 [@id="name_date_day"]
823 [./option[@value="3"][@selected="selected"]]
824 /following-sibling::select
825 [@id="name_date_year"]
826 [./option[@value="2011"][@selected="selected"]]
827 ]
828 /following-sibling::div
829 [@id="name_time"]
830 [
831 ./select
832 [@id="name_time_hour"]
833 [./option[@value="4"][@selected="selected"]]
834 /following-sibling::select
835 [@id="name_time_minute"]
836 [./option[@value="5"][@selected="selected"]]
837 ]
838 ]
839 [count(.//select)=5]
840'
841 );
842 }
843
844 public function testDateTimeWithEmptyValueGlobal()
845 {
846 $form = $this->factory->createNamed('name', 'datetime', null, array(
847 'input' => 'string',
848 'empty_value' => 'Change&Me',
849 'required' => false,
850 ));
851
852 $this->assertWidgetMatchesXpath($form->createView(), array(),
853'/div
854 [
855 ./div
856 [@id="name_date"]
857 [
858 ./select
859 [@id="name_date_month"]
860 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
861 /following-sibling::select
862 [@id="name_date_day"]
863 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
864 /following-sibling::select
865 [@id="name_date_year"]
866 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
867 ]
868 /following-sibling::div
869 [@id="name_time"]
870 [
871 ./select
872 [@id="name_time_hour"]
873 [./option[@value=""][.="[trans]Change&Me[/trans]"]]
874 /following-sibling::select
875 [@id="name_time_minute"]
876 [./option[@value=""][.="[trans]Change&Me[/trans]"]]
877 ]
878 ]
879 [count(.//select)=5]
880'
881 );
882 }
883
884 public function testDateTimeWithEmptyValueOnTime()
885 {
886 $data = array('year' => '2011', 'month' => '2', 'day' => '3', 'hour' => '', 'minute' => '');
887
888 $form = $this->factory->createNamed('name', 'datetime', $data, array(
889 'input' => 'array',
890 'empty_value' => array('hour' => 'Change&Me', 'minute' => 'Change&Me'),
891 'required' => false,
892 ));
893
894 $this->assertWidgetMatchesXpath($form->createView(), array(),
895'/div
896 [
897 ./div
898 [@id="name_date"]
899 [
900 ./select
901 [@id="name_date_month"]
902 [./option[@value="2"][@selected="selected"]]
903 /following-sibling::select
904 [@id="name_date_day"]
905 [./option[@value="3"][@selected="selected"]]
906 /following-sibling::select
907 [@id="name_date_year"]
908 [./option[@value="2011"][@selected="selected"]]
909 ]
910 /following-sibling::div
911 [@id="name_time"]
912 [
913 ./select
914 [@id="name_time_hour"]
915 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
916 /following-sibling::select
917 [@id="name_time_minute"]
918 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
919 ]
920 ]
921 [count(.//select)=5]
922'
923 );
924 }
925
926 public function testDateTimeWithSeconds()
927 {
928 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
929 'input' => 'string',
930 'with_seconds' => true,
931 ));
932
933 $this->assertWidgetMatchesXpath($form->createView(), array(),
934'/div
935 [
936 ./div
937 [@id="name_date"]
938 [
939 ./select
940 [@id="name_date_month"]
941 [./option[@value="2"][@selected="selected"]]
942 /following-sibling::select
943 [@id="name_date_day"]
944 [./option[@value="3"][@selected="selected"]]
945 /following-sibling::select
946 [@id="name_date_year"]
947 [./option[@value="2011"][@selected="selected"]]
948 ]
949 /following-sibling::div
950 [@id="name_time"]
951 [
952 ./select
953 [@id="name_time_hour"]
954 [./option[@value="4"][@selected="selected"]]
955 /following-sibling::select
956 [@id="name_time_minute"]
957 [./option[@value="5"][@selected="selected"]]
958 /following-sibling::select
959 [@id="name_time_second"]
960 [./option[@value="6"][@selected="selected"]]
961 ]
962 ]
963 [count(.//select)=6]
964'
965 );
966 }
967
968 public function testDateTimeSingleText()
969 {
970 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
971 'input' => 'string',
972 'date_widget' => 'single_text',
973 'time_widget' => 'single_text',
974 ));
975
976 $this->assertWidgetMatchesXpath($form->createView(), array(),
977'/div
978 [
979 ./input
980 [@type="date"]
981 [@id="name_date"]
982 [@name="name[date]"]
983 [@value="2011-02-03"]
984 /following-sibling::input
985 [@type="time"]
986 [@id="name_time"]
987 [@name="name[time]"]
988 [@value="04:05"]
989 ]
990'
991 );
992 }
993
994 public function testDateTimeWithWidgetSingleText()
995 {
996 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
997 'input' => 'string',
998 'widget' => 'single_text',
999 'model_timezone' => 'UTC',
1000 'view_timezone' => 'UTC',
1001 ));
1002
1003 $this->assertWidgetMatchesXpath($form->createView(), array(),
1004'/input
1005 [@type="datetime"]
1006 [@name="name"]
1007 [@value="2011-02-03T04:05:06Z"]
1008'
1009 );
1010 }
1011
1012 public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
1013 {
1014 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
1015 'input' => 'string',
1016 'date_widget' => 'choice',
1017 'time_widget' => 'choice',
1018 'widget' => 'single_text',
1019 'model_timezone' => 'UTC',
1020 'view_timezone' => 'UTC',
1021 ));
1022
1023 $this->assertWidgetMatchesXpath($form->createView(), array(),
1024'/input
1025 [@type="datetime"]
1026 [@name="name"]
1027 [@value="2011-02-03T04:05:06Z"]
1028'
1029 );
1030 }
1031
1032 public function testDateChoice()
1033 {
1034 $form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
1035 'input' => 'string',
1036 'widget' => 'choice',
1037 ));
1038
1039 $this->assertWidgetMatchesXpath($form->createView(), array(),
1040'/div
1041 [
1042 ./select
1043 [@id="name_month"]
1044 [./option[@value="2"][@selected="selected"]]
1045 /following-sibling::select
1046 [@id="name_day"]
1047 [./option[@value="3"][@selected="selected"]]
1048 /following-sibling::select
1049 [@id="name_year"]
1050 [./option[@value="2011"][@selected="selected"]]
1051 ]
1052 [count(./select)=3]
1053'
1054 );
1055 }
1056
1057 public function testDateChoiceWithEmptyValueGlobal()
1058 {
1059 $form = $this->factory->createNamed('name', 'date', null, array(
1060 'input' => 'string',
1061 'widget' => 'choice',
1062 'empty_value' => 'Change&Me',
1063 'required' => false,
1064 ));
1065
1066 $this->assertWidgetMatchesXpath($form->createView(), array(),
1067'/div
1068 [
1069 ./select
1070 [@id="name_month"]
1071 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1072 /following-sibling::select
1073 [@id="name_day"]
1074 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1075 /following-sibling::select
1076 [@id="name_year"]
1077 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1078 ]
1079 [count(./select)=3]
1080'
1081 );
1082 }
1083
1084 public function testDateChoiceWithEmptyValueOnYear()
1085 {
1086 $form = $this->factory->createNamed('name', 'date', null, array(
1087 'input' => 'string',
1088 'widget' => 'choice',
1089 'required' => false,
1090 'empty_value' => array('year' => 'Change&Me'),
1091 ));
1092
1093 $this->assertWidgetMatchesXpath($form->createView(), array(),
1094'/div
1095 [
1096 ./select
1097 [@id="name_month"]
1098 [./option[@value="1"]]
1099 /following-sibling::select
1100 [@id="name_day"]
1101 [./option[@value="1"]]
1102 /following-sibling::select
1103 [@id="name_year"]
1104 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1105 ]
1106 [count(./select)=3]
1107'
1108 );
1109 }
1110
1111 public function testDateText()
1112 {
1113 $form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
1114 'input' => 'string',
1115 'widget' => 'text',
1116 ));
1117
1118 $this->assertWidgetMatchesXpath($form->createView(), array(),
1119'/div
1120 [
1121 ./input
1122 [@id="name_month"]
1123 [@type="text"]
1124 [@value="2"]
1125 /following-sibling::input
1126 [@id="name_day"]
1127 [@type="text"]
1128 [@value="3"]
1129 /following-sibling::input
1130 [@id="name_year"]
1131 [@type="text"]
1132 [@value="2011"]
1133 ]
1134 [count(./input)=3]
1135'
1136 );
1137 }
1138
1139 public function testDateSingleText()
1140 {
1141 $form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
1142 'input' => 'string',
1143 'widget' => 'single_text',
1144 ));
1145
1146 $this->assertWidgetMatchesXpath($form->createView(), array(),
1147'/input
1148 [@type="date"]
1149 [@name="name"]
1150 [@value="2011-02-03"]
1151'
1152 );
1153 }
1154
1155 public function testDateErrorBubbling()
1156 {
1157 $form = $this->factory->createNamedBuilder('form', 'form')
1158 ->add('date', 'date')
1159 ->getForm();
1160 $form->get('date')->addError(new FormError('[trans]Error![/trans]'));
1161 $view = $form->createView();
1162
1163 $this->assertEmpty($this->renderErrors($view));
1164 $this->assertNotEmpty($this->renderErrors($view['date']));
1165 }
1166
1167 public function testBirthDay()
1168 {
1169 $form = $this->factory->createNamed('name', 'birthday', '2000-02-03', array(
1170 'input' => 'string',
1171 ));
1172
1173 $this->assertWidgetMatchesXpath($form->createView(), array(),
1174'/div
1175 [
1176 ./select
1177 [@id="name_month"]
1178 [./option[@value="2"][@selected="selected"]]
1179 /following-sibling::select
1180 [@id="name_day"]
1181 [./option[@value="3"][@selected="selected"]]
1182 /following-sibling::select
1183 [@id="name_year"]
1184 [./option[@value="2000"][@selected="selected"]]
1185 ]
1186 [count(./select)=3]
1187'
1188 );
1189 }
1190
1191 public function testBirthDayWithEmptyValue()
1192 {
1193 $form = $this->factory->createNamed('name', 'birthday', '1950-01-01', array(
1194 'input' => 'string',
1195 'empty_value' => '',
1196 'required' => false,
1197 ));
1198
1199 $this->assertWidgetMatchesXpath($form->createView(), array(),
1200'/div
1201 [
1202 ./select
1203 [@id="name_month"]
1204 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
1205 [./option[@value="1"][@selected="selected"]]
1206 /following-sibling::select
1207 [@id="name_day"]
1208 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
1209 [./option[@value="1"][@selected="selected"]]
1210 /following-sibling::select
1211 [@id="name_year"]
1212 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
1213 [./option[@value="1950"][@selected="selected"]]
1214 ]
1215 [count(./select)=3]
1216'
1217 );
1218 }
1219
1220 public function testEmail()
1221 {
1222 $form = $this->factory->createNamed('name', 'email', 'foo&bar');
1223
1224 $this->assertWidgetMatchesXpath($form->createView(), array(),
1225'/input
1226 [@type="email"]
1227 [@name="name"]
1228 [@value="foo&bar"]
1229 [not(@maxlength)]
1230'
1231 );
1232 }
1233
1234 public function testEmailWithMaxLength()
1235 {
1236 $form = $this->factory->createNamed('name', 'email', 'foo&bar', array(
1237 'max_length' => 123,
1238 ));
1239
1240 $this->assertWidgetMatchesXpath($form->createView(), array(),
1241'/input
1242 [@type="email"]
1243 [@name="name"]
1244 [@value="foo&bar"]
1245 [@maxlength="123"]
1246'
1247 );
1248 }
1249
1250 public function testFile()
1251 {
1252 $form = $this->factory->createNamed('name', 'file');
1253
1254 $this->assertWidgetMatchesXpath($form->createView(), array(),
1255'/input
1256 [@type="file"]
1257'
1258 );
1259 }
1260
1261 public function testHidden()
1262 {
1263 $form = $this->factory->createNamed('name', 'hidden', 'foo&bar');
1264
1265 $this->assertWidgetMatchesXpath($form->createView(), array(),
1266'/input
1267 [@type="hidden"]
1268 [@name="name"]
1269 [@value="foo&bar"]
1270'
1271 );
1272 }
1273
1274 public function testReadOnly()
1275 {
1276 $form = $this->factory->createNamed('name', 'text', null, array(
1277 'read_only' => true,
1278 ));
1279
1280 $this->assertWidgetMatchesXpath($form->createView(), array(),
1281'/input
1282 [@type="text"]
1283 [@name="name"]
1284 [@readonly="readonly"]
1285'
1286 );
1287 }
1288
1289 public function testDisabled()
1290 {
1291 $form = $this->factory->createNamed('name', 'text', null, array(
1292 'disabled' => true,
1293 ));
1294
1295 $this->assertWidgetMatchesXpath($form->createView(), array(),
1296'/input
1297 [@type="text"]
1298 [@name="name"]
1299 [@disabled="disabled"]
1300'
1301 );
1302 }
1303
1304 public function testInteger()
1305 {
1306 $form = $this->factory->createNamed('name', 'integer', 123);
1307
1308 $this->assertWidgetMatchesXpath($form->createView(), array(),
1309'/input
1310 [@type="number"]
1311 [@name="name"]
1312 [@value="123"]
1313'
1314 );
1315 }
1316
1317 public function testLanguage()
1318 {
1319 $form = $this->factory->createNamed('name', 'language', 'de');
1320
1321 $this->assertWidgetMatchesXpath($form->createView(), array(),
1322'/select
1323 [@name="name"]
1324 [./option[@value="de"][@selected="selected"][.="[trans]German[/trans]"]]
1325 [count(./option)>200]
1326'
1327 );
1328 }
1329
1330 public function testLocale()
1331 {
1332 $form = $this->factory->createNamed('name', 'locale', 'de_AT');
1333
1334 $this->assertWidgetMatchesXpath($form->createView(), array(),
1335'/select
1336 [@name="name"]
1337 [./option[@value="de_AT"][@selected="selected"][.="[trans]German (Austria)[/trans]"]]
1338 [count(./option)>200]
1339'
1340 );
1341 }
1342
1343 public function testMoney()
1344 {
1345 $form = $this->factory->createNamed('name', 'money', 1234.56, array(
1346 'currency' => 'EUR',
1347 ));
1348
1349 $this->assertWidgetMatchesXpath($form->createView(), array(),
1350'/input
1351 [@type="text"]
1352 [@name="name"]
1353 [@value="1234.56"]
1354 [contains(.., "€")]
1355'
1356 );
1357 }
1358
1359 public function testNumber()
1360 {
1361 $form = $this->factory->createNamed('name', 'number', 1234.56);
1362
1363 $this->assertWidgetMatchesXpath($form->createView(), array(),
1364'/input
1365 [@type="text"]
1366 [@name="name"]
1367 [@value="1234.56"]
1368'
1369 );
1370 }
1371
1372 public function testPassword()
1373 {
1374 $form = $this->factory->createNamed('name', 'password', 'foo&bar');
1375
1376 $this->assertWidgetMatchesXpath($form->createView(), array(),
1377'/input
1378 [@type="password"]
1379 [@name="name"]
1380'
1381 );
1382 }
1383
1384 public function testPasswordSubmittedWithNotAlwaysEmpty()
1385 {
1386 $form = $this->factory->createNamed('name', 'password', null, array(
1387 'always_empty' => false,
1388 ));
1389 $form->submit('foo&bar');
1390
1391 $this->assertWidgetMatchesXpath($form->createView(), array(),
1392'/input
1393 [@type="password"]
1394 [@name="name"]
1395 [@value="foo&bar"]
1396'
1397 );
1398 }
1399
1400 public function testPasswordWithMaxLength()
1401 {
1402 $form = $this->factory->createNamed('name', 'password', 'foo&bar', array(
1403 'max_length' => 123,
1404 ));
1405
1406 $this->assertWidgetMatchesXpath($form->createView(), array(),
1407'/input
1408 [@type="password"]
1409 [@name="name"]
1410 [@maxlength="123"]
1411'
1412 );
1413 }
1414
1415 public function testPercent()
1416 {
1417 $form = $this->factory->createNamed('name', 'percent', 0.1);
1418
1419 $this->assertWidgetMatchesXpath($form->createView(), array(),
1420'/input
1421 [@type="text"]
1422 [@name="name"]
1423 [@value="10"]
1424 [contains(.., "%")]
1425'
1426 );
1427 }
1428
1429 public function testCheckedRadio()
1430 {
1431 $form = $this->factory->createNamed('name', 'radio', true);
1432
1433 $this->assertWidgetMatchesXpath($form->createView(), array(),
1434'/input
1435 [@type="radio"]
1436 [@name="name"]
1437 [@checked="checked"]
1438 [@value="1"]
1439'
1440 );
1441 }
1442
1443 public function testUncheckedRadio()
1444 {
1445 $form = $this->factory->createNamed('name', 'radio', false);
1446
1447 $this->assertWidgetMatchesXpath($form->createView(), array(),
1448'/input
1449 [@type="radio"]
1450 [@name="name"]
1451 [not(@checked)]
1452'
1453 );
1454 }
1455
1456 public function testRadioWithValue()
1457 {
1458 $form = $this->factory->createNamed('name', 'radio', false, array(
1459 'value' => 'foo&bar',
1460 ));
1461
1462 $this->assertWidgetMatchesXpath($form->createView(), array(),
1463'/input
1464 [@type="radio"]
1465 [@name="name"]
1466 [@value="foo&bar"]
1467'
1468 );
1469 }
1470
1471 public function testTextarea()
1472 {
1473 $form = $this->factory->createNamed('name', 'textarea', 'foo&bar', array(
1474 'pattern' => 'foo',
1475 ));
1476
1477 $this->assertWidgetMatchesXpath($form->createView(), array(),
1478'/textarea
1479 [@name="name"]
1480 [not(@pattern)]
1481 [.="foo&bar"]
1482'
1483 );
1484 }
1485
1486 public function testText()
1487 {
1488 $form = $this->factory->createNamed('name', 'text', 'foo&bar');
1489
1490 $this->assertWidgetMatchesXpath($form->createView(), array(),
1491'/input
1492 [@type="text"]
1493 [@name="name"]
1494 [@value="foo&bar"]
1495 [not(@maxlength)]
1496'
1497 );
1498 }
1499
1500 public function testTextWithMaxLength()
1501 {
1502 $form = $this->factory->createNamed('name', 'text', 'foo&bar', array(
1503 'max_length' => 123,
1504 ));
1505
1506 $this->assertWidgetMatchesXpath($form->createView(), array(),
1507'/input
1508 [@type="text"]
1509 [@name="name"]
1510 [@value="foo&bar"]
1511 [@maxlength="123"]
1512'
1513 );
1514 }
1515
1516 public function testSearch()
1517 {
1518 $form = $this->factory->createNamed('name', 'search', 'foo&bar');
1519
1520 $this->assertWidgetMatchesXpath($form->createView(), array(),
1521'/input
1522 [@type="search"]
1523 [@name="name"]
1524 [@value="foo&bar"]
1525 [not(@maxlength)]
1526'
1527 );
1528 }
1529
1530 public function testTime()
1531 {
1532 $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
1533 'input' => 'string',
1534 'with_seconds' => false,
1535 ));
1536
1537 $this->assertWidgetMatchesXpath($form->createView(), array(),
1538'/div
1539 [
1540 ./select
1541 [@id="name_hour"]
1542 [not(@size)]
1543 [./option[@value="4"][@selected="selected"]]
1544 /following-sibling::select
1545 [@id="name_minute"]
1546 [not(@size)]
1547 [./option[@value="5"][@selected="selected"]]
1548 ]
1549 [count(./select)=2]
1550'
1551 );
1552 }
1553
1554 public function testTimeWithSeconds()
1555 {
1556 $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
1557 'input' => 'string',
1558 'with_seconds' => true,
1559 ));
1560
1561 $this->assertWidgetMatchesXpath($form->createView(), array(),
1562'/div
1563 [
1564 ./select
1565 [@id="name_hour"]
1566 [not(@size)]
1567 [./option[@value="4"][@selected="selected"]]
1568 [count(./option)>23]
1569 /following-sibling::select
1570 [@id="name_minute"]
1571 [not(@size)]
1572 [./option[@value="5"][@selected="selected"]]
1573 [count(./option)>59]
1574 /following-sibling::select
1575 [@id="name_second"]
1576 [not(@size)]
1577 [./option[@value="6"][@selected="selected"]]
1578 [count(./option)>59]
1579 ]
1580 [count(./select)=3]
1581'
1582 );
1583 }
1584
1585 public function testTimeText()
1586 {
1587 $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
1588 'input' => 'string',
1589 'widget' => 'text',
1590 ));
1591
1592 $this->assertWidgetMatchesXpath($form->createView(), array(),
1593'/div
1594 [
1595 ./input
1596 [@type="text"]
1597 [@id="name_hour"]
1598 [@name="name[hour]"]
1599 [@value="04"]
1600 [@size="1"]
1601 [@required="required"]
1602 /following-sibling::input
1603 [@type="text"]
1604 [@id="name_minute"]
1605 [@name="name[minute]"]
1606 [@value="05"]
1607 [@size="1"]
1608 [@required="required"]
1609 ]
1610 [count(./input)=2]
1611'
1612 );
1613 }
1614
1615 public function testTimeSingleText()
1616 {
1617 $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
1618 'input' => 'string',
1619 'widget' => 'single_text',
1620 ));
1621
1622 $this->assertWidgetMatchesXpath($form->createView(), array(),
1623'/input
1624 [@type="time"]
1625 [@name="name"]
1626 [@value="04:05"]
1627 [not(@size)]
1628'
1629 );
1630 }
1631
1632 public function testTimeWithEmptyValueGlobal()
1633 {
1634 $form = $this->factory->createNamed('name', 'time', null, array(
1635 'input' => 'string',
1636 'empty_value' => 'Change&Me',
1637 'required' => false,
1638 ));
1639
1640 $this->assertWidgetMatchesXpath($form->createView(), array(),
1641'/div
1642 [
1643 ./select
1644 [@id="name_hour"]
1645 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1646 [count(./option)>24]
1647 /following-sibling::select
1648 [@id="name_minute"]
1649 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1650 [count(./option)>60]
1651 ]
1652 [count(./select)=2]
1653'
1654 );
1655 }
1656
1657 public function testTimeWithEmptyValueOnYear()
1658 {
1659 $form = $this->factory->createNamed('name', 'time', null, array(
1660 'input' => 'string',
1661 'required' => false,
1662 'empty_value' => array('hour' => 'Change&Me'),
1663 ));
1664
1665 $this->assertWidgetMatchesXpath($form->createView(), array(),
1666'/div
1667 [
1668 ./select
1669 [@id="name_hour"]
1670 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1671 [count(./option)>24]
1672 /following-sibling::select
1673 [@id="name_minute"]
1674 [./option[@value="1"]]
1675 [count(./option)>59]
1676 ]
1677 [count(./select)=2]
1678'
1679 );
1680 }
1681
1682 public function testTimeErrorBubbling()
1683 {
1684 $form = $this->factory->createNamedBuilder('form', 'form')
1685 ->add('time', 'time')
1686 ->getForm();
1687 $form->get('time')->addError(new FormError('[trans]Error![/trans]'));
1688 $view = $form->createView();
1689
1690 $this->assertEmpty($this->renderErrors($view));
1691 $this->assertNotEmpty($this->renderErrors($view['time']));
1692 }
1693
1694 public function testTimezone()
1695 {
1696 $form = $this->factory->createNamed('name', 'timezone', 'Europe/Vienna');
1697
1698 $this->assertWidgetMatchesXpath($form->createView(), array(),
1699'/select
1700 [@name="name"]
1701 [@required="required"]
1702 [./optgroup
1703 [@label="[trans]Europe[/trans]"]
1704 [./option[@value="Europe/Vienna"][@selected="selected"][.="[trans]Vienna[/trans]"]]
1705 ]
1706 [count(./optgroup)>10]
1707 [count(.//option)>200]
1708'
1709 );
1710 }
1711
1712 public function testTimezoneWithEmptyValue()
1713 {
1714 $form = $this->factory->createNamed('name', 'timezone', null, array(
1715 'empty_value' => 'Select&Timezone',
1716 'required' => false,
1717 ));
1718
1719 $this->assertWidgetMatchesXpath($form->createView(), array(),
1720'/select
1721 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Timezone[/trans]"]]
1722 [count(./optgroup)>10]
1723 [count(.//option)>201]
1724'
1725 );
1726 }
1727
1728 public function testUrl()
1729 {
1730 $url = 'http://www.google.com?foo1=bar1&foo2=bar2';
1731 $form = $this->factory->createNamed('name', 'url', $url);
1732
1733 $this->assertWidgetMatchesXpath($form->createView(), array(),
1734'/input
1735 [@type="url"]
1736 [@name="name"]
1737 [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
1738'
1739 );
1740 }
1741
1742 public function testCollectionPrototype()
1743 {
1744 $form = $this->factory->createNamedBuilder('name', 'form', array('items' => array('one', 'two', 'three')))
1745 ->add('items', 'collection', array('allow_add' => true))
1746 ->getForm()
1747 ->createView();
1748
1749 $html = $this->renderWidget($form);
1750
1751 $this->assertMatchesXpath($html,
1752 '//div[@id="name_items"][@data-prototype]
1753 |
1754 //table[@id="name_items"][@data-prototype]'
1755 );
1756 }
1757
1758 public function testEmptyRootFormName()
1759 {
1760 $form = $this->factory->createNamedBuilder('', 'form')
1761 ->add('child', 'text')
1762 ->getForm();
1763
1764 $this->assertMatchesXpath($this->renderWidget($form->createView()),
1765 '//input[@type="hidden"][@id="_token"][@name="_token"]
1766 |
1767 //input[@type="text"][@id="child"][@name="child"]'
1768 , 2);
1769 }
1770
1771 public function testButton()
1772 {
1773 $form = $this->factory->createNamed('name', 'button');
1774
1775 $this->assertWidgetMatchesXpath($form->createView(), array(),
1776 '/button[@type="button"][@name="name"][.="[trans]Name[/trans]"]'
1777 );
1778 }
1779
1780 public function testButtonLabelIsEmpty()
1781 {
1782 $form = $this->factory->createNamed('name', 'button');
1783
1784 $this->assertSame('', $this->renderLabel($form->createView()));
1785 }
1786
1787 public function testSubmit()
1788 {
1789 $form = $this->factory->createNamed('name', 'submit');
1790
1791 $this->assertWidgetMatchesXpath($form->createView(), array(),
1792 '/button[@type="submit"][@name="name"]'
1793 );
1794 }
1795
1796 public function testReset()
1797 {
1798 $form = $this->factory->createNamed('name', 'reset');
1799
1800 $this->assertWidgetMatchesXpath($form->createView(), array(),
1801 '/button[@type="reset"][@name="name"]'
1802 );
1803 }
1804
1805 public function testStartTag()
1806 {
1807 $form = $this->factory->create('form', null, array(
1808 'method' => 'get',
1809 'action' => 'http://example.com/directory'
1810 ));
1811
1812 $html = $this->renderStart($form->createView());
1813
1814 $this->assertSame('<form method="get" action="http://example.com/directory">', $html);
1815 }
1816
1817 public function testStartTagForPutRequest()
1818 {
1819 $form = $this->factory->create('form', null, array(
1820 'method' => 'put',
1821 'action' => 'http://example.com/directory'
1822 ));
1823
1824 $html = $this->renderStart($form->createView());
1825
1826 $this->assertMatchesXpath($html . '</form>',
1827'/form
1828 [./input[@type="hidden"][@name="_method"][@value="PUT"]]
1829 [@method="post"]
1830 [@action="http://example.com/directory"]'
1831 );
1832 }
1833
1834 public function testStartTagWithOverriddenVars()
1835 {
1836 $form = $this->factory->create('form', null, array(
1837 'method' => 'put',
1838 'action' => 'http://example.com/directory',
1839 ));
1840
1841 $html = $this->renderStart($form->createView(), array(
1842 'method' => 'post',
1843 'action' => 'http://foo.com/directory'
1844 ));
1845
1846 $this->assertSame('<form method="post" action="http://foo.com/directory">', $html);
1847 }
1848
1849 public function testStartTagForMultipartForm()
1850 {
1851 $form = $this->factory->createBuilder('form', null, array(
1852 'method' => 'get',
1853 'action' => 'http://example.com/directory'
1854 ))
1855 ->add('file', 'file')
1856 ->getForm();
1857
1858 $html = $this->renderStart($form->createView());
1859
1860 $this->assertSame('<form method="get" action="http://example.com/directory" enctype="multipart/form-data">', $html);
1861 }
1862
1863 public function testStartTagWithExtraAttributes()
1864 {
1865 $form = $this->factory->create('form', null, array(
1866 'method' => 'get',
1867 'action' => 'http://example.com/directory'
1868 ));
1869
1870 $html = $this->renderStart($form->createView(), array(
1871 'attr' => array('class' => 'foobar'),
1872 ));
1873
1874 $this->assertSame('<form method="get" action="http://example.com/directory" class="foobar">', $html);
1875 }
1876}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php
new file mode 100644
index 00000000..cef8f3bf
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php
@@ -0,0 +1,280 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17abstract class AbstractRequestHandlerTest extends \PHPUnit_Framework_TestCase
18{
19 /**
20 * @var \Symfony\Component\Form\RequestHandlerInterface
21 */
22 protected $requestHandler;
23
24 protected $request;
25
26 protected function setUp()
27 {
28 $this->requestHandler = $this->getRequestHandler();
29 $this->request = null;
30 }
31
32 public function methodExceptGetProvider()
33 {
34 return array(
35 array('POST'),
36 array('PUT'),
37 array('DELETE'),
38 array('PATCH'),
39 );
40 }
41
42 public function methodProvider()
43 {
44 return array_merge(array(
45 array('GET'),
46 ), $this->methodExceptGetProvider());
47 }
48
49 /**
50 * @dataProvider methodProvider
51 */
52 public function testSubmitIfNameInRequest($method)
53 {
54 $form = $this->getMockForm('param1', $method);
55
56 $this->setRequestData($method, array(
57 'param1' => 'DATA',
58 ));
59
60 $form->expects($this->once())
61 ->method('submit')
62 ->with('DATA', 'PATCH' !== $method);
63
64 $this->requestHandler->handleRequest($form, $this->request);
65 }
66
67 /**
68 * @dataProvider methodProvider
69 */
70 public function testDoNotSubmitIfWrongRequestMethod($method)
71 {
72 $form = $this->getMockForm('param1', $method);
73
74 $otherMethod = 'POST' === $method ? 'PUT' : 'POST';
75
76 $this->setRequestData($otherMethod, array(
77 'param1' => 'DATA',
78 ));
79
80 $form->expects($this->never())
81 ->method('submit');
82
83 $this->requestHandler->handleRequest($form, $this->request);
84 }
85
86 /**
87 * @dataProvider methodExceptGetProvider
88 */
89 public function testSubmitSimpleFormWithNullIfNameNotInRequestAndNotGetRequest($method)
90 {
91 $form = $this->getMockForm('param1', $method, false);
92
93 $this->setRequestData($method, array(
94 'paramx' => array(),
95 ));
96
97 $form->expects($this->once())
98 ->method('submit')
99 ->with($this->identicalTo(null), 'PATCH' !== $method);
100
101 $this->requestHandler->handleRequest($form, $this->request);
102 }
103
104 /**
105 * @dataProvider methodExceptGetProvider
106 */
107 public function testSubmitCompoundFormWithArrayIfNameNotInRequestAndNotGetRequest($method)
108 {
109 $form = $this->getMockForm('param1', $method, true);
110
111 $this->setRequestData($method, array(
112 'paramx' => array(),
113 ));
114
115 $form->expects($this->once())
116 ->method('submit')
117 ->with($this->identicalTo(array()), 'PATCH' !== $method);
118
119 $this->requestHandler->handleRequest($form, $this->request);
120 }
121
122 public function testDoNotSubmitIfNameNotInRequestAndGetRequest()
123 {
124 $form = $this->getMockForm('param1', 'GET');
125
126 $this->setRequestData('GET', array(
127 'paramx' => array(),
128 ));
129
130 $form->expects($this->never())
131 ->method('submit');
132
133 $this->requestHandler->handleRequest($form, $this->request);
134 }
135
136 /**
137 * @dataProvider methodProvider
138 */
139 public function testSubmitFormWithEmptyNameIfAtLeastOneFieldInRequest($method)
140 {
141 $form = $this->getMockForm('', $method);
142 $form->expects($this->any())
143 ->method('all')
144 ->will($this->returnValue(array(
145 'param1' => $this->getMockForm('param1'),
146 'param2' => $this->getMockForm('param2'),
147 )));
148
149 $this->setRequestData($method, $requestData = array(
150 'param1' => 'submitted value',
151 'paramx' => 'submitted value',
152 ));
153
154 $form->expects($this->once())
155 ->method('submit')
156 ->with($requestData, 'PATCH' !== $method);
157
158 $this->requestHandler->handleRequest($form, $this->request);
159 }
160
161 /**
162 * @dataProvider methodProvider
163 */
164 public function testDoNotSubmitFormWithEmptyNameIfNoFieldInRequest($method)
165 {
166 $form = $this->getMockForm('', $method);
167 $form->expects($this->any())
168 ->method('all')
169 ->will($this->returnValue(array(
170 'param1' => $this->getMockForm('param1'),
171 'param2' => $this->getMockForm('param2'),
172 )));
173
174 $this->setRequestData($method, array(
175 'paramx' => 'submitted value',
176 ));
177
178 $form->expects($this->never())
179 ->method('submit');
180
181 $this->requestHandler->handleRequest($form, $this->request);
182 }
183
184 /**
185 * @dataProvider methodExceptGetProvider
186 */
187 public function testMergeParamsAndFiles($method)
188 {
189 $form = $this->getMockForm('param1', $method);
190 $file = $this->getMockFile();
191
192 $this->setRequestData($method, array(
193 'param1' => array(
194 'field1' => 'DATA',
195 ),
196 ), array(
197 'param1' => array(
198 'field2' => $file,
199 ),
200 ));
201
202 $form->expects($this->once())
203 ->method('submit')
204 ->with(array(
205 'field1' => 'DATA',
206 'field2' => $file,
207 ), 'PATCH' !== $method);
208
209 $this->requestHandler->handleRequest($form, $this->request);
210 }
211
212 /**
213 * @dataProvider methodExceptGetProvider
214 */
215 public function testParamTakesPrecedenceOverFile($method)
216 {
217 $form = $this->getMockForm('param1', $method);
218 $file = $this->getMockFile();
219
220 $this->setRequestData($method, array(
221 'param1' => 'DATA',
222 ), array(
223 'param1' => $file,
224 ));
225
226 $form->expects($this->once())
227 ->method('submit')
228 ->with('DATA', 'PATCH' !== $method);
229
230 $this->requestHandler->handleRequest($form, $this->request);
231 }
232
233 /**
234 * @dataProvider methodExceptGetProvider
235 */
236 public function testSubmitFileIfNoParam($method)
237 {
238 $form = $this->getMockForm('param1', $method);
239 $file = $this->getMockFile();
240
241 $this->setRequestData($method, array(
242 'param1' => null,
243 ), array(
244 'param1' => $file,
245 ));
246
247 $form->expects($this->once())
248 ->method('submit')
249 ->with($file, 'PATCH' !== $method);
250
251 $this->requestHandler->handleRequest($form, $this->request);
252 }
253
254 abstract protected function setRequestData($method, $data, $files = array());
255
256 abstract protected function getRequestHandler();
257
258 abstract protected function getMockFile();
259
260 protected function getMockForm($name, $method = null, $compound = true)
261 {
262 $config = $this->getMock('Symfony\Component\Form\FormConfigInterface');
263 $config->expects($this->any())
264 ->method('getMethod')
265 ->will($this->returnValue($method));
266 $config->expects($this->any())
267 ->method('getCompound')
268 ->will($this->returnValue($compound));
269
270 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
271 $form->expects($this->any())
272 ->method('getName')
273 ->will($this->returnValue($name));
274 $form->expects($this->any())
275 ->method('getConfig')
276 ->will($this->returnValue($config));
277
278 return $form;
279 }
280}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php
new file mode 100644
index 00000000..5c911951
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php
@@ -0,0 +1,509 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\FormError;
15
16abstract class AbstractTableLayoutTest extends AbstractLayoutTest
17{
18 public function testRow()
19 {
20 $form = $this->factory->createNamed('name', 'text');
21 $form->addError(new FormError('[trans]Error![/trans]'));
22 $view = $form->createView();
23 $html = $this->renderRow($view);
24
25 $this->assertMatchesXpath($html,
26'/tr
27 [
28 ./td
29 [./label[@for="name"]]
30 /following-sibling::td
31 [
32 ./ul
33 [./li[.="[trans]Error![/trans]"]]
34 [count(./li)=1]
35 /following-sibling::input[@id="name"]
36 ]
37 ]
38'
39 );
40 }
41
42 public function testLabelIsNotRenderedWhenSetToFalse()
43 {
44 $form = $this->factory->createNamed('name', 'text', null, array(
45 'label' => false
46 ));
47 $html = $this->renderRow($form->createView());
48
49 $this->assertMatchesXpath($html,
50'/tr
51 [
52 ./td
53 [count(//label)=0]
54 /following-sibling::td
55 [./input[@id="name"]]
56 ]
57'
58 );
59 }
60
61 public function testRepeatedRow()
62 {
63 $form = $this->factory->createNamed('name', 'repeated');
64 $html = $this->renderRow($form->createView());
65
66 $this->assertMatchesXpath($html,
67'/tr
68 [
69 ./td
70 [./label[@for="name_first"]]
71 /following-sibling::td
72 [./input[@id="name_first"]]
73 ]
74/following-sibling::tr
75 [
76 ./td
77 [./label[@for="name_second"]]
78 /following-sibling::td
79 [./input[@id="name_second"]]
80 ]
81/following-sibling::tr[@style="display: none"]
82 [./td[@colspan="2"]/input
83 [@type="hidden"]
84 [@id="name__token"]
85 ]
86 [count(../tr)=3]
87'
88 );
89 }
90
91 public function testRepeatedRowWithErrors()
92 {
93 $form = $this->factory->createNamed('name', 'repeated');
94 $form->addError(new FormError('[trans]Error![/trans]'));
95 $view = $form->createView();
96 $html = $this->renderRow($view);
97
98 // The errors of the form are not rendered by intention!
99 // In practice, repeated fields cannot have errors as all errors
100 // on them are mapped to the first child.
101 // (see RepeatedTypeValidatorExtension)
102
103 $this->assertMatchesXpath($html,
104'/tr
105 [
106 ./td
107 [./label[@for="name_first"]]
108 /following-sibling::td
109 [./input[@id="name_first"]]
110 ]
111/following-sibling::tr
112 [
113 ./td
114 [./label[@for="name_second"]]
115 /following-sibling::td
116 [./input[@id="name_second"]]
117 ]
118/following-sibling::tr[@style="display: none"]
119 [./td[@colspan="2"]/input
120 [@type="hidden"]
121 [@id="name__token"]
122 ]
123 [count(../tr)=3]
124'
125 );
126 }
127
128 public function testButtonRow()
129 {
130 $form = $this->factory->createNamed('name', 'button');
131 $view = $form->createView();
132 $html = $this->renderRow($view);
133
134 $this->assertMatchesXpath($html,
135'/tr
136 [
137 ./td
138 [.=""]
139 /following-sibling::td
140 [./button[@type="button"][@name="name"]]
141 ]
142 [count(//label)=0]
143'
144 );
145 }
146
147 public function testRest()
148 {
149 $view = $this->factory->createNamedBuilder('name', 'form')
150 ->add('field1', 'text')
151 ->add('field2', 'repeated')
152 ->add('field3', 'text')
153 ->add('field4', 'text')
154 ->getForm()
155 ->createView();
156
157 // Render field2 row -> does not implicitly call renderWidget because
158 // it is a repeated field!
159 $this->renderRow($view['field2']);
160
161 // Render field3 widget
162 $this->renderWidget($view['field3']);
163
164 // Rest should only contain field1 and field4
165 $html = $this->renderRest($view);
166
167 $this->assertMatchesXpath($html,
168'/tr
169 [
170 ./td
171 [./label[@for="name_field1"]]
172 /following-sibling::td
173 [./input[@id="name_field1"]]
174 ]
175/following-sibling::tr
176 [
177 ./td
178 [./label[@for="name_field4"]]
179 /following-sibling::td
180 [./input[@id="name_field4"]]
181 ]
182 [count(../tr)=3]
183 [count(..//label)=2]
184 [count(..//input)=3]
185/following-sibling::tr[@style="display: none"]
186 [./td[@colspan="2"]/input
187 [@type="hidden"]
188 [@id="name__token"]
189 ]
190'
191 );
192 }
193
194 public function testCollection()
195 {
196 $form = $this->factory->createNamed('name', 'collection', array('a', 'b'), array(
197 'type' => 'text',
198 ));
199
200 $this->assertWidgetMatchesXpath($form->createView(), array(),
201'/table
202 [
203 ./tr[./td/input[@type="text"][@value="a"]]
204 /following-sibling::tr[./td/input[@type="text"][@value="b"]]
205 /following-sibling::tr[@style="display: none"][./td[@colspan="2"]/input[@type="hidden"][@id="name__token"]]
206 ]
207 [count(./tr[./td/input])=3]
208'
209 );
210 }
211
212 public function testEmptyCollection()
213 {
214 $form = $this->factory->createNamed('name', 'collection', array(), array(
215 'type' => 'text',
216 ));
217
218 $this->assertWidgetMatchesXpath($form->createView(), array(),
219'/table
220 [./tr[@style="display: none"][./td[@colspan="2"]/input[@type="hidden"][@id="name__token"]]]
221 [count(./tr[./td/input])=1]
222'
223 );
224 }
225
226 public function testForm()
227 {
228 $view = $this->factory->createNamedBuilder('name', 'form')
229 ->setMethod('PUT')
230 ->setAction('http://example.com')
231 ->add('firstName', 'text')
232 ->add('lastName', 'text')
233 ->getForm()
234 ->createView();
235
236 $html = $this->renderForm($view, array(
237 'id' => 'my&id',
238 'attr' => array('class' => 'my&class'),
239 ));
240
241 $this->assertMatchesXpath($html,
242'/form
243 [
244 ./input[@type="hidden"][@name="_method"][@value="PUT"]
245 /following-sibling::table
246 [
247 ./tr
248 [
249 ./td
250 [./label[@for="name_firstName"]]
251 /following-sibling::td
252 [./input[@id="name_firstName"]]
253 ]
254 /following-sibling::tr
255 [
256 ./td
257 [./label[@for="name_lastName"]]
258 /following-sibling::td
259 [./input[@id="name_lastName"]]
260 ]
261 /following-sibling::tr[@style="display: none"]
262 [./td[@colspan="2"]/input
263 [@type="hidden"]
264 [@id="name__token"]
265 ]
266 ]
267 [count(.//input)=3]
268 [@id="my&id"]
269 [@class="my&class"]
270 ]
271 [@method="post"]
272 [@action="http://example.com"]
273 [@class="my&class"]
274'
275 );
276 }
277
278 public function testFormWidget()
279 {
280 $view = $this->factory->createNamedBuilder('name', 'form')
281 ->add('firstName', 'text')
282 ->add('lastName', 'text')
283 ->getForm()
284 ->createView();
285
286 $this->assertWidgetMatchesXpath($view, array(),
287'/table
288 [
289 ./tr
290 [
291 ./td
292 [./label[@for="name_firstName"]]
293 /following-sibling::td
294 [./input[@id="name_firstName"]]
295 ]
296 /following-sibling::tr
297 [
298 ./td
299 [./label[@for="name_lastName"]]
300 /following-sibling::td
301 [./input[@id="name_lastName"]]
302 ]
303 /following-sibling::tr[@style="display: none"]
304 [./td[@colspan="2"]/input
305 [@type="hidden"]
306 [@id="name__token"]
307 ]
308 ]
309 [count(.//input)=3]
310'
311 );
312 }
313
314 // https://github.com/symfony/symfony/issues/2308
315 public function testNestedFormError()
316 {
317 $form = $this->factory->createNamedBuilder('name', 'form')
318 ->add($this->factory
319 ->createNamedBuilder('child', 'form', null, array('error_bubbling' => false))
320 ->add('grandChild', 'form')
321 )
322 ->getForm();
323
324 $form->get('child')->addError(new FormError('[trans]Error![/trans]'));
325
326 $this->assertWidgetMatchesXpath($form->createView(), array(),
327'/table
328 [
329 ./tr/td/ul[./li[.="[trans]Error![/trans]"]]
330 /following-sibling::table[@id="name_child"]
331 ]
332 [count(.//li[.="[trans]Error![/trans]"])=1]
333'
334 );
335 }
336
337 public function testCsrf()
338 {
339 $this->csrfProvider->expects($this->any())
340 ->method('generateCsrfToken')
341 ->will($this->returnValue('foo&bar'));
342
343 $form = $this->factory->createNamedBuilder('name', 'form')
344 ->add($this->factory
345 // No CSRF protection on nested forms
346 ->createNamedBuilder('child', 'form')
347 ->add($this->factory->createNamedBuilder('grandchild', 'text'))
348 )
349 ->getForm();
350
351 $this->assertWidgetMatchesXpath($form->createView(), array(),
352'/table
353 [
354 ./tr[@style="display: none"]
355 [./td[@colspan="2"]/input
356 [@type="hidden"]
357 [@id="name__token"]
358 ]
359 ]
360 [count(.//input[@type="hidden"])=1]
361'
362 );
363 }
364
365 public function testRepeated()
366 {
367 $form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
368 'type' => 'text',
369 ));
370
371 $this->assertWidgetMatchesXpath($form->createView(), array(),
372'/table
373 [
374 ./tr
375 [
376 ./td
377 [./label[@for="name_first"]]
378 /following-sibling::td
379 [./input[@type="text"][@id="name_first"]]
380 ]
381 /following-sibling::tr
382 [
383 ./td
384 [./label[@for="name_second"]]
385 /following-sibling::td
386 [./input[@type="text"][@id="name_second"]]
387 ]
388 /following-sibling::tr[@style="display: none"]
389 [./td[@colspan="2"]/input
390 [@type="hidden"]
391 [@id="name__token"]
392 ]
393 ]
394 [count(.//input)=3]
395'
396 );
397 }
398
399 public function testRepeatedWithCustomOptions()
400 {
401 $form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
402 'type' => 'password',
403 'first_options' => array('label' => 'Test', 'required' => false),
404 'second_options' => array('label' => 'Test2')
405 ));
406
407 $this->assertWidgetMatchesXpath($form->createView(), array(),
408'/table
409 [
410 ./tr
411 [
412 ./td
413 [./label[@for="name_first"][.="[trans]Test[/trans]"]]
414 /following-sibling::td
415 [./input[@type="password"][@id="name_first"][@required="required"]]
416 ]
417 /following-sibling::tr
418 [
419 ./td
420 [./label[@for="name_second"][.="[trans]Test2[/trans]"]]
421 /following-sibling::td
422 [./input[@type="password"][@id="name_second"][@required="required"]]
423 ]
424 /following-sibling::tr[@style="display: none"]
425 [./td[@colspan="2"]/input
426 [@type="hidden"]
427 [@id="name__token"]
428 ]
429 ]
430 [count(.//input)=3]
431'
432 );
433 }
434
435 /**
436 * The block "_name_child_label" should be overridden in the theme of the
437 * implemented driver.
438 */
439 public function testCollectionRowWithCustomBlock()
440 {
441 $collection = array('one', 'two', 'three');
442 $form = $this->factory->createNamedBuilder('name', 'collection', $collection)
443 ->getForm();
444
445 $this->assertWidgetMatchesXpath($form->createView(), array(),
446'/table
447 [
448 ./tr[./td/label[.="Custom label: [trans]0[/trans]"]]
449 /following-sibling::tr[./td/label[.="Custom label: [trans]1[/trans]"]]
450 /following-sibling::tr[./td/label[.="Custom label: [trans]2[/trans]"]]
451 ]
452'
453 );
454 }
455
456 public function testFormEndWithRest()
457 {
458 $view = $this->factory->createNamedBuilder('name', 'form')
459 ->add('field1', 'text')
460 ->add('field2', 'text')
461 ->getForm()
462 ->createView();
463
464 $this->renderWidget($view['field1']);
465
466 // Rest should only contain field2
467 $html = $this->renderEnd($view);
468
469 // Insert the start tag, the end tag should be rendered by the helper
470 // Unfortunately this is not valid HTML, because the surrounding table
471 // tag is missing. If someone renders a form with table layout
472 // manually, she should call form_rest() explicitly within the <table>
473 // tag.
474 $this->assertMatchesXpath('<form>' . $html,
475'/form
476 [
477 ./tr
478 [
479 ./td
480 [./label[@for="name_field2"]]
481 /following-sibling::td
482 [./input[@id="name_field2"]]
483 ]
484 /following-sibling::tr[@style="display: none"]
485 [./td[@colspan="2"]/input
486 [@type="hidden"]
487 [@id="name__token"]
488 ]
489 ]
490'
491 );
492 }
493
494 public function testFormEndWithoutRest()
495 {
496 $view = $this->factory->createNamedBuilder('name', 'form')
497 ->add('field1', 'text')
498 ->add('field2', 'text')
499 ->getForm()
500 ->createView();
501
502 $this->renderWidget($view['field1']);
503
504 // Rest should only contain field2, but isn't rendered
505 $html = $this->renderEnd($view, array('render_rest' => false));
506
507 $this->assertEquals('</form>', $html);
508 }
509}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/CompoundFormPerformanceTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/CompoundFormPerformanceTest.php
new file mode 100644
index 00000000..73c602c5
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/CompoundFormPerformanceTest.php
@@ -0,0 +1,48 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class CompoundFormPerformanceTest extends \Symfony\Component\Form\Tests\FormPerformanceTestCase
18{
19 /**
20 * Create a compound form multiple times, as happens in a collection form
21 *
22 * @group benchmark
23 */
24 public function testArrayBasedForm()
25 {
26 $this->setMaxRunningTime(1);
27
28 for ($i = 0; $i < 40; ++$i) {
29 $form = $this->factory->createBuilder('form')
30 ->add('firstName', 'text')
31 ->add('lastName', 'text')
32 ->add('gender', 'choice', array(
33 'choices' => array('male' => 'Male', 'female' => 'Female'),
34 'required' => false,
35 ))
36 ->add('age', 'number')
37 ->add('birthDate', 'birthday')
38 ->add('city', 'choice', array(
39 // simulate 300 different cities
40 'choices' => range(1, 300),
41 ))
42 ->getForm();
43
44 // load the form into a view
45 $form->createView();
46 }
47 }
48}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/CompoundFormTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/CompoundFormTest.php
new file mode 100644
index 00000000..b240d2d0
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/CompoundFormTest.php
@@ -0,0 +1,759 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
15use Symfony\Component\Form\FormError;
16use Symfony\Component\HttpFoundation\Request;
17use Symfony\Component\HttpFoundation\File\UploadedFile;
18use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
19
20class CompoundFormTest extends AbstractFormTest
21{
22 public function testValidIfAllChildrenAreValid()
23 {
24 $this->form->add($this->getValidForm('firstName'));
25 $this->form->add($this->getValidForm('lastName'));
26
27 $this->form->submit(array(
28 'firstName' => 'Bernhard',
29 'lastName' => 'Schussek',
30 ));
31
32 $this->assertTrue($this->form->isValid());
33 }
34
35 public function testInvalidIfChildIsInvalid()
36 {
37 $this->form->add($this->getValidForm('firstName'));
38 $this->form->add($this->getInvalidForm('lastName'));
39
40 $this->form->submit(array(
41 'firstName' => 'Bernhard',
42 'lastName' => 'Schussek',
43 ));
44
45 $this->assertFalse($this->form->isValid());
46 }
47
48 public function testSubmitForwardsNullIfValueIsMissing()
49 {
50 $child = $this->getMockForm('firstName');
51
52 $this->form->add($child);
53
54 $child->expects($this->once())
55 ->method('submit')
56 ->with($this->equalTo(null));
57
58 $this->form->submit(array());
59 }
60
61 public function testSubmitDoesNotForwardNullIfNotClearMissing()
62 {
63 $child = $this->getMockForm('firstName');
64
65 $this->form->add($child);
66
67 $child->expects($this->never())
68 ->method('submit');
69
70 $this->form->submit(array(), false);
71 }
72
73 public function testClearMissingFlagIsForwarded()
74 {
75 $child = $this->getMockForm('firstName');
76
77 $this->form->add($child);
78
79 $child->expects($this->once())
80 ->method('submit')
81 ->with($this->equalTo('foo'), false);
82
83 $this->form->submit(array('firstName' => 'foo'), false);
84 }
85
86 public function testCloneChildren()
87 {
88 $child = $this->getBuilder('child')->getForm();
89 $this->form->add($child);
90
91 $clone = clone $this->form;
92
93 $this->assertNotSame($this->form, $clone);
94 $this->assertNotSame($child, $clone['child']);
95 }
96
97 public function testNotEmptyIfChildNotEmpty()
98 {
99 $child = $this->getMockForm();
100 $child->expects($this->once())
101 ->method('isEmpty')
102 ->will($this->returnValue(false));
103
104 $this->form->setData(null);
105 $this->form->add($child);
106
107 $this->assertFalse($this->form->isEmpty());
108 }
109
110 public function testValidIfSubmittedAndDisabledWithChildren()
111 {
112 $this->factory->expects($this->once())
113 ->method('createNamedBuilder')
114 ->with('name', 'text', null, array())
115 ->will($this->returnValue($this->getBuilder('name')));
116
117 $form = $this->getBuilder('person')
118 ->setDisabled(true)
119 ->setCompound(true)
120 ->setDataMapper($this->getDataMapper())
121 ->add('name', 'text')
122 ->getForm();
123 $form->submit(array('name' => 'Jacques Doe'));
124
125 $this->assertTrue($form->isValid());
126 }
127
128 public function testNotValidIfChildNotValid()
129 {
130 $child = $this->getMockForm();
131 $child->expects($this->once())
132 ->method('isValid')
133 ->will($this->returnValue(false));
134
135 $this->form->add($child);
136 $this->form->submit(array());
137
138 $this->assertFalse($this->form->isValid());
139 }
140
141 public function testAdd()
142 {
143 $child = $this->getBuilder('foo')->getForm();
144 $this->form->add($child);
145
146 $this->assertTrue($this->form->has('foo'));
147 $this->assertSame($this->form, $child->getParent());
148 $this->assertSame(array('foo' => $child), $this->form->all());
149 }
150
151 public function testAddUsingNameAndType()
152 {
153 $child = $this->getBuilder('foo')->getForm();
154
155 $this->factory->expects($this->once())
156 ->method('createNamed')
157 ->with('foo', 'text', null, array(
158 'bar' => 'baz',
159 'auto_initialize' => false,
160 ))
161 ->will($this->returnValue($child));
162
163 $this->form->add('foo', 'text', array('bar' => 'baz'));
164
165 $this->assertTrue($this->form->has('foo'));
166 $this->assertSame($this->form, $child->getParent());
167 $this->assertSame(array('foo' => $child), $this->form->all());
168 }
169
170 public function testAddUsingIntegerNameAndType()
171 {
172 $child = $this->getBuilder(0)->getForm();
173
174 $this->factory->expects($this->once())
175 ->method('createNamed')
176 ->with('0', 'text', null, array(
177 'bar' => 'baz',
178 'auto_initialize' => false,
179 ))
180 ->will($this->returnValue($child));
181
182 // in order to make casting unnecessary
183 $this->form->add(0, 'text', array('bar' => 'baz'));
184
185 $this->assertTrue($this->form->has(0));
186 $this->assertSame($this->form, $child->getParent());
187 $this->assertSame(array(0 => $child), $this->form->all());
188 }
189
190 public function testAddUsingNameButNoType()
191 {
192 $this->form = $this->getBuilder('name', null, '\stdClass')
193 ->setCompound(true)
194 ->setDataMapper($this->getDataMapper())
195 ->getForm();
196
197 $child = $this->getBuilder('foo')->getForm();
198
199 $this->factory->expects($this->once())
200 ->method('createForProperty')
201 ->with('\stdClass', 'foo')
202 ->will($this->returnValue($child));
203
204 $this->form->add('foo');
205
206 $this->assertTrue($this->form->has('foo'));
207 $this->assertSame($this->form, $child->getParent());
208 $this->assertSame(array('foo' => $child), $this->form->all());
209 }
210
211 public function testAddUsingNameButNoTypeAndOptions()
212 {
213 $this->form = $this->getBuilder('name', null, '\stdClass')
214 ->setCompound(true)
215 ->setDataMapper($this->getDataMapper())
216 ->getForm();
217
218 $child = $this->getBuilder('foo')->getForm();
219
220 $this->factory->expects($this->once())
221 ->method('createForProperty')
222 ->with('\stdClass', 'foo', null, array(
223 'bar' => 'baz',
224 'auto_initialize' => false,
225 ))
226 ->will($this->returnValue($child));
227
228 $this->form->add('foo', null, array('bar' => 'baz'));
229
230 $this->assertTrue($this->form->has('foo'));
231 $this->assertSame($this->form, $child->getParent());
232 $this->assertSame(array('foo' => $child), $this->form->all());
233 }
234
235 /**
236 * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
237 */
238 public function testAddThrowsExceptionIfAlreadySubmitted()
239 {
240 $this->form->submit(array());
241 $this->form->add($this->getBuilder('foo')->getForm());
242 }
243
244 public function testRemove()
245 {
246 $child = $this->getBuilder('foo')->getForm();
247 $this->form->add($child);
248 $this->form->remove('foo');
249
250 $this->assertNull($child->getParent());
251 $this->assertCount(0, $this->form);
252 }
253
254 /**
255 * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
256 */
257 public function testRemoveThrowsExceptionIfAlreadySubmitted()
258 {
259 $this->form->add($this->getBuilder('foo')->setCompound(false)->getForm());
260 $this->form->submit(array('foo' => 'bar'));
261 $this->form->remove('foo');
262 }
263
264 public function testRemoveIgnoresUnknownName()
265 {
266 $this->form->remove('notexisting');
267 }
268
269 public function testArrayAccess()
270 {
271 $child = $this->getBuilder('foo')->getForm();
272
273 $this->form[] = $child;
274
275 $this->assertTrue(isset($this->form['foo']));
276 $this->assertSame($child, $this->form['foo']);
277
278 unset($this->form['foo']);
279
280 $this->assertFalse(isset($this->form['foo']));
281 }
282
283 public function testCountable()
284 {
285 $this->form->add($this->getBuilder('foo')->getForm());
286 $this->form->add($this->getBuilder('bar')->getForm());
287
288 $this->assertCount(2, $this->form);
289 }
290
291 public function testIterator()
292 {
293 $this->form->add($this->getBuilder('foo')->getForm());
294 $this->form->add($this->getBuilder('bar')->getForm());
295
296 $this->assertSame($this->form->all(), iterator_to_array($this->form));
297 }
298
299 public function testAddMapsViewDataToFormIfInitialized()
300 {
301 $test = $this;
302 $mapper = $this->getDataMapper();
303 $form = $this->getBuilder()
304 ->setCompound(true)
305 ->setDataMapper($mapper)
306 ->addViewTransformer(new FixedDataTransformer(array(
307 '' => '',
308 'foo' => 'bar',
309 )))
310 ->setData('foo')
311 ->getForm();
312
313 $child = $this->getBuilder()->getForm();
314 $mapper->expects($this->once())
315 ->method('mapDataToForms')
316 ->with('bar', $this->isInstanceOf('\RecursiveIteratorIterator'))
317 ->will($this->returnCallback(function ($data, \RecursiveIteratorIterator $iterator) use ($child, $test) {
318 $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
319 $test->assertSame(array($child), iterator_to_array($iterator));
320 }));
321
322 $form->initialize();
323 $form->add($child);
324 }
325
326 public function testAddDoesNotMapViewDataToFormIfNotInitialized()
327 {
328 $mapper = $this->getDataMapper();
329 $form = $this->getBuilder()
330 ->setCompound(true)
331 ->setDataMapper($mapper)
332 ->getForm();
333
334 $child = $this->getBuilder()->getForm();
335 $mapper->expects($this->never())
336 ->method('mapDataToForms');
337
338 $form->add($child);
339 }
340
341 public function testAddDoesNotMapViewDataToFormIfInheritData()
342 {
343 $mapper = $this->getDataMapper();
344 $form = $this->getBuilder()
345 ->setCompound(true)
346 ->setDataMapper($mapper)
347 ->setInheritData(true)
348 ->getForm();
349
350 $child = $this->getBuilder()->getForm();
351 $mapper->expects($this->never())
352 ->method('mapDataToForms');
353
354 $form->initialize();
355 $form->add($child);
356 }
357
358 public function testSetDataMapsViewDataToChildren()
359 {
360 $test = $this;
361 $mapper = $this->getDataMapper();
362 $form = $this->getBuilder()
363 ->setCompound(true)
364 ->setDataMapper($mapper)
365 ->addViewTransformer(new FixedDataTransformer(array(
366 '' => '',
367 'foo' => 'bar',
368 )))
369 ->getForm();
370
371 $form->add($child1 = $this->getBuilder('firstName')->getForm());
372 $form->add($child2 = $this->getBuilder('lastName')->getForm());
373
374 $mapper->expects($this->once())
375 ->method('mapDataToForms')
376 ->with('bar', $this->isInstanceOf('\RecursiveIteratorIterator'))
377 ->will($this->returnCallback(function ($data, \RecursiveIteratorIterator $iterator) use ($child1, $child2, $test) {
378 $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
379 $test->assertSame(array('firstName' => $child1, 'lastName' => $child2), iterator_to_array($iterator));
380 }));
381
382 $form->setData('foo');
383 }
384
385 public function testSubmitMapsSubmittedChildrenOntoExistingViewData()
386 {
387 $test = $this;
388 $mapper = $this->getDataMapper();
389 $form = $this->getBuilder()
390 ->setCompound(true)
391 ->setDataMapper($mapper)
392 ->addViewTransformer(new FixedDataTransformer(array(
393 '' => '',
394 'foo' => 'bar',
395 )))
396 ->setData('foo')
397 ->getForm();
398
399 $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->getForm());
400 $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->getForm());
401
402 $mapper->expects($this->once())
403 ->method('mapFormsToData')
404 ->with($this->isInstanceOf('\RecursiveIteratorIterator'), 'bar')
405 ->will($this->returnCallback(function (\RecursiveIteratorIterator $iterator) use ($child1, $child2, $test) {
406 $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
407 $test->assertSame(array('firstName' => $child1, 'lastName' => $child2), iterator_to_array($iterator));
408 $test->assertEquals('Bernhard', $child1->getData());
409 $test->assertEquals('Schussek', $child2->getData());
410 }));
411
412 $form->submit(array(
413 'firstName' => 'Bernhard',
414 'lastName' => 'Schussek',
415 ));
416 }
417
418 public function testMapFormsToDataIsNotInvokedIfInheritData()
419 {
420 $mapper = $this->getDataMapper();
421 $form = $this->getBuilder()
422 ->setCompound(true)
423 ->setDataMapper($mapper)
424 ->setInheritData(true)
425 ->addViewTransformer(new FixedDataTransformer(array(
426 '' => '',
427 'foo' => 'bar',
428 )))
429 ->getForm();
430
431 $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->getForm());
432 $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->getForm());
433
434 $mapper->expects($this->never())
435 ->method('mapFormsToData');
436
437 $form->submit(array(
438 'firstName' => 'Bernhard',
439 'lastName' => 'Schussek',
440 ));
441 }
442
443 /*
444 * https://github.com/symfony/symfony/issues/4480
445 */
446 public function testSubmitRestoresViewDataIfCompoundAndEmpty()
447 {
448 $mapper = $this->getDataMapper();
449 $object = new \stdClass();
450 $form = $this->getBuilder('name', null, 'stdClass')
451 ->setCompound(true)
452 ->setDataMapper($mapper)
453 ->setData($object)
454 ->getForm();
455
456 $form->submit(array());
457
458 $this->assertSame($object, $form->getData());
459 }
460
461 public function testSubmitMapsSubmittedChildrenOntoEmptyData()
462 {
463 $test = $this;
464 $mapper = $this->getDataMapper();
465 $object = new \stdClass();
466 $form = $this->getBuilder()
467 ->setCompound(true)
468 ->setDataMapper($mapper)
469 ->setEmptyData($object)
470 ->setData(null)
471 ->getForm();
472
473 $form->add($child = $this->getBuilder('name')->setCompound(false)->getForm());
474
475 $mapper->expects($this->once())
476 ->method('mapFormsToData')
477 ->with($this->isInstanceOf('\RecursiveIteratorIterator'), $object)
478 ->will($this->returnCallback(function (\RecursiveIteratorIterator $iterator) use ($child, $test) {
479 $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
480 $test->assertSame(array('name' => $child), iterator_to_array($iterator));
481 }));
482
483 $form->submit(array(
484 'name' => 'Bernhard',
485 ));
486 }
487
488 public function requestMethodProvider()
489 {
490 return array(
491 array('POST'),
492 array('PUT'),
493 array('DELETE'),
494 array('PATCH'),
495 );
496 }
497
498 /**
499 * @dataProvider requestMethodProvider
500 */
501 public function testSubmitPostOrPutRequest($method)
502 {
503 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
504 $this->markTestSkipped('The "HttpFoundation" component is not available');
505 }
506
507 $path = tempnam(sys_get_temp_dir(), 'sf2');
508 touch($path);
509
510 $values = array(
511 'author' => array(
512 'name' => 'Bernhard',
513 'image' => array('filename' => 'foobar.png'),
514 ),
515 );
516
517 $files = array(
518 'author' => array(
519 'error' => array('image' => UPLOAD_ERR_OK),
520 'name' => array('image' => 'upload.png'),
521 'size' => array('image' => 123),
522 'tmp_name' => array('image' => $path),
523 'type' => array('image' => 'image/png'),
524 ),
525 );
526
527 $request = new Request(array(), $values, array(), array(), $files, array(
528 'REQUEST_METHOD' => $method,
529 ));
530
531 $form = $this->getBuilder('author')
532 ->setMethod($method)
533 ->setCompound(true)
534 ->setDataMapper($this->getDataMapper())
535 ->setRequestHandler(new HttpFoundationRequestHandler())
536 ->getForm();
537 $form->add($this->getBuilder('name')->getForm());
538 $form->add($this->getBuilder('image')->getForm());
539
540 $form->handleRequest($request);
541
542 $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
543
544 $this->assertEquals('Bernhard', $form['name']->getData());
545 $this->assertEquals($file, $form['image']->getData());
546
547 unlink($path);
548 }
549
550 /**
551 * @dataProvider requestMethodProvider
552 */
553 public function testSubmitPostOrPutRequestWithEmptyRootFormName($method)
554 {
555 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
556 $this->markTestSkipped('The "HttpFoundation" component is not available');
557 }
558
559 $path = tempnam(sys_get_temp_dir(), 'sf2');
560 touch($path);
561
562 $values = array(
563 'name' => 'Bernhard',
564 'extra' => 'data',
565 );
566
567 $files = array(
568 'image' => array(
569 'error' => UPLOAD_ERR_OK,
570 'name' => 'upload.png',
571 'size' => 123,
572 'tmp_name' => $path,
573 'type' => 'image/png',
574 ),
575 );
576
577 $request = new Request(array(), $values, array(), array(), $files, array(
578 'REQUEST_METHOD' => $method,
579 ));
580
581 $form = $this->getBuilder('')
582 ->setMethod($method)
583 ->setCompound(true)
584 ->setDataMapper($this->getDataMapper())
585 ->setRequestHandler(new HttpFoundationRequestHandler())
586 ->getForm();
587 $form->add($this->getBuilder('name')->getForm());
588 $form->add($this->getBuilder('image')->getForm());
589
590 $form->handleRequest($request);
591
592 $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
593
594 $this->assertEquals('Bernhard', $form['name']->getData());
595 $this->assertEquals($file, $form['image']->getData());
596 $this->assertEquals(array('extra' => 'data'), $form->getExtraData());
597
598 unlink($path);
599 }
600
601 /**
602 * @dataProvider requestMethodProvider
603 */
604 public function testSubmitPostOrPutRequestWithSingleChildForm($method)
605 {
606 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
607 $this->markTestSkipped('The "HttpFoundation" component is not available');
608 }
609
610 $path = tempnam(sys_get_temp_dir(), 'sf2');
611 touch($path);
612
613 $files = array(
614 'image' => array(
615 'error' => UPLOAD_ERR_OK,
616 'name' => 'upload.png',
617 'size' => 123,
618 'tmp_name' => $path,
619 'type' => 'image/png',
620 ),
621 );
622
623 $request = new Request(array(), array(), array(), array(), $files, array(
624 'REQUEST_METHOD' => $method,
625 ));
626
627 $form = $this->getBuilder('image')
628 ->setMethod($method)
629 ->setRequestHandler(new HttpFoundationRequestHandler())
630 ->getForm();
631
632 $form->handleRequest($request);
633
634 $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
635
636 $this->assertEquals($file, $form->getData());
637
638 unlink($path);
639 }
640
641 /**
642 * @dataProvider requestMethodProvider
643 */
644 public function testSubmitPostOrPutRequestWithSingleChildFormUploadedFile($method)
645 {
646 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
647 $this->markTestSkipped('The "HttpFoundation" component is not available');
648 }
649
650 $path = tempnam(sys_get_temp_dir(), 'sf2');
651 touch($path);
652
653 $values = array(
654 'name' => 'Bernhard',
655 );
656
657 $request = new Request(array(), $values, array(), array(), array(), array(
658 'REQUEST_METHOD' => $method,
659 ));
660
661 $form = $this->getBuilder('name')
662 ->setMethod($method)
663 ->setRequestHandler(new HttpFoundationRequestHandler())
664 ->getForm();
665
666 $form->handleRequest($request);
667
668 $this->assertEquals('Bernhard', $form->getData());
669
670 unlink($path);
671 }
672
673 public function testSubmitGetRequest()
674 {
675 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
676 $this->markTestSkipped('The "HttpFoundation" component is not available');
677 }
678
679 $values = array(
680 'author' => array(
681 'firstName' => 'Bernhard',
682 'lastName' => 'Schussek',
683 ),
684 );
685
686 $request = new Request($values, array(), array(), array(), array(), array(
687 'REQUEST_METHOD' => 'GET',
688 ));
689
690 $form = $this->getBuilder('author')
691 ->setMethod('GET')
692 ->setCompound(true)
693 ->setDataMapper($this->getDataMapper())
694 ->setRequestHandler(new HttpFoundationRequestHandler())
695 ->getForm();
696 $form->add($this->getBuilder('firstName')->getForm());
697 $form->add($this->getBuilder('lastName')->getForm());
698
699 $form->handleRequest($request);
700
701 $this->assertEquals('Bernhard', $form['firstName']->getData());
702 $this->assertEquals('Schussek', $form['lastName']->getData());
703 }
704
705 public function testSubmitGetRequestWithEmptyRootFormName()
706 {
707 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
708 $this->markTestSkipped('The "HttpFoundation" component is not available');
709 }
710
711 $values = array(
712 'firstName' => 'Bernhard',
713 'lastName' => 'Schussek',
714 'extra' => 'data'
715 );
716
717 $request = new Request($values, array(), array(), array(), array(), array(
718 'REQUEST_METHOD' => 'GET',
719 ));
720
721 $form = $this->getBuilder('')
722 ->setMethod('GET')
723 ->setCompound(true)
724 ->setDataMapper($this->getDataMapper())
725 ->setRequestHandler(new HttpFoundationRequestHandler())
726 ->getForm();
727 $form->add($this->getBuilder('firstName')->getForm());
728 $form->add($this->getBuilder('lastName')->getForm());
729
730 $form->handleRequest($request);
731
732 $this->assertEquals('Bernhard', $form['firstName']->getData());
733 $this->assertEquals('Schussek', $form['lastName']->getData());
734 $this->assertEquals(array('extra' => 'data'), $form->getExtraData());
735 }
736
737 public function testGetErrorsAsStringDeep()
738 {
739 $parent = $this->getBuilder()
740 ->setCompound(true)
741 ->setDataMapper($this->getDataMapper())
742 ->getForm();
743
744 $this->form->addError(new FormError('Error!'));
745
746 $parent->add($this->form);
747 $parent->add($this->getBuilder('foo')->getForm());
748
749 $this->assertEquals("name:\n ERROR: Error!\nfoo:\n No errors\n", $parent->getErrorsAsString());
750 }
751
752 protected function createForm()
753 {
754 return $this->getBuilder()
755 ->setCompound(true)
756 ->setDataMapper($this->getDataMapper())
757 ->getForm();
758 }
759}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ChoiceListTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ChoiceListTest.php
new file mode 100644
index 00000000..63eae9bf
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ChoiceListTest.php
@@ -0,0 +1,200 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\ChoiceList;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
15use Symfony\Component\Form\Extension\Core\View\ChoiceView;
16
17class ChoiceListTest extends \PHPUnit_Framework_TestCase
18{
19 private $obj1;
20
21 private $obj2;
22
23 private $obj3;
24
25 private $obj4;
26
27 private $list;
28
29 protected function setUp()
30 {
31 parent::setUp();
32
33 $this->obj1 = new \stdClass();
34 $this->obj2 = new \stdClass();
35 $this->obj3 = new \stdClass();
36 $this->obj4 = new \stdClass();
37
38 $this->list = new ChoiceList(
39 array(
40 'Group 1' => array($this->obj1, $this->obj2),
41 'Group 2' => array($this->obj3, $this->obj4),
42 ),
43 array(
44 'Group 1' => array('A', 'B'),
45 'Group 2' => array('C', 'D'),
46 ),
47 array($this->obj2, $this->obj3)
48 );
49 }
50
51 protected function tearDown()
52 {
53 parent::tearDown();
54
55 $this->obj1 = null;
56 $this->obj2 = null;
57 $this->obj3 = null;
58 $this->obj4 = null;
59 $this->list = null;
60 }
61
62 public function testInitArray()
63 {
64 $this->list = new ChoiceList(
65 array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
66 array('A', 'B', 'C', 'D'),
67 array($this->obj2)
68 );
69
70 $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
71 $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
72 $this->assertEquals(array(1 => new ChoiceView($this->obj2, '1', 'B')), $this->list->getPreferredViews());
73 $this->assertEquals(array(0 => new ChoiceView($this->obj1, '0', 'A'), 2 => new ChoiceView($this->obj3, '2', 'C'), 3 => new ChoiceView($this->obj4, '3', 'D')), $this->list->getRemainingViews());
74 }
75
76 /**
77 * Necessary for interoperability with MongoDB cursors or ORM relations as
78 * choices parameter. A choice itself that is an object implementing \Traversable
79 * is not treated as hierarchical structure, but as-is.
80 */
81 public function testInitNestedTraversable()
82 {
83 $traversableChoice = new \ArrayIterator(array($this->obj3, $this->obj4));
84
85 $this->list = new ChoiceList(
86 new \ArrayIterator(array(
87 'Group' => array($this->obj1, $this->obj2),
88 'Not a Group' => $traversableChoice
89 )),
90 array(
91 'Group' => array('A', 'B'),
92 'Not a Group' => 'C',
93 ),
94 array($this->obj2)
95 );
96
97 $this->assertSame(array($this->obj1, $this->obj2, $traversableChoice), $this->list->getChoices());
98 $this->assertSame(array('0', '1', '2'), $this->list->getValues());
99 $this->assertEquals(array(
100 'Group' => array(1 => new ChoiceView($this->obj2, '1', 'B'))
101 ), $this->list->getPreferredViews());
102 $this->assertEquals(array(
103 'Group' => array(0 => new ChoiceView($this->obj1, '0', 'A')),
104 2 => new ChoiceView($traversableChoice, '2', 'C')
105 ), $this->list->getRemainingViews());
106 }
107
108 public function testInitNestedArray()
109 {
110 $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
111 $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
112 $this->assertEquals(array(
113 'Group 1' => array(1 => new ChoiceView($this->obj2, '1', 'B')),
114 'Group 2' => array(2 => new ChoiceView($this->obj3, '2', 'C'))
115 ), $this->list->getPreferredViews());
116 $this->assertEquals(array(
117 'Group 1' => array(0 => new ChoiceView($this->obj1, '0', 'A')),
118 'Group 2' => array(3 => new ChoiceView($this->obj4, '3', 'D'))
119 ), $this->list->getRemainingViews());
120 }
121
122 public function testGetIndicesForChoices()
123 {
124 $choices = array($this->obj2, $this->obj3);
125 $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
126 }
127
128 public function testGetIndicesForChoicesIgnoresNonExistingChoices()
129 {
130 $choices = array($this->obj2, $this->obj3, 'foobar');
131 $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
132 }
133
134 public function testGetIndicesForValues()
135 {
136 // values and indices are always the same
137 $values = array('1', '2');
138 $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
139 }
140
141 public function testGetIndicesForValuesIgnoresNonExistingValues()
142 {
143 $values = array('1', '2', '5');
144 $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
145 }
146
147 public function testGetChoicesForValues()
148 {
149 $values = array('1', '2');
150 $this->assertSame(array($this->obj2, $this->obj3), $this->list->getChoicesForValues($values));
151 }
152
153 public function testGetChoicesForValuesCorrectOrderingOfResult()
154 {
155 $values = array('2', '1');
156 $this->assertSame(array($this->obj3, $this->obj2), $this->list->getChoicesForValues($values));
157 }
158
159 public function testGetChoicesForValuesIgnoresNonExistingValues()
160 {
161 $values = array('1', '2', '5');
162 $this->assertSame(array($this->obj2, $this->obj3), $this->list->getChoicesForValues($values));
163 }
164
165 public function testGetValuesForChoices()
166 {
167 $choices = array($this->obj2, $this->obj3);
168 $this->assertSame(array('1', '2'), $this->list->getValuesForChoices($choices));
169 }
170
171 public function testGetValuesForChoicesIgnoresNonExistingChoices()
172 {
173 $choices = array($this->obj2, $this->obj3, 'foobar');
174 $this->assertSame(array('1', '2'), $this->list->getValuesForChoices($choices));
175 }
176
177 /**
178 * @expectedException \InvalidArgumentException
179 */
180 public function testNonMatchingLabels()
181 {
182 $this->list = new ChoiceList(
183 array($this->obj1, $this->obj2),
184 array('A')
185 );
186 }
187
188 public function testLabelsContainingNull()
189 {
190 $this->list = new ChoiceList(
191 array($this->obj1, $this->obj2),
192 array('A', null)
193 );
194
195 $this->assertEquals(
196 array(0 => new ChoiceView($this->obj1, '0', 'A'), 1 => new ChoiceView($this->obj2, '1', null)),
197 $this->list->getRemainingViews()
198 );
199 }
200}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/LazyChoiceListTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/LazyChoiceListTest.php
new file mode 100644
index 00000000..bcd309e0
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/LazyChoiceListTest.php
@@ -0,0 +1,116 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\ChoiceList;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
15use Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList;
16use Symfony\Component\Form\Extension\Core\View\ChoiceView;
17
18class LazyChoiceListTest extends \PHPUnit_Framework_TestCase
19{
20 private $list;
21
22 protected function setUp()
23 {
24 parent::setUp();
25
26 $this->list = new LazyChoiceListTest_Impl(new SimpleChoiceList(array(
27 'a' => 'A',
28 'b' => 'B',
29 'c' => 'C',
30 ), array('b')));
31 }
32
33 protected function tearDown()
34 {
35 parent::tearDown();
36
37 $this->list = null;
38 }
39
40 public function testGetChoices()
41 {
42 $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c'), $this->list->getChoices());
43 }
44
45 public function testGetValues()
46 {
47 $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c'), $this->list->getValues());
48 }
49
50 public function testGetPreferredViews()
51 {
52 $this->assertEquals(array(1 => new ChoiceView('b', 'b', 'B')), $this->list->getPreferredViews());
53 }
54
55 public function testGetRemainingViews()
56 {
57 $this->assertEquals(array(0 => new ChoiceView('a', 'a', 'A'), 2 => new ChoiceView('c', 'c', 'C')), $this->list->getRemainingViews());
58 }
59
60 public function testGetIndicesForChoices()
61 {
62 $choices = array('b', 'c');
63 $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
64 }
65
66 public function testGetIndicesForValues()
67 {
68 $values = array('b', 'c');
69 $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
70 }
71
72 public function testGetChoicesForValues()
73 {
74 $values = array('b', 'c');
75 $this->assertSame(array('b', 'c'), $this->list->getChoicesForValues($values));
76 }
77
78 public function testGetValuesForChoices()
79 {
80 $choices = array('b', 'c');
81 $this->assertSame(array('b', 'c'), $this->list->getValuesForChoices($choices));
82 }
83
84 /**
85 * @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
86 */
87 public function testLoadChoiceListShouldReturnChoiceList()
88 {
89 $list = new LazyChoiceListTest_InvalidImpl();
90
91 $list->getChoices();
92 }
93}
94
95class LazyChoiceListTest_Impl extends LazyChoiceList
96{
97 private $choiceList;
98
99 public function __construct($choiceList)
100 {
101 $this->choiceList = $choiceList;
102 }
103
104 protected function loadChoiceList()
105 {
106 return $this->choiceList;
107 }
108}
109
110class LazyChoiceListTest_InvalidImpl extends LazyChoiceList
111{
112 protected function loadChoiceList()
113 {
114 return new \stdClass();
115 }
116}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ObjectChoiceListTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ObjectChoiceListTest.php
new file mode 100644
index 00000000..69c5aa0f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ObjectChoiceListTest.php
@@ -0,0 +1,212 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\ChoiceList;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
15use Symfony\Component\Form\Extension\Core\View\ChoiceView;
16
17class ObjectChoiceListTest_EntityWithToString
18{
19 private $property;
20
21 public function __construct($property)
22 {
23 $this->property = $property;
24 }
25
26 public function __toString()
27 {
28 return $this->property;
29 }
30}
31
32class ObjectChoiceListTest extends \PHPUnit_Framework_TestCase
33{
34 private $obj1;
35
36 private $obj2;
37
38 private $obj3;
39
40 private $obj4;
41
42 /**
43 * @var ObjectChoiceList
44 */
45 private $list;
46
47 protected function setUp()
48 {
49 parent::setUp();
50
51 $this->obj1 = (object) array('name' => 'A');
52 $this->obj2 = (object) array('name' => 'B');
53 $this->obj3 = (object) array('name' => 'C');
54 $this->obj4 = (object) array('name' => 'D');
55
56 $this->list = new ObjectChoiceList(
57 array(
58 'Group 1' => array($this->obj1, $this->obj2),
59 'Group 2' => array($this->obj3, $this->obj4),
60 ),
61 'name',
62 array($this->obj2, $this->obj3)
63 );
64 }
65
66 protected function tearDown()
67 {
68 parent::tearDown();
69
70 $this->obj1 = null;
71 $this->obj2 = null;
72 $this->obj3 = null;
73 $this->obj4 = null;
74 $this->list = null;
75 }
76
77 public function testInitArray()
78 {
79 $this->list = new ObjectChoiceList(
80 array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
81 'name',
82 array($this->obj2)
83 );
84
85 $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
86 $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
87 $this->assertEquals(array(1 => new ChoiceView($this->obj2, '1', 'B')), $this->list->getPreferredViews());
88 $this->assertEquals(array(0 => new ChoiceView($this->obj1, '0', 'A'), 2 => new ChoiceView($this->obj3, '2', 'C'), 3 => new ChoiceView($this->obj4, '3', 'D')), $this->list->getRemainingViews());
89 }
90
91 public function testInitNestedArray()
92 {
93 $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
94 $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
95 $this->assertEquals(array(
96 'Group 1' => array(1 => new ChoiceView($this->obj2, '1', 'B')),
97 'Group 2' => array(2 => new ChoiceView($this->obj3, '2', 'C'))
98 ), $this->list->getPreferredViews());
99 $this->assertEquals(array(
100 'Group 1' => array(0 => new ChoiceView($this->obj1, '0', 'A')),
101 'Group 2' => array(3 => new ChoiceView($this->obj4, '3', 'D'))
102 ), $this->list->getRemainingViews());
103 }
104
105 public function testInitArrayWithGroupPath()
106 {
107 $this->obj1 = (object) array('name' => 'A', 'category' => 'Group 1');
108 $this->obj2 = (object) array('name' => 'B', 'category' => 'Group 1');
109 $this->obj3 = (object) array('name' => 'C', 'category' => 'Group 2');
110 $this->obj4 = (object) array('name' => 'D', 'category' => 'Group 2');
111
112 // Objects with NULL groups are not grouped
113 $obj5 = (object) array('name' => 'E', 'category' => null);
114
115 // Objects without the group property are not grouped either
116 // see https://github.com/symfony/symfony/commit/d9b7abb7c7a0f28e0ce970afc5e305dce5dccddf
117 $obj6 = (object) array('name' => 'F');
118
119 $this->list = new ObjectChoiceList(
120 array($this->obj1, $this->obj2, $this->obj3, $this->obj4, $obj5, $obj6),
121 'name',
122 array($this->obj2, $this->obj3),
123 'category'
124 );
125
126 $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4, $obj5, $obj6), $this->list->getChoices());
127 $this->assertSame(array('0', '1', '2', '3', '4', '5'), $this->list->getValues());
128 $this->assertEquals(array(
129 'Group 1' => array(1 => new ChoiceView($this->obj2, '1', 'B')),
130 'Group 2' => array(2 => new ChoiceView($this->obj3, '2', 'C'))
131 ), $this->list->getPreferredViews());
132 $this->assertEquals(array(
133 'Group 1' => array(0 => new ChoiceView($this->obj1, '0', 'A')),
134 'Group 2' => array(3 => new ChoiceView($this->obj4, '3', 'D')),
135 4 => new ChoiceView($obj5, '4', 'E'),
136 5 => new ChoiceView($obj6, '5', 'F'),
137 ), $this->list->getRemainingViews());
138 }
139
140 /**
141 * @expectedException \InvalidArgumentException
142 */
143 public function testInitArrayWithGroupPathThrowsExceptionIfNestedArray()
144 {
145 $this->obj1 = (object) array('name' => 'A', 'category' => 'Group 1');
146 $this->obj2 = (object) array('name' => 'B', 'category' => 'Group 1');
147 $this->obj3 = (object) array('name' => 'C', 'category' => 'Group 2');
148 $this->obj4 = (object) array('name' => 'D', 'category' => 'Group 2');
149
150 new ObjectChoiceList(
151 array(
152 'Group 1' => array($this->obj1, $this->obj2),
153 'Group 2' => array($this->obj3, $this->obj4),
154 ),
155 'name',
156 array($this->obj2, $this->obj3),
157 'category'
158 );
159 }
160
161 public function testInitArrayWithValuePath()
162 {
163 $this->obj1 = (object) array('name' => 'A', 'id' => 10);
164 $this->obj2 = (object) array('name' => 'B', 'id' => 20);
165 $this->obj3 = (object) array('name' => 'C', 'id' => 30);
166 $this->obj4 = (object) array('name' => 'D', 'id' => 40);
167
168 $this->list = new ObjectChoiceList(
169 array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
170 'name',
171 array($this->obj2, $this->obj3),
172 null,
173 'id'
174 );
175
176 $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
177 $this->assertSame(array('10', '20', '30', '40'), $this->list->getValues());
178 $this->assertEquals(array(1 => new ChoiceView($this->obj2, '20', 'B'), 2 => new ChoiceView($this->obj3, '30', 'C')), $this->list->getPreferredViews());
179 $this->assertEquals(array(0 => new ChoiceView($this->obj1, '10', 'A'), 3 => new ChoiceView($this->obj4, '40', 'D')), $this->list->getRemainingViews());
180 }
181
182 public function testInitArrayUsesToString()
183 {
184 $this->obj1 = new ObjectChoiceListTest_EntityWithToString('A');
185 $this->obj2 = new ObjectChoiceListTest_EntityWithToString('B');
186 $this->obj3 = new ObjectChoiceListTest_EntityWithToString('C');
187 $this->obj4 = new ObjectChoiceListTest_EntityWithToString('D');
188
189 $this->list = new ObjectChoiceList(
190 array($this->obj1, $this->obj2, $this->obj3, $this->obj4)
191 );
192
193 $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
194 $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
195 $this->assertEquals(array(0 => new ChoiceView($this->obj1, '0', 'A'), 1 => new ChoiceView($this->obj2, '1', 'B'), 2 => new ChoiceView($this->obj3, '2', 'C'), 3 => new ChoiceView($this->obj4, '3', 'D')), $this->list->getRemainingViews());
196 }
197
198 /**
199 * @expectedException \Symfony\Component\Form\Exception\StringCastException
200 */
201 public function testInitArrayThrowsExceptionIfToStringNotFound()
202 {
203 $this->obj1 = new ObjectChoiceListTest_EntityWithToString('A');
204 $this->obj2 = new ObjectChoiceListTest_EntityWithToString('B');
205 $this->obj3 = (object) array('name' => 'C');
206 $this->obj4 = new ObjectChoiceListTest_EntityWithToString('D');
207
208 new ObjectChoiceList(
209 array($this->obj1, $this->obj2, $this->obj3, $this->obj4)
210 );
211 }
212}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/SimpleChoiceListTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/SimpleChoiceListTest.php
new file mode 100644
index 00000000..69d27a18
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/SimpleChoiceListTest.php
@@ -0,0 +1,188 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\ChoiceList;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
15use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
16use Symfony\Component\Form\Extension\Core\View\ChoiceView;
17
18class SimpleChoiceListTest extends \PHPUnit_Framework_TestCase
19{
20 private $list;
21
22 private $numericList;
23
24 protected function setUp()
25 {
26 parent::setUp();
27
28 $choices = array(
29 'Group 1' => array('a' => 'A', 'b' => 'B'),
30 'Group 2' => array('c' => 'C', 'd' => 'D'),
31 );
32 $numericChoices = array(
33 'Group 1' => array(0 => 'A', 1 => 'B'),
34 'Group 2' => array(2 => 'C', 3 => 'D'),
35 );
36
37 $this->list = new SimpleChoiceList($choices, array('b', 'c'));
38
39 // Use COPY_CHOICE strategy to test for the various associated problems
40 $this->numericList = new SimpleChoiceList($numericChoices, array(1, 2));
41 }
42
43 protected function tearDown()
44 {
45 parent::tearDown();
46
47 $this->list = null;
48 $this->numericList = null;
49 }
50
51 public function testInitArray()
52 {
53 $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C');
54 $this->list = new SimpleChoiceList($choices, array('b'));
55
56 $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c'), $this->list->getChoices());
57 $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c'), $this->list->getValues());
58 $this->assertEquals(array(1 => new ChoiceView('b', 'b', 'B')), $this->list->getPreferredViews());
59 $this->assertEquals(array(0 => new ChoiceView('a', 'a', 'A'), 2 => new ChoiceView('c', 'c', 'C')), $this->list->getRemainingViews());
60 }
61
62 public function testInitNestedArray()
63 {
64 $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $this->list->getChoices());
65 $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $this->list->getValues());
66 $this->assertEquals(array(
67 'Group 1' => array(1 => new ChoiceView('b', 'b', 'B')),
68 'Group 2' => array(2 => new ChoiceView('c', 'c', 'C'))
69 ), $this->list->getPreferredViews());
70 $this->assertEquals(array(
71 'Group 1' => array(0 => new ChoiceView('a', 'a', 'A')),
72 'Group 2' => array(3 => new ChoiceView('d', 'd', 'D'))
73 ), $this->list->getRemainingViews());
74 }
75
76 public function testGetIndicesForChoices()
77 {
78 $choices = array('b', 'c');
79 $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
80 }
81
82 public function testGetIndicesForChoicesIgnoresNonExistingChoices()
83 {
84 $choices = array('b', 'c', 'foobar');
85 $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
86 }
87
88 public function testGetIndicesForChoicesDealsWithNumericChoices()
89 {
90 // Pass choices as strings although they are integers
91 $choices = array('0', '1');
92 $this->assertSame(array(0, 1), $this->numericList->getIndicesForChoices($choices));
93 }
94
95 public function testGetIndicesForValues()
96 {
97 $values = array('b', 'c');
98 $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
99 }
100
101 public function testGetIndicesForValuesIgnoresNonExistingValues()
102 {
103 $values = array('b', 'c', '100');
104 $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
105 }
106
107 public function testGetIndicesForValuesDealsWithNumericValues()
108 {
109 // Pass values as strings although they are integers
110 $values = array('0', '1');
111 $this->assertSame(array(0, 1), $this->numericList->getIndicesForValues($values));
112 }
113
114 public function testGetChoicesForValues()
115 {
116 $values = array('b', 'c');
117 $this->assertSame(array('b', 'c'), $this->list->getChoicesForValues($values));
118 }
119
120 public function testGetChoicesForValuesIgnoresNonExistingValues()
121 {
122 $values = array('b', 'c', '100');
123 $this->assertSame(array('b', 'c'), $this->list->getChoicesForValues($values));
124 }
125
126 public function testGetChoicesForValuesDealsWithNumericValues()
127 {
128 // Pass values as strings although they are integers
129 $values = array('0', '1');
130 $this->assertSame(array(0, 1), $this->numericList->getChoicesForValues($values));
131 }
132
133 public function testGetValuesForChoices()
134 {
135 $choices = array('b', 'c');
136 $this->assertSame(array('b', 'c'), $this->list->getValuesForChoices($choices));
137 }
138
139 public function testGetValuesForChoicesIgnoresNonExistingValues()
140 {
141 $choices = array('b', 'c', 'foobar');
142 $this->assertSame(array('b', 'c'), $this->list->getValuesForChoices($choices));
143 }
144
145 public function testGetValuesForChoicesDealsWithNumericValues()
146 {
147 // Pass values as strings although they are integers
148 $values = array('0', '1');
149
150 $this->assertSame(array('0', '1'), $this->numericList->getValuesForChoices($values));
151 }
152
153 /**
154 * @dataProvider dirtyValuesProvider
155 */
156 public function testGetValuesForChoicesDealsWithDirtyValues($choice, $value)
157 {
158 $choices = array(
159 '0' => 'Zero',
160 '1' => 'One',
161 '' => 'Empty',
162 '1.23' => 'Float',
163 'foo' => 'Foo',
164 'foo10' => 'Foo 10',
165 );
166
167 // use COPY_CHOICE strategy to test the problems
168 $this->list = new SimpleChoiceList($choices, array());
169
170 $this->assertSame(array($value), $this->list->getValuesForChoices(array($choice)));
171 }
172
173 public function dirtyValuesProvider()
174 {
175 return array(
176 array(0, '0'),
177 array('0', '0'),
178 array('1', '1'),
179 array(false, '0'),
180 array(true, '1'),
181 array('', ''),
182 array(null, ''),
183 array('1.23', '1.23'),
184 array('foo', 'foo'),
185 array('foo10', 'foo10'),
186 );
187 }
188}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php
new file mode 100644
index 00000000..ee2e3351
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php
@@ -0,0 +1,319 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataMapper;
13
14use Symfony\Component\Form\FormConfigBuilder;
15use Symfony\Component\Form\FormConfigInterface;
16use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
17
18class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase
19{
20 /**
21 * @var PropertyPathMapper
22 */
23 private $mapper;
24
25 /**
26 * @var \PHPUnit_Framework_MockObject_MockObject
27 */
28 private $dispatcher;
29
30 /**
31 * @var \PHPUnit_Framework_MockObject_MockObject
32 */
33 private $propertyAccessor;
34
35 protected function setUp()
36 {
37 if (!class_exists('Symfony\Component\EventDispatcher\Event')) {
38 $this->markTestSkipped('The "EventDispatcher" component is not available');
39 }
40
41 if (!class_exists('Symfony\Component\PropertyAccess\PropertyAccess')) {
42 $this->markTestSkipped('The "PropertyAccess" component is not available');
43 }
44
45 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
46 $this->propertyAccessor = $this->getMock('Symfony\Component\PropertyAccess\PropertyAccessorInterface');
47 $this->mapper = new PropertyPathMapper($this->propertyAccessor);
48 }
49
50 /**
51 * @param $path
52 * @return \PHPUnit_Framework_MockObject_MockObject
53 */
54 private function getPropertyPath($path)
55 {
56 return $this->getMockBuilder('Symfony\Component\PropertyAccess\PropertyPath')
57 ->setConstructorArgs(array($path))
58 ->setMethods(array('getValue', 'setValue'))
59 ->getMock();
60 }
61
62 /**
63 * @param FormConfigInterface $config
64 * @param Boolean $synchronized
65 * @return \PHPUnit_Framework_MockObject_MockObject
66 */
67 private function getForm(FormConfigInterface $config, $synchronized = true)
68 {
69 $form = $this->getMockBuilder('Symfony\Component\Form\Form')
70 ->setConstructorArgs(array($config))
71 ->setMethods(array('isSynchronized'))
72 ->getMock();
73
74 $form->expects($this->any())
75 ->method('isSynchronized')
76 ->will($this->returnValue($synchronized));
77
78 return $form;
79 }
80
81 /**
82 * @return \PHPUnit_Framework_MockObject_MockObject
83 */
84 private function getDataMapper()
85 {
86 return $this->getMock('Symfony\Component\Form\DataMapperInterface');
87 }
88
89 public function testMapDataToFormsPassesObjectRefIfByReference()
90 {
91 $car = new \stdClass();
92 $engine = new \stdClass();
93 $propertyPath = $this->getPropertyPath('engine');
94
95 $this->propertyAccessor->expects($this->once())
96 ->method('getValue')
97 ->with($car, $propertyPath)
98 ->will($this->returnValue($engine));
99
100 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
101 $config->setByReference(true);
102 $config->setPropertyPath($propertyPath);
103 $form = $this->getForm($config);
104
105 $this->mapper->mapDataToForms($car, array($form));
106
107 // Can't use isIdentical() above because mocks always clone their
108 // arguments which can't be disabled in PHPUnit 3.6
109 $this->assertSame($engine, $form->getData());
110 }
111
112 public function testMapDataToFormsPassesObjectCloneIfNotByReference()
113 {
114 $car = new \stdClass();
115 $engine = new \stdClass();
116 $propertyPath = $this->getPropertyPath('engine');
117
118 $this->propertyAccessor->expects($this->once())
119 ->method('getValue')
120 ->with($car, $propertyPath)
121 ->will($this->returnValue($engine));
122
123 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
124 $config->setByReference(false);
125 $config->setPropertyPath($propertyPath);
126 $form = $this->getForm($config);
127
128 $this->mapper->mapDataToForms($car, array($form));
129
130 $this->assertNotSame($engine, $form->getData());
131 $this->assertEquals($engine, $form->getData());
132 }
133
134 public function testMapDataToFormsIgnoresEmptyPropertyPath()
135 {
136 $car = new \stdClass();
137
138 $config = new FormConfigBuilder(null, '\stdClass', $this->dispatcher);
139 $config->setByReference(true);
140 $form = $this->getForm($config);
141
142 $this->assertNull($form->getPropertyPath());
143
144 $this->mapper->mapDataToForms($car, array($form));
145
146 $this->assertNull($form->getData());
147 }
148
149 public function testMapDataToFormsIgnoresUnmapped()
150 {
151 $car = new \stdClass();
152 $propertyPath = $this->getPropertyPath('engine');
153
154 $this->propertyAccessor->expects($this->never())
155 ->method('getValue');
156
157 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
158 $config->setByReference(true);
159 $config->setMapped(false);
160 $config->setPropertyPath($propertyPath);
161 $form = $this->getForm($config);
162
163 $this->mapper->mapDataToForms($car, array($form));
164
165 $this->assertNull($form->getData());
166 }
167
168 public function testMapDataToFormsIgnoresEmptyData()
169 {
170 $propertyPath = $this->getPropertyPath('engine');
171
172 $this->propertyAccessor->expects($this->never())
173 ->method('getValue');
174
175 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
176 $config->setByReference(true);
177 $config->setPropertyPath($propertyPath);
178 $form = $this->getForm($config);
179
180 $this->mapper->mapDataToForms(null, array($form));
181
182 $this->assertNull($form->getData());
183 }
184
185 public function testMapFormsToDataWritesBackIfNotByReference()
186 {
187 $car = new \stdClass();
188 $engine = new \stdClass();
189 $propertyPath = $this->getPropertyPath('engine');
190
191 $this->propertyAccessor->expects($this->once())
192 ->method('setValue')
193 ->with($car, $propertyPath, $engine);
194
195 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
196 $config->setByReference(false);
197 $config->setPropertyPath($propertyPath);
198 $config->setData($engine);
199 $form = $this->getForm($config);
200
201 $this->mapper->mapFormsToData(array($form), $car);
202 }
203
204 public function testMapFormsToDataWritesBackIfByReferenceButNoReference()
205 {
206 $car = new \stdClass();
207 $engine = new \stdClass();
208 $propertyPath = $this->getPropertyPath('engine');
209
210 $this->propertyAccessor->expects($this->once())
211 ->method('setValue')
212 ->with($car, $propertyPath, $engine);
213
214 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
215 $config->setByReference(true);
216 $config->setPropertyPath($propertyPath);
217 $config->setData($engine);
218 $form = $this->getForm($config);
219
220 $this->mapper->mapFormsToData(array($form), $car);
221 }
222
223 public function testMapFormsToDataWritesBackIfByReferenceAndReference()
224 {
225 $car = new \stdClass();
226 $engine = new \stdClass();
227 $propertyPath = $this->getPropertyPath('engine');
228
229 // $car already contains the reference of $engine
230 $this->propertyAccessor->expects($this->once())
231 ->method('getValue')
232 ->with($car, $propertyPath)
233 ->will($this->returnValue($engine));
234
235 $this->propertyAccessor->expects($this->never())
236 ->method('setValue');
237
238 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
239 $config->setByReference(true);
240 $config->setPropertyPath($propertyPath);
241 $config->setData($engine);
242 $form = $this->getForm($config);
243
244 $this->mapper->mapFormsToData(array($form), $car);
245 }
246
247 public function testMapFormsToDataIgnoresUnmapped()
248 {
249 $car = new \stdClass();
250 $engine = new \stdClass();
251 $propertyPath = $this->getPropertyPath('engine');
252
253 $this->propertyAccessor->expects($this->never())
254 ->method('setValue');
255
256 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
257 $config->setByReference(true);
258 $config->setPropertyPath($propertyPath);
259 $config->setData($engine);
260 $config->setMapped(false);
261 $form = $this->getForm($config);
262
263 $this->mapper->mapFormsToData(array($form), $car);
264 }
265
266 public function testMapFormsToDataIgnoresEmptyData()
267 {
268 $car = new \stdClass();
269 $propertyPath = $this->getPropertyPath('engine');
270
271 $this->propertyAccessor->expects($this->never())
272 ->method('setValue');
273
274 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
275 $config->setByReference(true);
276 $config->setPropertyPath($propertyPath);
277 $config->setData(null);
278 $form = $this->getForm($config);
279
280 $this->mapper->mapFormsToData(array($form), $car);
281 }
282
283 public function testMapFormsToDataIgnoresUnsynchronized()
284 {
285 $car = new \stdClass();
286 $engine = new \stdClass();
287 $propertyPath = $this->getPropertyPath('engine');
288
289 $this->propertyAccessor->expects($this->never())
290 ->method('setValue');
291
292 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
293 $config->setByReference(true);
294 $config->setPropertyPath($propertyPath);
295 $config->setData($engine);
296 $form = $this->getForm($config, false);
297
298 $this->mapper->mapFormsToData(array($form), $car);
299 }
300
301 public function testMapFormsToDataIgnoresDisabled()
302 {
303 $car = new \stdClass();
304 $engine = new \stdClass();
305 $propertyPath = $this->getPropertyPath('engine');
306
307 $this->propertyAccessor->expects($this->never())
308 ->method('setValue');
309
310 $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
311 $config->setByReference(true);
312 $config->setPropertyPath($propertyPath);
313 $config->setData($engine);
314 $config->setDisabled(true);
315 $form = $this->getForm($config);
316
317 $this->mapper->mapFormsToData(array($form), $car);
318 }
319}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ArrayToPartsTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ArrayToPartsTransformerTest.php
new file mode 100644
index 00000000..bafe5c09
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ArrayToPartsTransformerTest.php
@@ -0,0 +1,149 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
15
16class ArrayToPartsTransformerTest extends \PHPUnit_Framework_TestCase
17{
18 private $transformer;
19
20 protected function setUp()
21 {
22 $this->transformer = new ArrayToPartsTransformer(array(
23 'first' => array('a', 'b', 'c'),
24 'second' => array('d', 'e', 'f'),
25 ));
26 }
27
28 protected function tearDown()
29 {
30 $this->transformer = null;
31 }
32
33 public function testTransform()
34 {
35 $input = array(
36 'a' => '1',
37 'b' => '2',
38 'c' => '3',
39 'd' => '4',
40 'e' => '5',
41 'f' => '6',
42 );
43
44 $output = array(
45 'first' => array(
46 'a' => '1',
47 'b' => '2',
48 'c' => '3',
49 ),
50 'second' => array(
51 'd' => '4',
52 'e' => '5',
53 'f' => '6',
54 ),
55 );
56
57 $this->assertSame($output, $this->transformer->transform($input));
58 }
59
60 public function testTransformEmpty()
61 {
62 $output = array(
63 'first' => null,
64 'second' => null,
65 );
66
67 $this->assertSame($output, $this->transformer->transform(null));
68 }
69
70 /**
71 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
72 */
73 public function testTransformRequiresArray()
74 {
75 $this->transformer->transform('12345');
76 }
77
78 public function testReverseTransform()
79 {
80 $input = array(
81 'first' => array(
82 'a' => '1',
83 'b' => '2',
84 'c' => '3',
85 ),
86 'second' => array(
87 'd' => '4',
88 'e' => '5',
89 'f' => '6',
90 ),
91 );
92
93 $output = array(
94 'a' => '1',
95 'b' => '2',
96 'c' => '3',
97 'd' => '4',
98 'e' => '5',
99 'f' => '6',
100 );
101
102 $this->assertSame($output, $this->transformer->reverseTransform($input));
103 }
104
105 public function testReverseTransformCompletelyEmpty()
106 {
107 $input = array(
108 'first' => '',
109 'second' => '',
110 );
111
112 $this->assertNull($this->transformer->reverseTransform($input));
113 }
114
115 public function testReverseTransformCompletelyNull()
116 {
117 $input = array(
118 'first' => null,
119 'second' => null,
120 );
121
122 $this->assertNull($this->transformer->reverseTransform($input));
123 }
124
125 /**
126 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
127 */
128 public function testReverseTransformPartiallyNull()
129 {
130 $input = array(
131 'first' => array(
132 'a' => '1',
133 'b' => '2',
134 'c' => '3',
135 ),
136 'second' => null,
137 );
138
139 $this->transformer->reverseTransform($input);
140 }
141
142 /**
143 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
144 */
145 public function testReverseTransformRequiresArray()
146 {
147 $this->transformer->reverseTransform('12345');
148 }
149}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BooleanToStringTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BooleanToStringTransformerTest.php
new file mode 100644
index 00000000..41f8f956
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BooleanToStringTransformerTest.php
@@ -0,0 +1,60 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\BooleanToStringTransformer;
15
16class BooleanToStringTransformerTest extends \PHPUnit_Framework_TestCase
17{
18 const TRUE_VALUE = '1';
19
20 protected $transformer;
21
22 protected function setUp()
23 {
24 $this->transformer = new BooleanToStringTransformer(self::TRUE_VALUE);
25 }
26
27 protected function tearDown()
28 {
29 $this->transformer = null;
30 }
31
32 public function testTransform()
33 {
34 $this->assertEquals(self::TRUE_VALUE, $this->transformer->transform(true));
35 $this->assertNull($this->transformer->transform(false));
36 $this->assertNull($this->transformer->transform(null));
37 }
38
39 public function testTransformExpectsBoolean()
40 {
41 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
42
43 $this->transformer->transform('1');
44 }
45
46 public function testReverseTransformExpectsString()
47 {
48 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
49
50 $this->transformer->reverseTransform(1);
51 }
52
53 public function testReverseTransform()
54 {
55 $this->assertTrue($this->transformer->reverseTransform(self::TRUE_VALUE));
56 $this->assertTrue($this->transformer->reverseTransform('foobar'));
57 $this->assertTrue($this->transformer->reverseTransform(''));
58 $this->assertFalse($this->transformer->reverseTransform(null));
59 }
60}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php
new file mode 100644
index 00000000..bbae0621
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php
@@ -0,0 +1,76 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
15use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
16
17class ChoiceToValueTransformerTest extends \PHPUnit_Framework_TestCase
18{
19 protected $transformer;
20
21 protected function setUp()
22 {
23 $list = new SimpleChoiceList(array('' => 'A', 0 => 'B', 1 => 'C'));
24 $this->transformer = new ChoiceToValueTransformer($list);
25 }
26
27 protected function tearDown()
28 {
29 $this->transformer = null;
30 }
31
32 public function transformProvider()
33 {
34 return array(
35 // more extensive test set can be found in FormUtilTest
36 array(0, '0'),
37 array(false, '0'),
38 array('', ''),
39 );
40 }
41
42 /**
43 * @dataProvider transformProvider
44 */
45 public function testTransform($in, $out)
46 {
47 $this->assertSame($out, $this->transformer->transform($in));
48 }
49
50 public function reverseTransformProvider()
51 {
52 return array(
53 // values are expected to be valid choice keys already and stay
54 // the same
55 array('0', 0),
56 array('', null),
57 array(null, null),
58 );
59 }
60
61 /**
62 * @dataProvider reverseTransformProvider
63 */
64 public function testReverseTransform($in, $out)
65 {
66 $this->assertSame($out, $this->transformer->reverseTransform($in));
67 }
68
69 /**
70 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
71 */
72 public function testReverseTransformExpectsScalar()
73 {
74 $this->transformer->reverseTransform(array());
75 }
76}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php
new file mode 100644
index 00000000..57297193
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php
@@ -0,0 +1,76 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
15
16use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
17
18class ChoicesToValuesTransformerTest extends \PHPUnit_Framework_TestCase
19{
20 protected $transformer;
21
22 protected function setUp()
23 {
24 $list = new SimpleChoiceList(array(0 => 'A', 1 => 'B', 2 => 'C'));
25 $this->transformer = new ChoicesToValuesTransformer($list);
26 }
27
28 protected function tearDown()
29 {
30 $this->transformer = null;
31 }
32
33 public function testTransform()
34 {
35 // Value strategy in SimpleChoiceList is to copy and convert to string
36 $in = array(0, 1, 2);
37 $out = array('0', '1', '2');
38
39 $this->assertSame($out, $this->transformer->transform($in));
40 }
41
42 public function testTransformNull()
43 {
44 $this->assertSame(array(), $this->transformer->transform(null));
45 }
46
47 /**
48 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
49 */
50 public function testTransformExpectsArray()
51 {
52 $this->transformer->transform('foobar');
53 }
54
55 public function testReverseTransform()
56 {
57 // values are expected to be valid choices and stay the same
58 $in = array('0', '1', '2');
59 $out = array(0, 1, 2);
60
61 $this->assertSame($out, $this->transformer->reverseTransform($in));
62 }
63
64 public function testReverseTransformNull()
65 {
66 $this->assertSame(array(), $this->transformer->reverseTransform(null));
67 }
68
69 /**
70 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
71 */
72 public function testReverseTransformExpectsArray()
73 {
74 $this->transformer->reverseTransform('foobar');
75 }
76}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DataTransformerChainTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DataTransformerChainTest.php
new file mode 100644
index 00000000..2ee2f22d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DataTransformerChainTest.php
@@ -0,0 +1,53 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
15
16class DataTransformerChainTest extends \PHPUnit_Framework_TestCase
17{
18 public function testTransform()
19 {
20 $transformer1 = $this->getMock('Symfony\Component\Form\DataTransformerInterface');
21 $transformer1->expects($this->once())
22 ->method('transform')
23 ->with($this->identicalTo('foo'))
24 ->will($this->returnValue('bar'));
25 $transformer2 = $this->getMock('Symfony\Component\Form\DataTransformerInterface');
26 $transformer2->expects($this->once())
27 ->method('transform')
28 ->with($this->identicalTo('bar'))
29 ->will($this->returnValue('baz'));
30
31 $chain = new DataTransformerChain(array($transformer1, $transformer2));
32
33 $this->assertEquals('baz', $chain->transform('foo'));
34 }
35
36 public function testReverseTransform()
37 {
38 $transformer2 = $this->getMock('Symfony\Component\Form\DataTransformerInterface');
39 $transformer2->expects($this->once())
40 ->method('reverseTransform')
41 ->with($this->identicalTo('foo'))
42 ->will($this->returnValue('bar'));
43 $transformer1 = $this->getMock('Symfony\Component\Form\DataTransformerInterface');
44 $transformer1->expects($this->once())
45 ->method('reverseTransform')
46 ->with($this->identicalTo('bar'))
47 ->will($this->returnValue('baz'));
48
49 $chain = new DataTransformerChain(array($transformer1, $transformer2));
50
51 $this->assertEquals('baz', $chain->reverseTransform('foo'));
52 }
53}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeTestCase.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeTestCase.php
new file mode 100644
index 00000000..f7722c49
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeTestCase.php
@@ -0,0 +1,20 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14abstract class DateTimeTestCase extends \PHPUnit_Framework_TestCase
15{
16 public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual)
17 {
18 self::assertEquals($expected->format('c'), $actual->format('c'));
19 }
20}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php
new file mode 100644
index 00000000..4898b88d
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php
@@ -0,0 +1,512 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
15
16class DateTimeToArrayTransformerTest extends DateTimeTestCase
17{
18 public function testTransform()
19 {
20 $transformer = new DateTimeToArrayTransformer('UTC', 'UTC');
21
22 $input = new \DateTime('2010-02-03 04:05:06 UTC');
23
24 $output = array(
25 'year' => '2010',
26 'month' => '2',
27 'day' => '3',
28 'hour' => '4',
29 'minute' => '5',
30 'second' => '6',
31 );
32
33 $this->assertSame($output, $transformer->transform($input));
34 }
35
36 public function testTransformEmpty()
37 {
38 $transformer = new DateTimeToArrayTransformer();
39
40 $output = array(
41 'year' => '',
42 'month' => '',
43 'day' => '',
44 'hour' => '',
45 'minute' => '',
46 'second' => '',
47 );
48
49 $this->assertSame($output, $transformer->transform(null));
50 }
51
52 public function testTransformEmptyWithFields()
53 {
54 $transformer = new DateTimeToArrayTransformer(null, null, array('year', 'minute', 'second'));
55
56 $output = array(
57 'year' => '',
58 'minute' => '',
59 'second' => '',
60 );
61
62 $this->assertSame($output, $transformer->transform(null));
63 }
64
65 public function testTransformWithFields()
66 {
67 $transformer = new DateTimeToArrayTransformer('UTC', 'UTC', array('year', 'month', 'minute', 'second'));
68
69 $input = new \DateTime('2010-02-03 04:05:06 UTC');
70
71 $output = array(
72 'year' => '2010',
73 'month' => '2',
74 'minute' => '5',
75 'second' => '6',
76 );
77
78 $this->assertSame($output, $transformer->transform($input));
79 }
80
81 public function testTransformWithPadding()
82 {
83 $transformer = new DateTimeToArrayTransformer('UTC', 'UTC', null, true);
84
85 $input = new \DateTime('2010-02-03 04:05:06 UTC');
86
87 $output = array(
88 'year' => '2010',
89 'month' => '02',
90 'day' => '03',
91 'hour' => '04',
92 'minute' => '05',
93 'second' => '06',
94 );
95
96 $this->assertSame($output, $transformer->transform($input));
97 }
98
99 public function testTransformDifferentTimezones()
100 {
101 $transformer = new DateTimeToArrayTransformer('America/New_York', 'Asia/Hong_Kong');
102
103 $input = new \DateTime('2010-02-03 04:05:06 America/New_York');
104
105 $dateTime = new \DateTime('2010-02-03 04:05:06 America/New_York');
106 $dateTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
107 $output = array(
108 'year' => (string) (int) $dateTime->format('Y'),
109 'month' => (string) (int) $dateTime->format('m'),
110 'day' => (string) (int) $dateTime->format('d'),
111 'hour' => (string) (int) $dateTime->format('H'),
112 'minute' => (string) (int) $dateTime->format('i'),
113 'second' => (string) (int) $dateTime->format('s'),
114 );
115
116 $this->assertSame($output, $transformer->transform($input));
117 }
118
119 /**
120 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
121 */
122 public function testTransformRequiresDateTime()
123 {
124 $transformer = new DateTimeToArrayTransformer();
125 $transformer->reverseTransform('12345');
126 }
127
128 public function testReverseTransform()
129 {
130 $transformer = new DateTimeToArrayTransformer('UTC', 'UTC');
131
132 $input = array(
133 'year' => '2010',
134 'month' => '2',
135 'day' => '3',
136 'hour' => '4',
137 'minute' => '5',
138 'second' => '6',
139 );
140
141 $output = new \DateTime('2010-02-03 04:05:06 UTC');
142
143 $this->assertDateTimeEquals($output, $transformer->reverseTransform($input));
144 }
145
146 public function testReverseTransformWithSomeZero()
147 {
148 $transformer = new DateTimeToArrayTransformer('UTC', 'UTC');
149
150 $input = array(
151 'year' => '2010',
152 'month' => '2',
153 'day' => '3',
154 'hour' => '4',
155 'minute' => '0',
156 'second' => '0',
157 );
158
159 $output = new \DateTime('2010-02-03 04:00:00 UTC');
160
161 $this->assertDateTimeEquals($output, $transformer->reverseTransform($input));
162 }
163
164 public function testReverseTransformCompletelyEmpty()
165 {
166 $transformer = new DateTimeToArrayTransformer();
167
168 $input = array(
169 'year' => '',
170 'month' => '',
171 'day' => '',
172 'hour' => '',
173 'minute' => '',
174 'second' => '',
175 );
176
177 $this->assertNull($transformer->reverseTransform($input));
178 }
179
180 public function testReverseTransformCompletelyEmptySubsetOfFields()
181 {
182 $transformer = new DateTimeToArrayTransformer(null, null, array('year', 'month', 'day'));
183
184 $input = array(
185 'year' => '',
186 'month' => '',
187 'day' => '',
188 );
189
190 $this->assertNull($transformer->reverseTransform($input));
191 }
192
193 /**
194 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
195 */
196 public function testReverseTransformPartiallyEmptyYear()
197 {
198 $transformer = new DateTimeToArrayTransformer();
199 $transformer->reverseTransform(array(
200 'month' => '2',
201 'day' => '3',
202 'hour' => '4',
203 'minute' => '5',
204 'second' => '6',
205 ));
206 }
207
208 /**
209 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
210 */
211 public function testReverseTransformPartiallyEmptyMonth()
212 {
213 $transformer = new DateTimeToArrayTransformer();
214 $transformer->reverseTransform(array(
215 'year' => '2010',
216 'day' => '3',
217 'hour' => '4',
218 'minute' => '5',
219 'second' => '6',
220 ));
221 }
222
223 /**
224 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
225 */
226 public function testReverseTransformPartiallyEmptyDay()
227 {
228 $transformer = new DateTimeToArrayTransformer();
229 $transformer->reverseTransform(array(
230 'year' => '2010',
231 'month' => '2',
232 'hour' => '4',
233 'minute' => '5',
234 'second' => '6',
235 ));
236 }
237
238 /**
239 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
240 */
241 public function testReverseTransformPartiallyEmptyHour()
242 {
243 $transformer = new DateTimeToArrayTransformer();
244 $transformer->reverseTransform(array(
245 'year' => '2010',
246 'month' => '2',
247 'day' => '3',
248 'minute' => '5',
249 'second' => '6',
250 ));
251 }
252
253 /**
254 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
255 */
256 public function testReverseTransformPartiallyEmptyMinute()
257 {
258 $transformer = new DateTimeToArrayTransformer();
259 $transformer->reverseTransform(array(
260 'year' => '2010',
261 'month' => '2',
262 'day' => '3',
263 'hour' => '4',
264 'second' => '6',
265 ));
266 }
267
268 /**
269 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
270 */
271 public function testReverseTransformPartiallyEmptySecond()
272 {
273 $transformer = new DateTimeToArrayTransformer();
274 $transformer->reverseTransform(array(
275 'year' => '2010',
276 'month' => '2',
277 'day' => '3',
278 'hour' => '4',
279 'minute' => '5',
280 ));
281 }
282
283 public function testReverseTransformNull()
284 {
285 $transformer = new DateTimeToArrayTransformer();
286
287 $this->assertNull($transformer->reverseTransform(null));
288 }
289
290 public function testReverseTransformDifferentTimezones()
291 {
292 $transformer = new DateTimeToArrayTransformer('America/New_York', 'Asia/Hong_Kong');
293
294 $input = array(
295 'year' => '2010',
296 'month' => '2',
297 'day' => '3',
298 'hour' => '4',
299 'minute' => '5',
300 'second' => '6',
301 );
302
303 $output = new \DateTime('2010-02-03 04:05:06 Asia/Hong_Kong');
304 $output->setTimezone(new \DateTimeZone('America/New_York'));
305
306 $this->assertDateTimeEquals($output, $transformer->reverseTransform($input));
307 }
308
309 public function testReverseTransformToDifferentTimezone()
310 {
311 $transformer = new DateTimeToArrayTransformer('Asia/Hong_Kong', 'UTC');
312
313 $input = array(
314 'year' => '2010',
315 'month' => '2',
316 'day' => '3',
317 'hour' => '4',
318 'minute' => '5',
319 'second' => '6',
320 );
321
322 $output = new \DateTime('2010-02-03 04:05:06 UTC');
323 $output->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
324
325 $this->assertDateTimeEquals($output, $transformer->reverseTransform($input));
326 }
327
328 /**
329 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
330 */
331 public function testReverseTransformRequiresArray()
332 {
333 $transformer = new DateTimeToArrayTransformer();
334 $transformer->reverseTransform('12345');
335 }
336
337 /**
338 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
339 */
340 public function testReverseTransformWithNegativeYear()
341 {
342 $transformer = new DateTimeToArrayTransformer();
343 $transformer->reverseTransform(array(
344 'year' => '-1',
345 'month' => '2',
346 'day' => '3',
347 'hour' => '4',
348 'minute' => '5',
349 'second' => '6',
350 ));
351 }
352
353 /**
354 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
355 */
356 public function testReverseTransformWithNegativeMonth()
357 {
358 $transformer = new DateTimeToArrayTransformer();
359 $transformer->reverseTransform(array(
360 'year' => '2010',
361 'month' => '-1',
362 'day' => '3',
363 'hour' => '4',
364 'minute' => '5',
365 'second' => '6',
366 ));
367 }
368
369 /**
370 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
371 */
372 public function testReverseTransformWithNegativeDay()
373 {
374 $transformer = new DateTimeToArrayTransformer();
375 $transformer->reverseTransform(array(
376 'year' => '2010',
377 'month' => '2',
378 'day' => '-1',
379 'hour' => '4',
380 'minute' => '5',
381 'second' => '6',
382 ));
383 }
384
385 /**
386 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
387 */
388 public function testReverseTransformWithNegativeHour()
389 {
390 $transformer = new DateTimeToArrayTransformer();
391 $transformer->reverseTransform(array(
392 'year' => '2010',
393 'month' => '2',
394 'day' => '3',
395 'hour' => '-1',
396 'minute' => '5',
397 'second' => '6',
398 ));
399 }
400
401 /**
402 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
403 */
404 public function testReverseTransformWithNegativeMinute()
405 {
406 $transformer = new DateTimeToArrayTransformer();
407 $transformer->reverseTransform(array(
408 'year' => '2010',
409 'month' => '2',
410 'day' => '3',
411 'hour' => '4',
412 'minute' => '-1',
413 'second' => '6',
414 ));
415 }
416
417 /**
418 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
419 */
420 public function testReverseTransformWithNegativeSecond()
421 {
422 $transformer = new DateTimeToArrayTransformer();
423 $transformer->reverseTransform(array(
424 'year' => '2010',
425 'month' => '2',
426 'day' => '3',
427 'hour' => '4',
428 'minute' => '5',
429 'second' => '-1',
430 ));
431 }
432
433 /**
434 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
435 */
436 public function testReverseTransformWithInvalidMonth()
437 {
438 $transformer = new DateTimeToArrayTransformer();
439 $transformer->reverseTransform(array(
440 'year' => '2010',
441 'month' => '13',
442 'day' => '3',
443 'hour' => '4',
444 'minute' => '5',
445 'second' => '6',
446 ));
447 }
448
449 /**
450 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
451 */
452 public function testReverseTransformWithInvalidDay()
453 {
454 $transformer = new DateTimeToArrayTransformer();
455 $transformer->reverseTransform(array(
456 'year' => '2010',
457 'month' => '2',
458 'day' => '31',
459 'hour' => '4',
460 'minute' => '5',
461 'second' => '6',
462 ));
463 }
464
465 /**
466 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
467 */
468 public function testReverseTransformWithStringDay()
469 {
470 $transformer = new DateTimeToArrayTransformer();
471 $transformer->reverseTransform(array(
472 'year' => '2010',
473 'month' => '2',
474 'day' => 'bazinga',
475 'hour' => '4',
476 'minute' => '5',
477 'second' => '6',
478 ));
479 }
480
481 /**
482 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
483 */
484 public function testReverseTransformWithStringMonth()
485 {
486 $transformer = new DateTimeToArrayTransformer();
487 $transformer->reverseTransform(array(
488 'year' => '2010',
489 'month' => 'bazinga',
490 'day' => '31',
491 'hour' => '4',
492 'minute' => '5',
493 'second' => '6',
494 ));
495 }
496
497 /**
498 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
499 */
500 public function testReverseTransformWithStringYear()
501 {
502 $transformer = new DateTimeToArrayTransformer();
503 $transformer->reverseTransform(array(
504 'year' => 'bazinga',
505 'month' => '2',
506 'day' => '31',
507 'hour' => '4',
508 'minute' => '5',
509 'second' => '6',
510 ));
511 }
512}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
new file mode 100644
index 00000000..cb50fc36
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
@@ -0,0 +1,275 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase
18{
19 protected $dateTime;
20 protected $dateTimeWithoutSeconds;
21
22 protected function setUp()
23 {
24 parent::setUp();
25
26 // Since we test against "de_AT", we need the full implementation
27 IntlTestHelper::requireFullIntl($this);
28
29 \Locale::setDefault('de_AT');
30
31 $this->dateTime = new \DateTime('2010-02-03 04:05:06 UTC');
32 $this->dateTimeWithoutSeconds = new \DateTime('2010-02-03 04:05:00 UTC');
33 }
34
35 protected function tearDown()
36 {
37 $this->dateTime = null;
38 $this->dateTimeWithoutSeconds = null;
39 }
40
41 public static function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
42 {
43 if ($expected instanceof \DateTime && $actual instanceof \DateTime) {
44 $expected = $expected->format('c');
45 $actual = $actual->format('c');
46 }
47
48 parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase);
49 }
50
51 public function dataProvider()
52 {
53 return array(
54 array(\IntlDateFormatter::SHORT, null, null, '03.02.10 04:05', '2010-02-03 04:05:00 UTC'),
55 array(\IntlDateFormatter::MEDIUM, null, null, '03.02.2010 04:05', '2010-02-03 04:05:00 UTC'),
56 array(\IntlDateFormatter::LONG, null, null, '03. Februar 2010 04:05', '2010-02-03 04:05:00 UTC'),
57 array(\IntlDateFormatter::FULL, null, null, 'Mittwoch, 03. Februar 2010 04:05', '2010-02-03 04:05:00 UTC'),
58 array(\IntlDateFormatter::SHORT, \IntlDateFormatter::NONE, null, '03.02.10', '2010-02-03 00:00:00 UTC'),
59 array(\IntlDateFormatter::MEDIUM, \IntlDateFormatter::NONE, null, '03.02.2010', '2010-02-03 00:00:00 UTC'),
60 array(\IntlDateFormatter::LONG, \IntlDateFormatter::NONE, null, '03. Februar 2010', '2010-02-03 00:00:00 UTC'),
61 array(\IntlDateFormatter::FULL, \IntlDateFormatter::NONE, null, 'Mittwoch, 03. Februar 2010', '2010-02-03 00:00:00 UTC'),
62 array(null, \IntlDateFormatter::SHORT, null, '03.02.2010 04:05', '2010-02-03 04:05:00 UTC'),
63 array(null, \IntlDateFormatter::MEDIUM, null, '03.02.2010 04:05:06', '2010-02-03 04:05:06 UTC'),
64 array(null, \IntlDateFormatter::LONG, null, '03.02.2010 04:05:06 GMT', '2010-02-03 04:05:06 UTC'),
65 // see below for extra test case for time format FULL
66 array(\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT, null, '04:05', '1970-01-01 04:05:00 UTC'),
67 array(\IntlDateFormatter::NONE, \IntlDateFormatter::MEDIUM, null, '04:05:06', '1970-01-01 04:05:06 UTC'),
68 array(\IntlDateFormatter::NONE, \IntlDateFormatter::LONG, null, '04:05:06 GMT', '1970-01-01 04:05:06 UTC'),
69 array(null, null, 'yyyy-MM-dd HH:mm:00', '2010-02-03 04:05:00', '2010-02-03 04:05:00 UTC'),
70 array(null, null, 'yyyy-MM-dd HH:mm', '2010-02-03 04:05', '2010-02-03 04:05:00 UTC'),
71 array(null, null, 'yyyy-MM-dd HH', '2010-02-03 04', '2010-02-03 04:00:00 UTC'),
72 array(null, null, 'yyyy-MM-dd', '2010-02-03', '2010-02-03 00:00:00 UTC'),
73 array(null, null, 'yyyy-MM', '2010-02', '2010-02-01 00:00:00 UTC'),
74 array(null, null, 'yyyy', '2010', '2010-01-01 00:00:00 UTC'),
75 array(null, null, 'dd-MM-yyyy', '03-02-2010', '2010-02-03 00:00:00 UTC'),
76 array(null, null, 'HH:mm:ss', '04:05:06', '1970-01-01 04:05:06 UTC'),
77 array(null, null, 'HH:mm:00', '04:05:00', '1970-01-01 04:05:00 UTC'),
78 array(null, null, 'HH:mm', '04:05', '1970-01-01 04:05:00 UTC'),
79 array(null, null, 'HH', '04', '1970-01-01 04:00:00 UTC'),
80 );
81 }
82
83 /**
84 * @dataProvider dataProvider
85 */
86 public function testTransform($dateFormat, $timeFormat, $pattern, $output, $input)
87 {
88 $transformer = new DateTimeToLocalizedStringTransformer(
89 'UTC',
90 'UTC',
91 $dateFormat,
92 $timeFormat,
93 \IntlDateFormatter::GREGORIAN,
94 $pattern
95 );
96
97 $input = new \DateTime($input);
98
99 $this->assertEquals($output, $transformer->transform($input));
100 }
101
102 public function testTransformFullTime()
103 {
104 $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::FULL);
105
106 $this->assertEquals('03.02.2010 04:05:06 GMT', $transformer->transform($this->dateTime));
107 }
108
109 public function testTransformToDifferentLocale()
110 {
111 \Locale::setDefault('en_US');
112
113 $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC');
114
115 $this->assertEquals('Feb 3, 2010, 4:05 AM', $transformer->transform($this->dateTime));
116 }
117
118 public function testTransformEmpty()
119 {
120 $transformer = new DateTimeToLocalizedStringTransformer();
121
122 $this->assertSame('', $transformer->transform(null));
123 }
124
125 public function testTransformWithDifferentTimezones()
126 {
127 $transformer = new DateTimeToLocalizedStringTransformer('America/New_York', 'Asia/Hong_Kong');
128
129 $input = new \DateTime('2010-02-03 04:05:06 America/New_York');
130
131 $dateTime = clone $input;
132 $dateTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
133
134 $this->assertEquals($dateTime->format('d.m.Y H:i'), $transformer->transform($input));
135 }
136
137 public function testTransformWithDifferentPatterns()
138 {
139 $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, 'MM*yyyy*dd HH|mm|ss');
140
141 $this->assertEquals('02*2010*03 04|05|06', $transformer->transform($this->dateTime));
142 }
143
144 /**
145 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
146 */
147 public function testTransformRequiresValidDateTime()
148 {
149 $transformer = new DateTimeToLocalizedStringTransformer();
150 $transformer->transform('2010-01-01');
151 }
152
153 public function testTransformWrapsIntlErrors()
154 {
155 $transformer = new DateTimeToLocalizedStringTransformer();
156
157 // HOW TO REPRODUCE?
158
159 //$this->setExpectedException('Symfony\Component\Form\Extension\Core\DataTransformer\Transdate_formationFailedException');
160
161 //$transformer->transform(1.5);
162 }
163
164 /**
165 * @dataProvider dataProvider
166 */
167 public function testReverseTransform($dateFormat, $timeFormat, $pattern, $input, $output)
168 {
169 $transformer = new DateTimeToLocalizedStringTransformer(
170 'UTC',
171 'UTC',
172 $dateFormat,
173 $timeFormat,
174 \IntlDateFormatter::GREGORIAN,
175 $pattern
176 );
177
178 $output = new \DateTime($output);
179
180 $this->assertEquals($output, $transformer->reverseTransform($input));
181 }
182
183 public function testReverseTransformFullTime()
184 {
185 $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::FULL);
186
187 $this->assertDateTimeEquals($this->dateTime, $transformer->reverseTransform('03.02.2010 04:05:06 GMT+00:00'));
188 }
189
190 public function testReverseTransformFromDifferentLocale()
191 {
192 \Locale::setDefault('en_US');
193
194 $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC');
195
196 $this->assertDateTimeEquals($this->dateTimeWithoutSeconds, $transformer->reverseTransform('Feb 3, 2010, 04:05 AM'));
197 }
198
199 public function testReverseTransformWithDifferentTimezones()
200 {
201 $transformer = new DateTimeToLocalizedStringTransformer('America/New_York', 'Asia/Hong_Kong');
202
203 $dateTime = new \DateTime('2010-02-03 04:05:00 Asia/Hong_Kong');
204 $dateTime->setTimezone(new \DateTimeZone('America/New_York'));
205
206 $this->assertDateTimeEquals($dateTime, $transformer->reverseTransform('03.02.2010 04:05'));
207 }
208
209 public function testReverseTransformWithDifferentPatterns()
210 {
211 $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, 'MM*yyyy*dd HH|mm|ss');
212
213 $this->assertDateTimeEquals($this->dateTime, $transformer->reverseTransform('02*2010*03 04|05|06'));
214 }
215
216 public function testReverseTransformEmpty()
217 {
218 $transformer = new DateTimeToLocalizedStringTransformer();
219
220 $this->assertNull($transformer->reverseTransform(''));
221 }
222
223 /**
224 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
225 */
226 public function testReverseTransformRequiresString()
227 {
228 $transformer = new DateTimeToLocalizedStringTransformer();
229 $transformer->reverseTransform(12345);
230 }
231
232 /**
233 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
234 */
235 public function testReverseTransformWrapsIntlErrors()
236 {
237 $transformer = new DateTimeToLocalizedStringTransformer();
238 $transformer->reverseTransform('12345');
239 }
240
241 /**
242 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
243 */
244 public function testValidateDateFormatOption()
245 {
246 new DateTimeToLocalizedStringTransformer(null, null, 'foobar');
247 }
248
249 /**
250 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
251 */
252 public function testValidateTimeFormatOption()
253 {
254 new DateTimeToLocalizedStringTransformer(null, null, null, 'foobar');
255 }
256
257 /**
258 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
259 */
260 public function testReverseTransformWithNonExistingDate()
261 {
262 $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::SHORT);
263
264 $this->assertDateTimeEquals($this->dateTimeWithoutSeconds, $transformer->reverseTransform('31.04.10 04:05'));
265 }
266
267 /**
268 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
269 */
270 public function testReverseTransformOutOfTimestampRange()
271 {
272 $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC');
273 $transformer->reverseTransform('1789-07-14');
274 }
275}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
new file mode 100644
index 00000000..98aeb772
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
@@ -0,0 +1,132 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToRfc3339Transformer;
15
16class DateTimeToRfc3339TransformerTest extends DateTimeTestCase
17{
18 protected $dateTime;
19 protected $dateTimeWithoutSeconds;
20
21 protected function setUp()
22 {
23 parent::setUp();
24
25 $this->dateTime = new \DateTime('2010-02-03 04:05:06 UTC');
26 $this->dateTimeWithoutSeconds = new \DateTime('2010-02-03 04:05:00 UTC');
27 }
28
29 protected function tearDown()
30 {
31 $this->dateTime = null;
32 $this->dateTimeWithoutSeconds = null;
33 }
34
35 public static function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE)
36 {
37 if ($expected instanceof \DateTime && $actual instanceof \DateTime) {
38 $expected = $expected->format('c');
39 $actual = $actual->format('c');
40 }
41
42 parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase);
43 }
44
45 public function allProvider()
46 {
47 return array(
48 array('UTC', 'UTC', '2010-02-03 04:05:06 UTC', '2010-02-03T04:05:06Z'),
49 array('UTC', 'UTC', null, ''),
50 array('America/New_York', 'Asia/Hong_Kong', '2010-02-03 04:05:06 America/New_York', '2010-02-03T17:05:06+08:00'),
51 array('America/New_York', 'Asia/Hong_Kong', null, ''),
52 array('UTC', 'Asia/Hong_Kong', '2010-02-03 04:05:06 UTC', '2010-02-03T12:05:06+08:00'),
53 array('America/New_York', 'UTC', '2010-02-03 04:05:06 America/New_York', '2010-02-03T09:05:06Z'),
54 );
55 }
56
57 public function transformProvider()
58 {
59 return $this->allProvider();
60 }
61
62 public function reverseTransformProvider()
63 {
64 return array_merge($this->allProvider(), array(
65 // format without seconds, as appears in some browsers
66 array('UTC', 'UTC', '2010-02-03 04:05:00 UTC', '2010-02-03T04:05Z'),
67 array('America/New_York', 'Asia/Hong_Kong', '2010-02-03 04:05:00 America/New_York', '2010-02-03T17:05+08:00'),
68 ));
69 }
70
71 /**
72 * @dataProvider transformProvider
73 */
74 public function testTransform($fromTz, $toTz, $from, $to)
75 {
76 $transformer = new DateTimeToRfc3339Transformer($fromTz, $toTz);
77
78 $this->assertSame($to, $transformer->transform(null !== $from ? new \DateTime($from) : null));
79 }
80
81 /**
82 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
83 */
84 public function testTransformRequiresValidDateTime()
85 {
86 $transformer = new DateTimeToRfc3339Transformer();
87 $transformer->transform('2010-01-01');
88 }
89
90 /**
91 * @dataProvider reverseTransformProvider
92 */
93 public function testReverseTransform($toTz, $fromTz, $to, $from)
94 {
95 $transformer = new DateTimeToRfc3339Transformer($toTz, $fromTz);
96
97 if (null !== $to) {
98 $this->assertDateTimeEquals(new \DateTime($to), $transformer->reverseTransform($from));
99 } else {
100 $this->assertSame($to, $transformer->reverseTransform($from));
101 }
102 }
103
104 /**
105 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
106 */
107 public function testReverseTransformRequiresString()
108 {
109 $transformer = new DateTimeToRfc3339Transformer();
110 $transformer->reverseTransform(12345);
111 }
112
113 /**
114 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
115 */
116 public function testReverseTransformWithNonExistingDate()
117 {
118 $transformer = new DateTimeToRfc3339Transformer('UTC', 'UTC');
119
120 $transformer->reverseTransform('2010-04-31T04:05Z');
121 }
122
123 /**
124 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
125 */
126 public function testReverseTransformExpectsValidDateString()
127 {
128 $transformer = new DateTimeToRfc3339Transformer('UTC', 'UTC');
129
130 $transformer->reverseTransform('2010-2010-2010');
131 }
132}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php
new file mode 100644
index 00000000..987df1d8
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php
@@ -0,0 +1,181 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
15
16class DateTimeToStringTransformerTest extends DateTimeTestCase
17{
18 public function dataProvider()
19 {
20 $data = array(
21 array('Y-m-d H:i:s', '2010-02-03 16:05:06', '2010-02-03 16:05:06 UTC'),
22 array('Y-m-d H:i:00', '2010-02-03 16:05:00', '2010-02-03 16:05:00 UTC'),
23 array('Y-m-d H:i', '2010-02-03 16:05', '2010-02-03 16:05:00 UTC'),
24 array('Y-m-d H', '2010-02-03 16', '2010-02-03 16:00:00 UTC'),
25 array('Y-m-d', '2010-02-03', '2010-02-03 00:00:00 UTC'),
26 array('Y-m', '2010-12', '2010-12-01 00:00:00 UTC'),
27 array('Y', '2010', '2010-01-01 00:00:00 UTC'),
28 array('d-m-Y', '03-02-2010', '2010-02-03 00:00:00 UTC'),
29 array('H:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'),
30 array('H:i:00', '16:05:00', '1970-01-01 16:05:00 UTC'),
31 array('H:i', '16:05', '1970-01-01 16:05:00 UTC'),
32 array('H', '16', '1970-01-01 16:00:00 UTC'),
33
34 // different day representations
35 array('Y-m-j', '2010-02-3', '2010-02-03 00:00:00 UTC'),
36 array('z', '33', '1970-02-03 00:00:00 UTC'),
37
38 // not bijective
39 // this will not work as php will use actual date to replace missing info
40 // and after change of date will lookup for closest Wednesday
41 // i.e. value: 2010-02, php value: 2010-02-(today i.e. 20), parsed date: 2010-02-24
42 //array('Y-m-D', '2010-02-Wed', '2010-02-03 00:00:00 UTC'),
43 //array('Y-m-l', '2010-02-Wednesday', '2010-02-03 00:00:00 UTC'),
44
45 // different month representations
46 array('Y-n-d', '2010-2-03', '2010-02-03 00:00:00 UTC'),
47 array('Y-M-d', '2010-Feb-03', '2010-02-03 00:00:00 UTC'),
48 array('Y-F-d', '2010-February-03', '2010-02-03 00:00:00 UTC'),
49
50 // different year representations
51 array('y-m-d', '10-02-03', '2010-02-03 00:00:00 UTC'),
52
53 // different time representations
54 array('G:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'),
55 array('g:i:s a', '4:05:06 pm', '1970-01-01 16:05:06 UTC'),
56 array('h:i:s a', '04:05:06 pm', '1970-01-01 16:05:06 UTC'),
57
58 // seconds since unix
59 array('U', '1265213106', '2010-02-03 16:05:06 UTC'),
60 );
61
62 // This test will fail < 5.3.9 - see https://bugs.php.net/51994
63 if (version_compare(phpversion(), '5.3.9', '>=')) {
64 $data[] = array('Y-z', '2010-33', '2010-02-03 00:00:00 UTC');
65 }
66
67 return $data;
68 }
69
70 /**
71 * @dataProvider dataProvider
72 */
73 public function testTransform($format, $output, $input)
74 {
75 $transformer = new DateTimeToStringTransformer('UTC', 'UTC', $format);
76
77 $input = new \DateTime($input);
78
79 $this->assertEquals($output, $transformer->transform($input));
80 }
81
82 public function testTransformEmpty()
83 {
84 $transformer = new DateTimeToStringTransformer();
85
86 $this->assertSame('', $transformer->transform(null));
87 }
88
89 public function testTransformWithDifferentTimezones()
90 {
91 $transformer = new DateTimeToStringTransformer('Asia/Hong_Kong', 'America/New_York', 'Y-m-d H:i:s');
92
93 $input = new \DateTime('2010-02-03 12:05:06 America/New_York');
94 $output = $input->format('Y-m-d H:i:s');
95 $input->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
96
97 $this->assertEquals($output, $transformer->transform($input));
98 }
99
100 public function testTransformExpectsDateTime()
101 {
102 $transformer = new DateTimeToStringTransformer();
103
104 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
105
106 $transformer->transform('1234');
107 }
108
109 /**
110 * @dataProvider dataProvider
111 */
112 public function testReverseTransformUsingPipe($format, $input, $output)
113 {
114 if (version_compare(phpversion(), '5.3.7', '<')) {
115 $this->markTestSkipped('Pipe usage requires PHP 5.3.7 or newer.');
116 }
117
118 $reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format, true);
119
120 $output = new \DateTime($output);
121
122 $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
123 }
124
125 /**
126 * @dataProvider dataProvider
127 */
128 public function testReverseTransformWithoutUsingPipe($format, $input, $output)
129 {
130 $reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format, false);
131
132 $output = new \DateTime($output);
133
134 $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
135 }
136
137 public function testReverseTransformEmpty()
138 {
139 $reverseTransformer = new DateTimeToStringTransformer();
140
141 $this->assertNull($reverseTransformer->reverseTransform(''));
142 }
143
144 public function testReverseTransformWithDifferentTimezones()
145 {
146 $reverseTransformer = new DateTimeToStringTransformer('America/New_York', 'Asia/Hong_Kong', 'Y-m-d H:i:s');
147
148 $output = new \DateTime('2010-02-03 16:05:06 Asia/Hong_Kong');
149 $input = $output->format('Y-m-d H:i:s');
150 $output->setTimeZone(new \DateTimeZone('America/New_York'));
151
152 $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
153 }
154
155 public function testReverseTransformExpectsString()
156 {
157 $reverseTransformer = new DateTimeToStringTransformer();
158
159 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
160
161 $reverseTransformer->reverseTransform(1234);
162 }
163
164 public function testReverseTransformExpectsValidDateString()
165 {
166 $reverseTransformer = new DateTimeToStringTransformer();
167
168 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
169
170 $reverseTransformer->reverseTransform('2010-2010-2010');
171 }
172
173 public function testReverseTransformWithNonExistingDate()
174 {
175 $reverseTransformer = new DateTimeToStringTransformer();
176
177 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
178
179 $reverseTransformer->reverseTransform('2010-04-31');
180 }
181}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php
new file mode 100644
index 00000000..b54f0c4c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php
@@ -0,0 +1,104 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
15
16class DateTimeToTimestampTransformerTest extends DateTimeTestCase
17{
18 public function testTransform()
19 {
20 $transformer = new DateTimeToTimestampTransformer('UTC', 'UTC');
21
22 $input = new \DateTime('2010-02-03 04:05:06 UTC');
23 $output = $input->format('U');
24
25 $this->assertEquals($output, $transformer->transform($input));
26 }
27
28 public function testTransformEmpty()
29 {
30 $transformer = new DateTimeToTimestampTransformer();
31
32 $this->assertNull($transformer->transform(null));
33 }
34
35 public function testTransformWithDifferentTimezones()
36 {
37 $transformer = new DateTimeToTimestampTransformer('Asia/Hong_Kong', 'America/New_York');
38
39 $input = new \DateTime('2010-02-03 04:05:06 America/New_York');
40 $output = $input->format('U');
41 $input->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
42
43 $this->assertEquals($output, $transformer->transform($input));
44 }
45
46 public function testTransformFromDifferentTimezone()
47 {
48 $transformer = new DateTimeToTimestampTransformer('Asia/Hong_Kong', 'UTC');
49
50 $input = new \DateTime('2010-02-03 04:05:06 Asia/Hong_Kong');
51
52 $dateTime = clone $input;
53 $dateTime->setTimezone(new \DateTimeZone('UTC'));
54 $output = $dateTime->format('U');
55
56 $this->assertEquals($output, $transformer->transform($input));
57 }
58
59 public function testTransformExpectsDateTime()
60 {
61 $transformer = new DateTimeToTimestampTransformer();
62
63 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
64
65 $transformer->transform('1234');
66 }
67
68 public function testReverseTransform()
69 {
70 $reverseTransformer = new DateTimeToTimestampTransformer('UTC', 'UTC');
71
72 $output = new \DateTime('2010-02-03 04:05:06 UTC');
73 $input = $output->format('U');
74
75 $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
76 }
77
78 public function testReverseTransformEmpty()
79 {
80 $reverseTransformer = new DateTimeToTimestampTransformer();
81
82 $this->assertNull($reverseTransformer->reverseTransform(null));
83 }
84
85 public function testReverseTransformWithDifferentTimezones()
86 {
87 $reverseTransformer = new DateTimeToTimestampTransformer('Asia/Hong_Kong', 'America/New_York');
88
89 $output = new \DateTime('2010-02-03 04:05:06 America/New_York');
90 $input = $output->format('U');
91 $output->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
92
93 $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
94 }
95
96 public function testReverseTransformExpectsValidTimestamp()
97 {
98 $reverseTransformer = new DateTimeToTimestampTransformer();
99
100 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
101
102 $reverseTransformer->reverseTransform('2010-2010-2010');
103 }
104}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php
new file mode 100644
index 00000000..a90fa91b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php
@@ -0,0 +1,115 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class IntegerToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 parent::setUp();
22
23 // Since we test against "de_AT", we need the full implementation
24 IntlTestHelper::requireFullIntl($this);
25
26 \Locale::setDefault('de_AT');
27 }
28
29 public function testReverseTransform()
30 {
31 $transformer = new IntegerToLocalizedStringTransformer();
32
33 $this->assertEquals(1, $transformer->reverseTransform('1'));
34 $this->assertEquals(1, $transformer->reverseTransform('1,5'));
35 $this->assertEquals(1234, $transformer->reverseTransform('1234,5'));
36 $this->assertEquals(12345, $transformer->reverseTransform('12345,912'));
37 }
38
39 public function testReverseTransformEmpty()
40 {
41 $transformer = new IntegerToLocalizedStringTransformer();
42
43 $this->assertNull($transformer->reverseTransform(''));
44 }
45
46 public function testReverseTransformWithGrouping()
47 {
48 $transformer = new IntegerToLocalizedStringTransformer(null, true);
49
50 $this->assertEquals(1234, $transformer->reverseTransform('1.234,5'));
51 $this->assertEquals(12345, $transformer->reverseTransform('12.345,912'));
52 $this->assertEquals(1234, $transformer->reverseTransform('1234,5'));
53 $this->assertEquals(12345, $transformer->reverseTransform('12345,912'));
54 }
55
56 /**
57 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
58 */
59 public function testReverseTransformExpectsString()
60 {
61 $transformer = new IntegerToLocalizedStringTransformer();
62
63 $transformer->reverseTransform(1);
64 }
65
66 /**
67 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
68 */
69 public function testReverseTransformExpectsValidNumber()
70 {
71 $transformer = new IntegerToLocalizedStringTransformer();
72
73 $transformer->reverseTransform('foo');
74 }
75
76 /**
77 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
78 */
79 public function testReverseTransformDisallowsNaN()
80 {
81 $transformer = new IntegerToLocalizedStringTransformer();
82
83 $transformer->reverseTransform('NaN');
84 }
85
86 /**
87 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
88 */
89 public function testReverseTransformDisallowsNaN2()
90 {
91 $transformer = new IntegerToLocalizedStringTransformer();
92
93 $transformer->reverseTransform('nan');
94 }
95
96 /**
97 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
98 */
99 public function testReverseTransformDisallowsInfinity()
100 {
101 $transformer = new IntegerToLocalizedStringTransformer();
102
103 $transformer->reverseTransform('∞');
104 }
105
106 /**
107 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
108 */
109 public function testReverseTransformDisallowsNegativeInfinity()
110 {
111 $transformer = new IntegerToLocalizedStringTransformer();
112
113 $transformer->reverseTransform('-∞');
114 }
115}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php
new file mode 100644
index 00000000..8b91fe10
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php
@@ -0,0 +1,74 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class MoneyToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 parent::setUp();
22
23 // Since we test against "de_AT", we need the full implementation
24 IntlTestHelper::requireFullIntl($this);
25
26 \Locale::setDefault('de_AT');
27 }
28
29 public function testTransform()
30 {
31 $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100);
32
33 $this->assertEquals('1,23', $transformer->transform(123));
34 }
35
36 public function testTransformExpectsNumeric()
37 {
38 $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100);
39
40 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
41
42 $transformer->transform('abcd');
43 }
44
45 public function testTransformEmpty()
46 {
47 $transformer = new MoneyToLocalizedStringTransformer();
48
49 $this->assertSame('', $transformer->transform(null));
50 }
51
52 public function testReverseTransform()
53 {
54 $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100);
55
56 $this->assertEquals(123, $transformer->reverseTransform('1,23'));
57 }
58
59 public function testReverseTransformExpectsString()
60 {
61 $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100);
62
63 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
64
65 $transformer->reverseTransform(12345);
66 }
67
68 public function testReverseTransformEmpty()
69 {
70 $transformer = new MoneyToLocalizedStringTransformer();
71
72 $this->assertNull($transformer->reverseTransform(''));
73 }
74}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php
new file mode 100644
index 00000000..c58e3f60
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php
@@ -0,0 +1,393 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class NumberToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 parent::setUp();
22
23 // Since we test against "de_AT", we need the full implementation
24 IntlTestHelper::requireFullIntl($this);
25
26 \Locale::setDefault('de_AT');
27 }
28
29 public function provideTransformations()
30 {
31 return array(
32 array(null, '', 'de_AT'),
33 array(1, '1', 'de_AT'),
34 array(1.5, '1,5', 'de_AT'),
35 array(1234.5, '1234,5', 'de_AT'),
36 array(12345.912, '12345,912', 'de_AT'),
37 array(1234.5, '1234,5', 'ru'),
38 array(1234.5, '1234,5', 'fi'),
39 );
40 }
41
42 /**
43 * @dataProvider provideTransformations
44 */
45 public function testTransform($from, $to, $locale)
46 {
47 \Locale::setDefault($locale);
48
49 $transformer = new NumberToLocalizedStringTransformer();
50
51 $this->assertSame($to, $transformer->transform($from));
52 }
53
54 public function provideTransformationsWithGrouping()
55 {
56 return array(
57 array(1234.5, '1.234,5', 'de_AT'),
58 array(12345.912, '12.345,912', 'de_AT'),
59 array(1234.5, '1 234,5', 'fr'),
60 array(1234.5, '1 234,5', 'ru'),
61 array(1234.5, '1 234,5', 'fi'),
62 );
63 }
64
65 /**
66 * @dataProvider provideTransformationsWithGrouping
67 */
68 public function testTransformWithGrouping($from, $to, $locale)
69 {
70 \Locale::setDefault($locale);
71
72 $transformer = new NumberToLocalizedStringTransformer(null, true);
73
74 $this->assertSame($to, $transformer->transform($from));
75 }
76
77 public function testTransformWithPrecision()
78 {
79 $transformer = new NumberToLocalizedStringTransformer(2);
80
81 $this->assertEquals('1234,50', $transformer->transform(1234.5));
82 $this->assertEquals('678,92', $transformer->transform(678.916));
83 }
84
85 public function testTransformWithRoundingMode()
86 {
87 $transformer = new NumberToLocalizedStringTransformer(null, null, NumberToLocalizedStringTransformer::ROUND_DOWN);
88 $this->assertEquals('1234,547', $transformer->transform(1234.547), '->transform() only applies rounding mode if precision set');
89
90 $transformer = new NumberToLocalizedStringTransformer(2, null, NumberToLocalizedStringTransformer::ROUND_DOWN);
91 $this->assertEquals('1234,54', $transformer->transform(1234.547), '->transform() rounding-mode works');
92
93 }
94
95 /**
96 * @dataProvider provideTransformations
97 */
98 public function testReverseTransform($to, $from, $locale)
99 {
100 \Locale::setDefault($locale);
101
102 $transformer = new NumberToLocalizedStringTransformer();
103
104 $this->assertEquals($to, $transformer->reverseTransform($from));
105 }
106
107 /**
108 * @dataProvider provideTransformationsWithGrouping
109 */
110 public function testReverseTransformWithGrouping($to, $from, $locale)
111 {
112 \Locale::setDefault($locale);
113
114 $transformer = new NumberToLocalizedStringTransformer(null, true);
115
116 $this->assertEquals($to, $transformer->reverseTransform($from));
117 }
118
119 // https://github.com/symfony/symfony/issues/7609
120 public function testReverseTransformWithGroupingAndFixedSpaces()
121 {
122 if (!extension_loaded('mbstring')) {
123 $this->markTestSkipped('The "mbstring" extension is required for this test.');
124 }
125
126 \Locale::setDefault('ru');
127
128 $transformer = new NumberToLocalizedStringTransformer(null, true);
129
130 $this->assertEquals(1234.5, $transformer->reverseTransform("1\xc2\xa0234,5"));
131 }
132
133 public function testReverseTransformWithGroupingButWithoutGroupSeparator()
134 {
135 $transformer = new NumberToLocalizedStringTransformer(null, true);
136
137 // omit group separator
138 $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
139 $this->assertEquals(12345.912, $transformer->reverseTransform('12345,912'));
140 }
141
142 public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsNotDot()
143 {
144 \Locale::setDefault('fr');
145 $transformer = new NumberToLocalizedStringTransformer(null, true);
146
147 // completely valid format
148 $this->assertEquals(1234.5, $transformer->reverseTransform('1 234,5'));
149 // accept dots
150 $this->assertEquals(1234.5, $transformer->reverseTransform('1 234.5'));
151 // omit group separator
152 $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
153 $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
154 }
155
156 /**
157 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
158 */
159 public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDot()
160 {
161 $transformer = new NumberToLocalizedStringTransformer(null, true);
162
163 $transformer->reverseTransform('1.234.5');
164 }
165
166 /**
167 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
168 */
169 public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDotWithNoGroupSep()
170 {
171 $transformer = new NumberToLocalizedStringTransformer(null, true);
172
173 $transformer->reverseTransform('1234.5');
174 }
175
176 public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsDotButNoGroupingUsed()
177 {
178 \Locale::setDefault('fr');
179 $transformer = new NumberToLocalizedStringTransformer();
180
181 $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
182 $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
183 }
184
185 public function testDecimalSeparatorMayBeCommaIfGroupingSeparatorIsNotComma()
186 {
187 \Locale::setDefault('bg');
188 $transformer = new NumberToLocalizedStringTransformer(null, true);
189
190 // completely valid format
191 $this->assertEquals(1234.5, $transformer->reverseTransform('1 234.5'));
192 // accept commas
193 $this->assertEquals(1234.5, $transformer->reverseTransform('1 234,5'));
194 // omit group separator
195 $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
196 $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
197 }
198
199 /**
200 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
201 */
202 public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsComma()
203 {
204 \Locale::setDefault('en');
205 $transformer = new NumberToLocalizedStringTransformer(null, true);
206
207 $transformer->reverseTransform('1,234,5');
208 }
209
210 /**
211 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
212 */
213 public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsCommaWithNoGroupSep()
214 {
215 \Locale::setDefault('en');
216 $transformer = new NumberToLocalizedStringTransformer(null, true);
217
218 $transformer->reverseTransform('1234,5');
219 }
220
221 public function testDecimalSeparatorMayBeCommaIfGroupingSeparatorIsCommaButNoGroupingUsed()
222 {
223 \Locale::setDefault('en');
224 $transformer = new NumberToLocalizedStringTransformer();
225
226 $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
227 $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
228 }
229
230 /**
231 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
232 */
233 public function testTransformExpectsNumeric()
234 {
235 $transformer = new NumberToLocalizedStringTransformer();
236
237 $transformer->transform('foo');
238 }
239
240 /**
241 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
242 */
243 public function testReverseTransformExpectsString()
244 {
245 $transformer = new NumberToLocalizedStringTransformer();
246
247 $transformer->reverseTransform(1);
248 }
249
250 /**
251 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
252 */
253 public function testReverseTransformExpectsValidNumber()
254 {
255 $transformer = new NumberToLocalizedStringTransformer();
256
257 $transformer->reverseTransform('foo');
258 }
259
260 /**
261 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
262 * @link https://github.com/symfony/symfony/issues/3161
263 */
264 public function testReverseTransformDisallowsNaN()
265 {
266 $transformer = new NumberToLocalizedStringTransformer();
267
268 $transformer->reverseTransform('NaN');
269 }
270
271 /**
272 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
273 */
274 public function testReverseTransformDisallowsNaN2()
275 {
276 $transformer = new NumberToLocalizedStringTransformer();
277
278 $transformer->reverseTransform('nan');
279 }
280
281 /**
282 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
283 */
284 public function testReverseTransformDisallowsInfinity()
285 {
286 $transformer = new NumberToLocalizedStringTransformer();
287
288 $transformer->reverseTransform('∞');
289 }
290
291 /**
292 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
293 */
294 public function testReverseTransformDisallowsInfinity2()
295 {
296 $transformer = new NumberToLocalizedStringTransformer();
297
298 $transformer->reverseTransform('∞,123');
299 }
300
301 /**
302 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
303 */
304 public function testReverseTransformDisallowsNegativeInfinity()
305 {
306 $transformer = new NumberToLocalizedStringTransformer();
307
308 $transformer->reverseTransform('-∞');
309 }
310
311 /**
312 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
313 */
314 public function testReverseTransformDisallowsLeadingExtraCharacters()
315 {
316 $transformer = new NumberToLocalizedStringTransformer();
317
318 $transformer->reverseTransform('foo123');
319 }
320
321 /**
322 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
323 * @expectedExceptionMessage The number contains unrecognized characters: "foo3"
324 */
325 public function testReverseTransformDisallowsCenteredExtraCharacters()
326 {
327 $transformer = new NumberToLocalizedStringTransformer();
328
329 $transformer->reverseTransform('12foo3');
330 }
331
332 /**
333 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
334 * @expectedExceptionMessage The number contains unrecognized characters: "foo8"
335 */
336 public function testReverseTransformDisallowsCenteredExtraCharactersMultibyte()
337 {
338 if (!extension_loaded('mbstring')) {
339 $this->markTestSkipped('The "mbstring" extension is required for this test.');
340 }
341
342 \Locale::setDefault('ru');
343
344 $transformer = new NumberToLocalizedStringTransformer(null, true);
345
346 $transformer->reverseTransform("12\xc2\xa0345,67foo8");
347 }
348
349 /**
350 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
351 * @expectedExceptionMessage The number contains unrecognized characters: "foo8"
352 */
353 public function testReverseTransformIgnoresTrailingSpacesInExceptionMessage()
354 {
355 if (!extension_loaded('mbstring')) {
356 $this->markTestSkipped('The "mbstring" extension is required for this test.');
357 }
358
359 \Locale::setDefault('ru');
360
361 $transformer = new NumberToLocalizedStringTransformer(null, true);
362
363 $transformer->reverseTransform("12\xc2\xa0345,67foo8 \xc2\xa0\t");
364 }
365
366 /**
367 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
368 * @expectedExceptionMessage The number contains unrecognized characters: "foo"
369 */
370 public function testReverseTransformDisallowsTrailingExtraCharacters()
371 {
372 $transformer = new NumberToLocalizedStringTransformer();
373
374 $transformer->reverseTransform('123foo');
375 }
376
377 /**
378 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
379 * @expectedExceptionMessage The number contains unrecognized characters: "foo"
380 */
381 public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte()
382 {
383 if (!extension_loaded('mbstring')) {
384 $this->markTestSkipped('The "mbstring" extension is required for this test.');
385 }
386
387 \Locale::setDefault('ru');
388
389 $transformer = new NumberToLocalizedStringTransformer(null, true);
390
391 $transformer->reverseTransform("12\xc2\xa0345,678foo");
392 }
393}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php
new file mode 100644
index 00000000..104941c9
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php
@@ -0,0 +1,114 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class PercentToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 parent::setUp();
22
23 // Since we test against "de_AT", we need the full implementation
24 IntlTestHelper::requireFullIntl($this);
25
26 \Locale::setDefault('de_AT');
27 }
28
29 public function testTransform()
30 {
31 $transformer = new PercentToLocalizedStringTransformer();
32
33 $this->assertEquals('10', $transformer->transform(0.1));
34 $this->assertEquals('15', $transformer->transform(0.15));
35 $this->assertEquals('12', $transformer->transform(0.1234));
36 $this->assertEquals('200', $transformer->transform(2));
37 }
38
39 public function testTransformEmpty()
40 {
41 $transformer = new PercentToLocalizedStringTransformer();
42
43 $this->assertEquals('', $transformer->transform(null));
44 }
45
46 public function testTransformWithInteger()
47 {
48 $transformer = new PercentToLocalizedStringTransformer(null, 'integer');
49
50 $this->assertEquals('0', $transformer->transform(0.1));
51 $this->assertEquals('1', $transformer->transform(1));
52 $this->assertEquals('15', $transformer->transform(15));
53 $this->assertEquals('16', $transformer->transform(15.9));
54 }
55
56 public function testTransformWithPrecision()
57 {
58 $transformer = new PercentToLocalizedStringTransformer(2);
59
60 $this->assertEquals('12,34', $transformer->transform(0.1234));
61 }
62
63 public function testReverseTransform()
64 {
65 $transformer = new PercentToLocalizedStringTransformer();
66
67 $this->assertEquals(0.1, $transformer->reverseTransform('10'));
68 $this->assertEquals(0.15, $transformer->reverseTransform('15'));
69 $this->assertEquals(0.12, $transformer->reverseTransform('12'));
70 $this->assertEquals(2, $transformer->reverseTransform('200'));
71 }
72
73 public function testReverseTransformEmpty()
74 {
75 $transformer = new PercentToLocalizedStringTransformer();
76
77 $this->assertNull($transformer->reverseTransform(''));
78 }
79
80 public function testReverseTransformWithInteger()
81 {
82 $transformer = new PercentToLocalizedStringTransformer(null, 'integer');
83
84 $this->assertEquals(10, $transformer->reverseTransform('10'));
85 $this->assertEquals(15, $transformer->reverseTransform('15'));
86 $this->assertEquals(12, $transformer->reverseTransform('12'));
87 $this->assertEquals(200, $transformer->reverseTransform('200'));
88 }
89
90 public function testReverseTransformWithPrecision()
91 {
92 $transformer = new PercentToLocalizedStringTransformer(2);
93
94 $this->assertEquals(0.1234, $transformer->reverseTransform('12,34'));
95 }
96
97 public function testTransformExpectsNumeric()
98 {
99 $transformer = new PercentToLocalizedStringTransformer();
100
101 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
102
103 $transformer->transform('foo');
104 }
105
106 public function testReverseTransformExpectsString()
107 {
108 $transformer = new PercentToLocalizedStringTransformer();
109
110 $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
111
112 $transformer->reverseTransform(1);
113 }
114}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ValueToDuplicatesTransformerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ValueToDuplicatesTransformerTest.php
new file mode 100644
index 00000000..2c5298da
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ValueToDuplicatesTransformerTest.php
@@ -0,0 +1,120 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\DataTransformer\ValueToDuplicatesTransformer;
15
16class ValueToDuplicatesTransformerTest extends \PHPUnit_Framework_TestCase
17{
18 private $transformer;
19
20 protected function setUp()
21 {
22 $this->transformer = new ValueToDuplicatesTransformer(array('a', 'b', 'c'));
23 }
24
25 protected function tearDown()
26 {
27 $this->transformer = null;
28 }
29
30 public function testTransform()
31 {
32 $output = array(
33 'a' => 'Foo',
34 'b' => 'Foo',
35 'c' => 'Foo',
36 );
37
38 $this->assertSame($output, $this->transformer->transform('Foo'));
39 }
40
41 public function testTransformEmpty()
42 {
43 $output = array(
44 'a' => null,
45 'b' => null,
46 'c' => null,
47 );
48
49 $this->assertSame($output, $this->transformer->transform(null));
50 }
51
52 public function testReverseTransform()
53 {
54 $input = array(
55 'a' => 'Foo',
56 'b' => 'Foo',
57 'c' => 'Foo',
58 );
59
60 $this->assertSame('Foo', $this->transformer->reverseTransform($input));
61 }
62
63 public function testReverseTransformCompletelyEmpty()
64 {
65 $input = array(
66 'a' => '',
67 'b' => '',
68 'c' => '',
69 );
70
71 $this->assertNull($this->transformer->reverseTransform($input));
72 }
73
74 public function testReverseTransformCompletelyNull()
75 {
76 $input = array(
77 'a' => null,
78 'b' => null,
79 'c' => null,
80 );
81
82 $this->assertNull($this->transformer->reverseTransform($input));
83 }
84
85 /**
86 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
87 */
88 public function testReverseTransformPartiallyNull()
89 {
90 $input = array(
91 'a' => 'Foo',
92 'b' => 'Foo',
93 'c' => null,
94 );
95
96 $this->transformer->reverseTransform($input);
97 }
98
99 /**
100 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
101 */
102 public function testReverseTransformDifferences()
103 {
104 $input = array(
105 'a' => 'Foo',
106 'b' => 'Bar',
107 'c' => 'Foo',
108 );
109
110 $this->transformer->reverseTransform($input);
111 }
112
113 /**
114 * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
115 */
116 public function testReverseTransformRequiresArray()
117 {
118 $this->transformer->reverseTransform('12345');
119 }
120}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixRadioInputListenerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixRadioInputListenerTest.php
new file mode 100644
index 00000000..a5d5c78a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixRadioInputListenerTest.php
@@ -0,0 +1,106 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormEvent;
15use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
16use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
17
18class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
19{
20 private $choiceList;
21
22 protected function setUp()
23 {
24 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
25 $this->markTestSkipped('The "EventDispatcher" component is not available');
26 }
27
28 parent::setUp();
29
30 $this->choiceList = new SimpleChoiceList(array('' => 'Empty', 0 => 'A', 1 => 'B'));
31 }
32
33 protected function tearDown()
34 {
35 parent::tearDown();
36
37 $listener = null;
38 }
39
40 public function testFixRadio()
41 {
42 $data = '1';
43 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
44 $event = new FormEvent($form, $data);
45
46 $listener = new FixRadioInputListener($this->choiceList, true);
47 $listener->preSubmit($event);
48
49 // Indices in SimpleChoiceList are zero-based generated integers
50 $this->assertEquals(array(2 => '1'), $event->getData());
51 }
52
53 public function testFixZero()
54 {
55 $data = '0';
56 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
57 $event = new FormEvent($form, $data);
58
59 $listener = new FixRadioInputListener($this->choiceList, true);
60 $listener->preSubmit($event);
61
62 // Indices in SimpleChoiceList are zero-based generated integers
63 $this->assertEquals(array(1 => '0'), $event->getData());
64 }
65
66 public function testFixEmptyString()
67 {
68 $data = '';
69 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
70 $event = new FormEvent($form, $data);
71
72 $listener = new FixRadioInputListener($this->choiceList, true);
73 $listener->preSubmit($event);
74
75 // Indices in SimpleChoiceList are zero-based generated integers
76 $this->assertEquals(array(0 => ''), $event->getData());
77 }
78
79 public function testConvertEmptyStringToPlaceholderIfNotFound()
80 {
81 $list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
82
83 $data = '';
84 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
85 $event = new FormEvent($form, $data);
86
87 $listener = new FixRadioInputListener($list, true);
88 $listener->preSubmit($event);
89
90 $this->assertEquals(array('placeholder' => ''), $event->getData());
91 }
92
93 public function testDontConvertEmptyStringToPlaceholderIfNoPlaceholderUsed()
94 {
95 $list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
96
97 $data = '';
98 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
99 $event = new FormEvent($form, $data);
100
101 $listener = new FixRadioInputListener($list, false);
102 $listener->preSubmit($event);
103
104 $this->assertEquals(array(), $event->getData());
105 }
106}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php
new file mode 100644
index 00000000..2b84e4fd
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormEvent;
15use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener;
16
17class FixUrlProtocolListenerTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
22 $this->markTestSkipped('The "EventDispatcher" component is not available');
23 }
24 }
25
26 public function testFixHttpUrl()
27 {
28 $data = "www.symfony.com";
29 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
30 $event = new FormEvent($form, $data);
31
32 $filter = new FixUrlProtocolListener('http');
33 $filter->onSubmit($event);
34
35 $this->assertEquals('http://www.symfony.com', $event->getData());
36 }
37
38 public function testSkipKnownUrl()
39 {
40 $data = "http://www.symfony.com";
41 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
42 $event = new FormEvent($form, $data);
43
44 $filter = new FixUrlProtocolListener('http');
45 $filter->onSubmit($event);
46
47 $this->assertEquals('http://www.symfony.com', $event->getData());
48 }
49
50 public function testSkipOtherProtocol()
51 {
52 $data = "ftp://www.symfony.com";
53 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
54 $event = new FormEvent($form, $data);
55
56 $filter = new FixUrlProtocolListener('http');
57 $filter->onSubmit($event);
58
59 $this->assertEquals('ftp://www.symfony.com', $event->getData());
60 }
61}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/Fixtures/randomhash b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/Fixtures/randomhash
new file mode 100644
index 00000000..b636f4b8
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/Fixtures/randomhash
Binary files differ
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayObjectTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayObjectTest.php
new file mode 100644
index 00000000..6f46c9d7
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayObjectTest.php
@@ -0,0 +1,27 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormBuilder;
15
16class MergeCollectionListenerArrayObjectTest extends MergeCollectionListenerTest
17{
18 protected function getData(array $data)
19 {
20 return new \ArrayObject($data);
21 }
22
23 protected function getBuilder($name = 'name')
24 {
25 return new FormBuilder($name, '\ArrayObject', $this->dispatcher, $this->factory);
26 }
27}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayTest.php
new file mode 100644
index 00000000..c0f3d597
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayTest.php
@@ -0,0 +1,27 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormBuilder;
15
16class MergeCollectionListenerArrayTest extends MergeCollectionListenerTest
17{
18 protected function getData(array $data)
19 {
20 return $data;
21 }
22
23 protected function getBuilder($name = 'name')
24 {
25 return new FormBuilder($name, null, $this->dispatcher, $this->factory);
26 }
27}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerCustomArrayObjectTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerCustomArrayObjectTest.php
new file mode 100644
index 00000000..5eb6c7b9
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerCustomArrayObjectTest.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
13
14use Symfony\Component\Form\Tests\Fixtures\CustomArrayObject;
15use Symfony\Component\Form\FormBuilder;
16
17class MergeCollectionListenerCustomArrayObjectTest extends MergeCollectionListenerTest
18{
19 protected function getData(array $data)
20 {
21 return new CustomArrayObject($data);
22 }
23
24 protected function getBuilder($name = 'name')
25 {
26 return new FormBuilder($name, 'Symfony\Component\Form\Tests\Fixtures\CustomArrayObject', $this->dispatcher, $this->factory);
27 }
28}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php
new file mode 100644
index 00000000..dbd28c6b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php
@@ -0,0 +1,259 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormEvent;
15use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
16
17abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase
18{
19 protected $dispatcher;
20 protected $factory;
21 protected $form;
22
23 protected function setUp()
24 {
25 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
26 $this->markTestSkipped('The "EventDispatcher" component is not available');
27 }
28
29 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
30 $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
31 $this->form = $this->getForm('axes');
32 }
33
34 protected function tearDown()
35 {
36 $this->dispatcher = null;
37 $this->factory = null;
38 $this->form = null;
39 }
40
41 abstract protected function getBuilder($name = 'name');
42
43 protected function getForm($name = 'name', $propertyPath = null)
44 {
45 $propertyPath = $propertyPath ?: $name;
46
47 return $this->getBuilder($name)->setAttribute('property_path', $propertyPath)->getForm();
48 }
49
50 protected function getMockForm()
51 {
52 return $this->getMock('Symfony\Component\Form\Test\FormInterface');
53 }
54
55 public function getBooleanMatrix1()
56 {
57 return array(
58 array(true),
59 array(false),
60 );
61 }
62
63 public function getBooleanMatrix2()
64 {
65 return array(
66 array(true, true),
67 array(true, false),
68 array(false, true),
69 array(false, false),
70 );
71 }
72
73 abstract protected function getData(array $data);
74
75 /**
76 * @dataProvider getBooleanMatrix1
77 */
78 public function testAddExtraEntriesIfAllowAdd($allowDelete)
79 {
80 $originalData = $this->getData(array(1 => 'second'));
81 $newData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
82
83 $listener = new MergeCollectionListener(true, $allowDelete);
84
85 $this->form->setData($originalData);
86
87 $event = new FormEvent($this->form, $newData);
88 $listener->onSubmit($event);
89
90 // The original object was modified
91 if (is_object($originalData)) {
92 $this->assertSame($originalData, $event->getData());
93 }
94
95 // The original object matches the new object
96 $this->assertEquals($newData, $event->getData());
97 }
98
99 /**
100 * @dataProvider getBooleanMatrix1
101 */
102 public function testAddExtraEntriesIfAllowAddDontOverwriteExistingIndices($allowDelete)
103 {
104 $originalData = $this->getData(array(1 => 'first'));
105 $newData = $this->getData(array(0 => 'first', 1 => 'second'));
106
107 $listener = new MergeCollectionListener(true, $allowDelete);
108
109 $this->form->setData($originalData);
110
111 $event = new FormEvent($this->form, $newData);
112 $listener->onSubmit($event);
113
114 // The original object was modified
115 if (is_object($originalData)) {
116 $this->assertSame($originalData, $event->getData());
117 }
118
119 // The original object matches the new object
120 $this->assertEquals($this->getData(array(1 => 'first', 2 => 'second')), $event->getData());
121 }
122
123 /**
124 * @dataProvider getBooleanMatrix1
125 */
126 public function testDoNothingIfNotAllowAdd($allowDelete)
127 {
128 $originalDataArray = array(1 => 'second');
129 $originalData = $this->getData($originalDataArray);
130 $newData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
131
132 $listener = new MergeCollectionListener(false, $allowDelete);
133
134 $this->form->setData($originalData);
135
136 $event = new FormEvent($this->form, $newData);
137 $listener->onSubmit($event);
138
139 // We still have the original object
140 if (is_object($originalData)) {
141 $this->assertSame($originalData, $event->getData());
142 }
143
144 // Nothing was removed
145 $this->assertEquals($this->getData($originalDataArray), $event->getData());
146 }
147
148 /**
149 * @dataProvider getBooleanMatrix1
150 */
151 public function testRemoveMissingEntriesIfAllowDelete($allowAdd)
152 {
153 $originalData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
154 $newData = $this->getData(array(1 => 'second'));
155
156 $listener = new MergeCollectionListener($allowAdd, true);
157
158 $this->form->setData($originalData);
159
160 $event = new FormEvent($this->form, $newData);
161 $listener->onSubmit($event);
162
163 // The original object was modified
164 if (is_object($originalData)) {
165 $this->assertSame($originalData, $event->getData());
166 }
167
168 // The original object matches the new object
169 $this->assertEquals($newData, $event->getData());
170 }
171
172 /**
173 * @dataProvider getBooleanMatrix1
174 */
175 public function testDoNothingIfNotAllowDelete($allowAdd)
176 {
177 $originalDataArray = array(0 => 'first', 1 => 'second', 2 => 'third');
178 $originalData = $this->getData($originalDataArray);
179 $newData = $this->getData(array(1 => 'second'));
180
181 $listener = new MergeCollectionListener($allowAdd, false);
182
183 $this->form->setData($originalData);
184
185 $event = new FormEvent($this->form, $newData);
186 $listener->onSubmit($event);
187
188 // We still have the original object
189 if (is_object($originalData)) {
190 $this->assertSame($originalData, $event->getData());
191 }
192
193 // Nothing was removed
194 $this->assertEquals($this->getData($originalDataArray), $event->getData());
195 }
196
197 /**
198 * @dataProvider getBooleanMatrix2
199 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
200 */
201 public function testRequireArrayOrTraversable($allowAdd, $allowDelete)
202 {
203 $newData = 'no array or traversable';
204 $event = new FormEvent($this->form, $newData);
205 $listener = new MergeCollectionListener($allowAdd, $allowDelete);
206 $listener->onSubmit($event);
207 }
208
209 public function testDealWithNullData()
210 {
211 $originalData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
212 $newData = null;
213
214 $listener = new MergeCollectionListener(false, false);
215
216 $this->form->setData($originalData);
217
218 $event = new FormEvent($this->form, $newData);
219 $listener->onSubmit($event);
220
221 $this->assertSame($originalData, $event->getData());
222 }
223
224 /**
225 * @dataProvider getBooleanMatrix1
226 */
227 public function testDealWithNullOriginalDataIfAllowAdd($allowDelete)
228 {
229 $originalData = null;
230 $newData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
231
232 $listener = new MergeCollectionListener(true, $allowDelete);
233
234 $this->form->setData($originalData);
235
236 $event = new FormEvent($this->form, $newData);
237 $listener->onSubmit($event);
238
239 $this->assertSame($newData, $event->getData());
240 }
241
242 /**
243 * @dataProvider getBooleanMatrix1
244 */
245 public function testDontDealWithNullOriginalDataIfNotAllowAdd($allowDelete)
246 {
247 $originalData = null;
248 $newData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
249
250 $listener = new MergeCollectionListener(false, $allowDelete);
251
252 $this->form->setData($originalData);
253
254 $event = new FormEvent($this->form, $newData);
255 $listener->onSubmit($event);
256
257 $this->assertNull($event->getData());
258 }
259}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php
new file mode 100644
index 00000000..1367b3ef
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php
@@ -0,0 +1,255 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
13
14use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
15use Symfony\Component\Form\FormBuilder;
16use Symfony\Component\Form\FormEvent;
17
18class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
19{
20 private $dispatcher;
21 private $factory;
22 private $form;
23
24 protected function setUp()
25 {
26 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
27 $this->markTestSkipped('The "EventDispatcher" component is not available');
28 }
29
30 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
31 $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
32 $this->form = $this->getBuilder()
33 ->setCompound(true)
34 ->setDataMapper($this->getDataMapper())
35 ->getForm();
36 }
37
38 protected function tearDown()
39 {
40 $this->dispatcher = null;
41 $this->factory = null;
42 $this->form = null;
43 }
44
45 protected function getBuilder($name = 'name')
46 {
47 return new FormBuilder($name, null, $this->dispatcher, $this->factory);
48 }
49
50 protected function getForm($name = 'name')
51 {
52 return $this->getBuilder($name)->getForm();
53 }
54
55 /**
56 * @return \PHPUnit_Framework_MockObject_MockObject
57 */
58 private function getDataMapper()
59 {
60 return $this->getMock('Symfony\Component\Form\DataMapperInterface');
61 }
62
63 protected function getMockForm()
64 {
65 return $this->getMock('Symfony\Component\Form\Test\FormInterface');
66 }
67
68 public function testPreSetDataResizesForm()
69 {
70 $this->form->add($this->getForm('0'));
71 $this->form->add($this->getForm('1'));
72
73 $this->factory->expects($this->at(0))
74 ->method('createNamed')
75 ->with(1, 'text', null, array('property_path' => '[1]', 'max_length' => 10, 'auto_initialize' => false))
76 ->will($this->returnValue($this->getForm('1')));
77 $this->factory->expects($this->at(1))
78 ->method('createNamed')
79 ->with(2, 'text', null, array('property_path' => '[2]', 'max_length' => 10, 'auto_initialize' => false))
80 ->will($this->returnValue($this->getForm('2')));
81
82 $data = array(1 => 'string', 2 => 'string');
83 $event = new FormEvent($this->form, $data);
84 $listener = new ResizeFormListener('text', array('max_length' => '10'), false, false);
85 $listener->preSetData($event);
86
87 $this->assertFalse($this->form->has('0'));
88 $this->assertTrue($this->form->has('1'));
89 $this->assertTrue($this->form->has('2'));
90 }
91
92 /**
93 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
94 */
95 public function testPreSetDataRequiresArrayOrTraversable()
96 {
97 $data = 'no array or traversable';
98 $event = new FormEvent($this->form, $data);
99 $listener = new ResizeFormListener('text', array(), false, false);
100 $listener->preSetData($event);
101 }
102
103 public function testPreSetDataDealsWithNullData()
104 {
105 $this->factory->expects($this->never())->method('createNamed');
106
107 $data = null;
108 $event = new FormEvent($this->form, $data);
109 $listener = new ResizeFormListener('text', array(), false, false);
110 $listener->preSetData($event);
111 }
112
113 public function testPreSubmitResizesUpIfAllowAdd()
114 {
115 $this->form->add($this->getForm('0'));
116
117 $this->factory->expects($this->once())
118 ->method('createNamed')
119 ->with(1, 'text', null, array('property_path' => '[1]', 'max_length' => 10, 'auto_initialize' => false))
120 ->will($this->returnValue($this->getForm('1')));
121
122 $data = array(0 => 'string', 1 => 'string');
123 $event = new FormEvent($this->form, $data);
124 $listener = new ResizeFormListener('text', array('max_length' => 10), true, false);
125 $listener->preSubmit($event);
126
127 $this->assertTrue($this->form->has('0'));
128 $this->assertTrue($this->form->has('1'));
129 }
130
131 public function testPreSubmitResizesDownIfAllowDelete()
132 {
133 $this->form->add($this->getForm('0'));
134 $this->form->add($this->getForm('1'));
135
136 $data = array(0 => 'string');
137 $event = new FormEvent($this->form, $data);
138 $listener = new ResizeFormListener('text', array(), false, true);
139 $listener->preSubmit($event);
140
141 $this->assertTrue($this->form->has('0'));
142 $this->assertFalse($this->form->has('1'));
143 }
144
145 // fix for https://github.com/symfony/symfony/pull/493
146 public function testPreSubmitRemovesZeroKeys()
147 {
148 $this->form->add($this->getForm('0'));
149
150 $data = array();
151 $event = new FormEvent($this->form, $data);
152 $listener = new ResizeFormListener('text', array(), false, true);
153 $listener->preSubmit($event);
154
155 $this->assertFalse($this->form->has('0'));
156 }
157
158 public function testPreSubmitDoesNothingIfNotAllowAddNorAllowDelete()
159 {
160 $this->form->add($this->getForm('0'));
161 $this->form->add($this->getForm('1'));
162
163 $data = array(0 => 'string', 2 => 'string');
164 $event = new FormEvent($this->form, $data);
165 $listener = new ResizeFormListener('text', array(), false, false);
166 $listener->preSubmit($event);
167
168 $this->assertTrue($this->form->has('0'));
169 $this->assertTrue($this->form->has('1'));
170 $this->assertFalse($this->form->has('2'));
171 }
172
173 /**
174 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
175 */
176 public function testPreSubmitRequiresArrayOrTraversable()
177 {
178 $data = 'no array or traversable';
179 $event = new FormEvent($this->form, $data);
180 $listener = new ResizeFormListener('text', array(), false, false);
181 $listener->preSubmit($event);
182 }
183
184 public function testPreSubmitDealsWithNullData()
185 {
186 $this->form->add($this->getForm('1'));
187
188 $data = null;
189 $event = new FormEvent($this->form, $data);
190 $listener = new ResizeFormListener('text', array(), false, true);
191 $listener->preSubmit($event);
192
193 $this->assertFalse($this->form->has('1'));
194 }
195
196 // fixes https://github.com/symfony/symfony/pull/40
197 public function testPreSubmitDealsWithEmptyData()
198 {
199 $this->form->add($this->getForm('1'));
200
201 $data = '';
202 $event = new FormEvent($this->form, $data);
203 $listener = new ResizeFormListener('text', array(), false, true);
204 $listener->preSubmit($event);
205
206 $this->assertFalse($this->form->has('1'));
207 }
208
209 public function testOnSubmitNormDataRemovesEntriesMissingInTheFormIfAllowDelete()
210 {
211 $this->form->add($this->getForm('1'));
212
213 $data = array(0 => 'first', 1 => 'second', 2 => 'third');
214 $event = new FormEvent($this->form, $data);
215 $listener = new ResizeFormListener('text', array(), false, true);
216 $listener->onSubmit($event);
217
218 $this->assertEquals(array(1 => 'second'), $event->getData());
219 }
220
221 public function testOnSubmitNormDataDoesNothingIfNotAllowDelete()
222 {
223 $this->form->add($this->getForm('1'));
224
225 $data = array(0 => 'first', 1 => 'second', 2 => 'third');
226 $event = new FormEvent($this->form, $data);
227 $listener = new ResizeFormListener('text', array(), false, false);
228 $listener->onSubmit($event);
229
230 $this->assertEquals($data, $event->getData());
231 }
232
233 /**
234 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
235 */
236 public function testOnSubmitNormDataRequiresArrayOrTraversable()
237 {
238 $data = 'no array or traversable';
239 $event = new FormEvent($this->form, $data);
240 $listener = new ResizeFormListener('text', array(), false, false);
241 $listener->onSubmit($event);
242 }
243
244 public function testOnSubmitNormDataDealsWithNullData()
245 {
246 $this->form->add($this->getForm('1'));
247
248 $data = null;
249 $event = new FormEvent($this->form, $data);
250 $listener = new ResizeFormListener('text', array(), false, true);
251 $listener->onSubmit($event);
252
253 $this->assertEquals(array(), $event->getData());
254 }
255}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php
new file mode 100644
index 00000000..4e368933
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php
@@ -0,0 +1,79 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
13
14use Symfony\Component\Form\FormEvent;
15use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
16
17class TrimListenerTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
22 $this->markTestSkipped('The "EventDispatcher" component is not available');
23 }
24 }
25
26 public function testTrim()
27 {
28 $data = " Foo! ";
29 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
30 $event = new FormEvent($form, $data);
31
32 $filter = new TrimListener();
33 $filter->preSubmit($event);
34
35 $this->assertEquals('Foo!', $event->getData());
36 }
37
38 public function testTrimSkipNonStrings()
39 {
40 $data = 1234;
41 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
42 $event = new FormEvent($form, $data);
43
44 $filter = new TrimListener();
45 $filter->preSubmit($event);
46
47 $this->assertSame(1234, $event->getData());
48 }
49
50 /**
51 * @dataProvider codePointProvider
52 */
53 public function testTrimUtf8($chars)
54 {
55 if (!function_exists('mb_check_encoding')) {
56 $this->markTestSkipped('The "mb_check_encoding" function is not available');
57 }
58
59 $data = mb_convert_encoding(pack('H*', implode('', $chars)), 'UTF-8', 'UCS-2BE');
60 $data = $data."ab\ncd".$data;
61
62 $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
63 $event = new FormEvent($form, $data);
64
65 $filter = new TrimListener();
66 $filter->preSubmit($event);
67
68 $this->assertSame("ab\ncd", $event->getData(), 'TrimListener should trim character(s): '.implode(', ', $chars));
69 }
70
71 public function codePointProvider()
72 {
73 return array(
74 'General category: Separator' => array(array('0020', '00A0', '1680', '180E', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '200A', '2028', '2029', '202F', '205F', '3000')),
75 'General category: Other, control' => array(array('0009', '000A', '000B', '000C', '000D', '0085')),
76 //'General category: Other, format. ZERO WIDTH SPACE' => array(array('200B')),
77 );
78 }
79}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php
new file mode 100644
index 00000000..bfa1e218
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php
@@ -0,0 +1,135 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17abstract class BaseTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
18{
19 public function testPassDisabledAsOption()
20 {
21 $form = $this->factory->create($this->getTestedType(), null, array('disabled' => true));
22
23 $this->assertTrue($form->isDisabled());
24 }
25
26 public function testPassIdAndNameToView()
27 {
28 $view = $this->factory->createNamed('name', $this->getTestedType())
29 ->createView();
30
31 $this->assertEquals('name', $view->vars['id']);
32 $this->assertEquals('name', $view->vars['name']);
33 $this->assertEquals('name', $view->vars['full_name']);
34 }
35
36 public function testStripLeadingUnderscoresAndDigitsFromId()
37 {
38 $view = $this->factory->createNamed('_09name', $this->getTestedType())
39 ->createView();
40
41 $this->assertEquals('name', $view->vars['id']);
42 $this->assertEquals('_09name', $view->vars['name']);
43 $this->assertEquals('_09name', $view->vars['full_name']);
44 }
45
46 public function testPassIdAndNameToViewWithParent()
47 {
48 $view = $this->factory->createNamedBuilder('parent', 'form')
49 ->add('child', $this->getTestedType())
50 ->getForm()
51 ->createView();
52
53 $this->assertEquals('parent_child', $view['child']->vars['id']);
54 $this->assertEquals('child', $view['child']->vars['name']);
55 $this->assertEquals('parent[child]', $view['child']->vars['full_name']);
56 }
57
58 public function testPassIdAndNameToViewWithGrandParent()
59 {
60 $builder = $this->factory->createNamedBuilder('parent', 'form')
61 ->add('child', 'form');
62 $builder->get('child')->add('grand_child', $this->getTestedType());
63 $view = $builder->getForm()->createView();
64
65 $this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->vars['id']);
66 $this->assertEquals('grand_child', $view['child']['grand_child']->vars['name']);
67 $this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->vars['full_name']);
68 }
69
70 public function testPassTranslationDomainToView()
71 {
72 $form = $this->factory->create($this->getTestedType(), null, array(
73 'translation_domain' => 'domain',
74 ));
75 $view = $form->createView();
76
77 $this->assertSame('domain', $view->vars['translation_domain']);
78 }
79
80 public function testInheritTranslationDomainFromParent()
81 {
82 $view = $this->factory
83 ->createNamedBuilder('parent', 'form', null, array(
84 'translation_domain' => 'domain',
85 ))
86 ->add('child', $this->getTestedType())
87 ->getForm()
88 ->createView();
89
90 $this->assertEquals('domain', $view['child']->vars['translation_domain']);
91 }
92
93 public function testPreferOwnTranslationDomain()
94 {
95 $view = $this->factory
96 ->createNamedBuilder('parent', 'form', null, array(
97 'translation_domain' => 'parent_domain',
98 ))
99 ->add('child', $this->getTestedType(), array(
100 'translation_domain' => 'domain',
101 ))
102 ->getForm()
103 ->createView();
104
105 $this->assertEquals('domain', $view['child']->vars['translation_domain']);
106 }
107
108 public function testDefaultTranslationDomain()
109 {
110 $view = $this->factory->createNamedBuilder('parent', 'form')
111 ->add('child', $this->getTestedType())
112 ->getForm()
113 ->createView();
114
115 $this->assertEquals('messages', $view['child']->vars['translation_domain']);
116 }
117
118 public function testPassLabelToView()
119 {
120 $form = $this->factory->createNamed('__test___field', $this->getTestedType(), null, array('label' => 'My label'));
121 $view = $form->createView();
122
123 $this->assertSame('My label', $view->vars['label']);
124 }
125
126 public function testPassMultipartFalseToView()
127 {
128 $form = $this->factory->create($this->getTestedType());
129 $view = $form->createView();
130
131 $this->assertFalse($view->vars['multipart']);
132 }
133
134 abstract protected function getTestedType();
135}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php
new file mode 100644
index 00000000..55835e77
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class ButtonTypeTest extends BaseTypeTest
18{
19 public function testCreateButtonInstances()
20 {
21 $this->assertInstanceOf('Symfony\Component\Form\Button', $this->factory->create('button'));
22 }
23
24 protected function getTestedType()
25 {
26 return 'button';
27 }
28}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CheckboxTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CheckboxTypeTest.php
new file mode 100644
index 00000000..c782adab
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CheckboxTypeTest.php
@@ -0,0 +1,162 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\CallbackTransformer;
15
16class CheckboxTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
17{
18 public function testPassValueToView()
19 {
20 $form = $this->factory->create('checkbox', null, array('value' => 'foobar'));
21 $view = $form->createView();
22
23 $this->assertEquals('foobar', $view->vars['value']);
24 }
25
26 public function testCheckedIfDataTrue()
27 {
28 $form = $this->factory->create('checkbox');
29 $form->setData(true);
30 $view = $form->createView();
31
32 $this->assertTrue($view->vars['checked']);
33 }
34
35 public function testCheckedIfDataTrueWithEmptyValue()
36 {
37 $form = $this->factory->create('checkbox', null, array('value' => ''));
38 $form->setData(true);
39 $view = $form->createView();
40
41 $this->assertTrue($view->vars['checked']);
42 }
43
44 public function testNotCheckedIfDataFalse()
45 {
46 $form = $this->factory->create('checkbox');
47 $form->setData(false);
48 $view = $form->createView();
49
50 $this->assertFalse($view->vars['checked']);
51 }
52
53 public function testSubmitWithValueChecked()
54 {
55 $form = $this->factory->create('checkbox', null, array(
56 'value' => 'foobar',
57 ));
58 $form->submit('foobar');
59
60 $this->assertTrue($form->getData());
61 $this->assertEquals('foobar', $form->getViewData());
62 }
63
64 public function testSubmitWithRandomValueChecked()
65 {
66 $form = $this->factory->create('checkbox', null, array(
67 'value' => 'foobar',
68 ));
69 $form->submit('krixikraxi');
70
71 $this->assertTrue($form->getData());
72 $this->assertEquals('foobar', $form->getViewData());
73 }
74
75 public function testSubmitWithValueUnchecked()
76 {
77 $form = $this->factory->create('checkbox', null, array(
78 'value' => 'foobar',
79 ));
80 $form->submit(null);
81
82 $this->assertFalse($form->getData());
83 $this->assertNull($form->getViewData());
84 }
85
86 public function testSubmitWithEmptyValueChecked()
87 {
88 $form = $this->factory->create('checkbox', null, array(
89 'value' => '',
90 ));
91 $form->submit('');
92
93 $this->assertTrue($form->getData());
94 $this->assertSame('', $form->getViewData());
95 }
96
97 public function testSubmitWithEmptyValueUnchecked()
98 {
99 $form = $this->factory->create('checkbox', null, array(
100 'value' => '',
101 ));
102 $form->submit(null);
103
104 $this->assertFalse($form->getData());
105 $this->assertNull($form->getViewData());
106 }
107
108 public function testBindWithEmptyValueAndFalseUnchecked()
109 {
110 $form = $this->factory->create('checkbox', null, array(
111 'value' => '',
112 ));
113 $form->bind(false);
114
115 $this->assertFalse($form->getData());
116 $this->assertNull($form->getViewData());
117 }
118
119 public function testBindWithEmptyValueAndTrueChecked()
120 {
121 $form = $this->factory->create('checkbox', null, array(
122 'value' => '',
123 ));
124 $form->bind(true);
125
126 $this->assertTrue($form->getData());
127 $this->assertSame('', $form->getViewData());
128 }
129
130 /**
131 * @dataProvider provideTransformedData
132 */
133 public function testTransformedData($data, $expected)
134 {
135 // present a binary status field as a checkbox
136 $transformer = new CallbackTransformer(
137 function ($value) {
138 return 'expedited' == $value;
139 },
140 function ($value) {
141 return $value ? 'expedited' : 'standard';
142 }
143 );
144
145 $form = $this->builder
146 ->create('expedited_shipping', 'checkbox')
147 ->addModelTransformer($transformer)
148 ->getForm();
149 $form->setData($data);
150 $view = $form->createView();
151
152 $this->assertEquals($expected, $view->vars['checked']);
153 }
154
155 public function provideTransformedData()
156 {
157 return array(
158 array('expedited', true),
159 array('standard', false),
160 );
161 }
162}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypePerformanceTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypePerformanceTest.php
new file mode 100644
index 00000000..0685946f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypePerformanceTest.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Test\FormPerformanceTestCase;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class ChoiceTypePerformanceTest extends FormPerformanceTestCase
20{
21 /**
22 * This test case is realistic in collection forms where each
23 * row contains the same choice field.
24 *
25 * @group benchmark
26 */
27 public function testSameChoiceFieldCreatedMultipleTimes()
28 {
29 $this->setMaxRunningTime(1);
30 $choices = range(1, 300);
31
32 for ($i = 0; $i < 100; ++$i) {
33 $this->factory->create('choice', rand(1, 400), array(
34 'choices' => $choices,
35 ));
36 }
37 }
38}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
new file mode 100644
index 00000000..219e8181
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
@@ -0,0 +1,949 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
15use Symfony\Component\Form\Extension\Core\View\ChoiceView;
16
17class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
18{
19 private $choices = array(
20 'a' => 'Bernhard',
21 'b' => 'Fabien',
22 'c' => 'Kris',
23 'd' => 'Jon',
24 'e' => 'Roman',
25 );
26
27 private $numericChoices = array(
28 0 => 'Bernhard',
29 1 => 'Fabien',
30 2 => 'Kris',
31 3 => 'Jon',
32 4 => 'Roman',
33 );
34
35 private $objectChoices;
36
37 protected $groupedChoices = array(
38 'Symfony' => array(
39 'a' => 'Bernhard',
40 'b' => 'Fabien',
41 'c' => 'Kris',
42 ),
43 'Doctrine' => array(
44 'd' => 'Jon',
45 'e' => 'Roman',
46 )
47 );
48
49 protected function setUp()
50 {
51 parent::setUp();
52
53 $this->objectChoices = array(
54 (object) array('id' => 1, 'name' => 'Bernhard'),
55 (object) array('id' => 2, 'name' => 'Fabien'),
56 (object) array('id' => 3, 'name' => 'Kris'),
57 (object) array('id' => 4, 'name' => 'Jon'),
58 (object) array('id' => 5, 'name' => 'Roman'),
59 );
60 }
61
62 protected function tearDown()
63 {
64 parent::tearDown();
65
66 $this->objectChoices = null;
67 }
68
69 /**
70 * @expectedException \PHPUnit_Framework_Error
71 */
72 public function testChoicesOptionExpectsArray()
73 {
74 $this->factory->create('choice', null, array(
75 'choices' => new \ArrayObject(),
76 ));
77 }
78
79 /**
80 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
81 */
82 public function testChoiceListOptionExpectsChoiceListInterface()
83 {
84 $this->factory->create('choice', null, array(
85 'choice_list' => array('foo' => 'foo'),
86 ));
87 }
88
89 public function testChoiceListAndChoicesCanBeEmpty()
90 {
91 $this->factory->create('choice');
92 }
93
94 public function testExpandedChoicesOptionsTurnIntoChildren()
95 {
96 $form = $this->factory->create('choice', null, array(
97 'expanded' => true,
98 'choices' => $this->choices,
99 ));
100
101 $this->assertCount(count($this->choices), $form, 'Each choice should become a new field');
102 }
103
104 public function testPlaceholderPresentOnNonRequiredExpandedSingleChoice()
105 {
106 $form = $this->factory->create('choice', null, array(
107 'multiple' => false,
108 'expanded' => true,
109 'required' => false,
110 'choices' => $this->choices,
111 ));
112
113 $this->assertTrue(isset($form['placeholder']));
114 $this->assertCount(count($this->choices) + 1, $form, 'Each choice should become a new field');
115 }
116
117 public function testPlaceholderNotPresentIfRequired()
118 {
119 $form = $this->factory->create('choice', null, array(
120 'multiple' => false,
121 'expanded' => true,
122 'required' => true,
123 'choices' => $this->choices,
124 ));
125
126 $this->assertFalse(isset($form['placeholder']));
127 $this->assertCount(count($this->choices), $form, 'Each choice should become a new field');
128 }
129
130 public function testPlaceholderNotPresentIfMultiple()
131 {
132 $form = $this->factory->create('choice', null, array(
133 'multiple' => true,
134 'expanded' => true,
135 'required' => false,
136 'choices' => $this->choices,
137 ));
138
139 $this->assertFalse(isset($form['placeholder']));
140 $this->assertCount(count($this->choices), $form, 'Each choice should become a new field');
141 }
142
143 public function testPlaceholderNotPresentIfEmptyChoice()
144 {
145 $form = $this->factory->create('choice', null, array(
146 'multiple' => false,
147 'expanded' => true,
148 'required' => false,
149 'choices' => array(
150 '' => 'Empty',
151 1 => 'Not empty',
152 ),
153 ));
154
155 $this->assertFalse(isset($form['placeholder']));
156 $this->assertCount(2, $form, 'Each choice should become a new field');
157 }
158
159 public function testExpandedChoicesOptionsAreFlattened()
160 {
161 $form = $this->factory->create('choice', null, array(
162 'expanded' => true,
163 'choices' => $this->groupedChoices,
164 ));
165
166 $flattened = array();
167 foreach ($this->groupedChoices as $choices) {
168 $flattened = array_merge($flattened, array_keys($choices));
169 }
170
171 $this->assertCount($form->count(), $flattened, 'Each nested choice should become a new field, not the groups');
172
173 foreach ($flattened as $value => $choice) {
174 $this->assertTrue($form->has($value), 'Flattened choice is named after it\'s value');
175 }
176 }
177
178 public function testExpandedCheckboxesAreNeverRequired()
179 {
180 $form = $this->factory->create('choice', null, array(
181 'multiple' => true,
182 'expanded' => true,
183 'required' => true,
184 'choices' => $this->choices,
185 ));
186
187 foreach ($form as $child) {
188 $this->assertFalse($child->isRequired());
189 }
190 }
191
192 public function testExpandedRadiosAreRequiredIfChoiceChildIsRequired()
193 {
194 $form = $this->factory->create('choice', null, array(
195 'multiple' => false,
196 'expanded' => true,
197 'required' => true,
198 'choices' => $this->choices,
199 ));
200
201 foreach ($form as $child) {
202 $this->assertTrue($child->isRequired());
203 }
204 }
205
206 public function testExpandedRadiosAreNotRequiredIfChoiceChildIsNotRequired()
207 {
208 $form = $this->factory->create('choice', null, array(
209 'multiple' => false,
210 'expanded' => true,
211 'required' => false,
212 'choices' => $this->choices,
213 ));
214
215 foreach ($form as $child) {
216 $this->assertFalse($child->isRequired());
217 }
218 }
219
220 public function testSubmitSingleNonExpanded()
221 {
222 $form = $this->factory->create('choice', null, array(
223 'multiple' => false,
224 'expanded' => false,
225 'choices' => $this->choices,
226 ));
227
228 $form->submit('b');
229
230 $this->assertEquals('b', $form->getData());
231 $this->assertEquals('b', $form->getViewData());
232 }
233
234 public function testSubmitSingleNonExpandedObjectChoices()
235 {
236 $form = $this->factory->create('choice', null, array(
237 'multiple' => false,
238 'expanded' => false,
239 'choice_list' => new ObjectChoiceList(
240 $this->objectChoices,
241 // label path
242 'name',
243 array(),
244 null,
245 // value path
246 'id'
247 ),
248 ));
249
250 // "id" value of the second entry
251 $form->submit('2');
252
253 $this->assertEquals($this->objectChoices[1], $form->getData());
254 $this->assertEquals('2', $form->getViewData());
255 }
256
257 public function testSubmitMultipleNonExpanded()
258 {
259 $form = $this->factory->create('choice', null, array(
260 'multiple' => true,
261 'expanded' => false,
262 'choices' => $this->choices,
263 ));
264
265 $form->submit(array('a', 'b'));
266
267 $this->assertEquals(array('a', 'b'), $form->getData());
268 $this->assertEquals(array('a', 'b'), $form->getViewData());
269 }
270
271 public function testSubmitMultipleNonExpandedObjectChoices()
272 {
273 $form = $this->factory->create('choice', null, array(
274 'multiple' => true,
275 'expanded' => false,
276 'choice_list' => new ObjectChoiceList(
277 $this->objectChoices,
278 // label path
279 'name',
280 array(),
281 null,
282 // value path
283 'id'
284 ),
285 ));
286
287 $form->submit(array('2', '3'));
288
289 $this->assertEquals(array($this->objectChoices[1], $this->objectChoices[2]), $form->getData());
290 $this->assertEquals(array('2', '3'), $form->getViewData());
291 }
292
293 public function testSubmitSingleExpandedRequired()
294 {
295 $form = $this->factory->create('choice', null, array(
296 'multiple' => false,
297 'expanded' => true,
298 'required' => true,
299 'choices' => $this->choices,
300 ));
301
302 $form->submit('b');
303
304 $this->assertSame('b', $form->getData());
305 $this->assertSame(array(
306 0 => false,
307 1 => true,
308 2 => false,
309 3 => false,
310 4 => false,
311 ), $form->getViewData());
312
313 $this->assertFalse($form[0]->getData());
314 $this->assertTrue($form[1]->getData());
315 $this->assertFalse($form[2]->getData());
316 $this->assertFalse($form[3]->getData());
317 $this->assertFalse($form[4]->getData());
318 $this->assertNull($form[0]->getViewData());
319 $this->assertSame('b', $form[1]->getViewData());
320 $this->assertNull($form[2]->getViewData());
321 $this->assertNull($form[3]->getViewData());
322 $this->assertNull($form[4]->getViewData());
323 }
324
325 public function testSubmitSingleExpandedNonRequired()
326 {
327 $form = $this->factory->create('choice', null, array(
328 'multiple' => false,
329 'expanded' => true,
330 'required' => false,
331 'choices' => $this->choices,
332 ));
333
334 $form->submit('b');
335
336 $this->assertSame('b', $form->getData());
337 $this->assertSame(array(
338 0 => false,
339 1 => true,
340 2 => false,
341 3 => false,
342 4 => false,
343 'placeholder' => false,
344 ), $form->getViewData());
345
346 $this->assertFalse($form['placeholder']->getData());
347 $this->assertFalse($form[0]->getData());
348 $this->assertTrue($form[1]->getData());
349 $this->assertFalse($form[2]->getData());
350 $this->assertFalse($form[3]->getData());
351 $this->assertFalse($form[4]->getData());
352 $this->assertNull($form['placeholder']->getViewData());
353 $this->assertNull($form[0]->getViewData());
354 $this->assertSame('b', $form[1]->getViewData());
355 $this->assertNull($form[2]->getViewData());
356 $this->assertNull($form[3]->getViewData());
357 $this->assertNull($form[4]->getViewData());
358 }
359
360 public function testSubmitSingleExpandedRequiredNothingChecked()
361 {
362 $form = $this->factory->create('choice', null, array(
363 'multiple' => false,
364 'expanded' => true,
365 'required' => true,
366 'choices' => $this->choices,
367 ));
368
369 $form->submit(null);
370
371 $this->assertNull($form->getData());
372 $this->assertSame(array(
373 0 => false,
374 1 => false,
375 2 => false,
376 3 => false,
377 4 => false,
378 ), $form->getViewData());
379
380 $this->assertFalse($form[0]->getData());
381 $this->assertFalse($form[1]->getData());
382 $this->assertFalse($form[2]->getData());
383 $this->assertFalse($form[3]->getData());
384 $this->assertFalse($form[4]->getData());
385 $this->assertNull($form[0]->getViewData());
386 $this->assertNull($form[1]->getViewData());
387 $this->assertNull($form[2]->getViewData());
388 $this->assertNull($form[3]->getViewData());
389 $this->assertNull($form[4]->getViewData());
390 }
391
392 public function testSubmitSingleExpandedNonRequiredNothingChecked()
393 {
394 $form = $this->factory->create('choice', null, array(
395 'multiple' => false,
396 'expanded' => true,
397 'required' => false,
398 'choices' => $this->choices,
399 ));
400
401 $form->submit(null);
402
403 $this->assertNull($form->getData());
404 $this->assertSame(array(
405 0 => false,
406 1 => false,
407 2 => false,
408 3 => false,
409 4 => false,
410 'placeholder' => true,
411 ), $form->getViewData());
412
413 $this->assertTrue($form['placeholder']->getData());
414 $this->assertFalse($form[0]->getData());
415 $this->assertFalse($form[1]->getData());
416 $this->assertFalse($form[2]->getData());
417 $this->assertFalse($form[3]->getData());
418 $this->assertFalse($form[4]->getData());
419 $this->assertSame('', $form['placeholder']->getViewData());
420 $this->assertNull($form[0]->getViewData());
421 $this->assertNull($form[1]->getViewData());
422 $this->assertNull($form[2]->getViewData());
423 $this->assertNull($form[3]->getViewData());
424 $this->assertNull($form[4]->getViewData());
425 }
426
427 public function testSubmitFalseToSingleExpandedRequiredDoesNotProduceExtraChildrenError()
428 {
429 $form = $this->factory->create('choice', null, array(
430 'multiple' => false,
431 'expanded' => true,
432 'required' => true,
433 'choices' => $this->choices,
434 ));
435
436 $form->submit(false);
437
438 $this->assertEmpty($form->getExtraData());
439 $this->assertNull($form->getData());
440 }
441
442 public function testSubmitFalseToSingleExpandedNonRequiredDoesNotProduceExtraChildrenError()
443 {
444 $form = $this->factory->create('choice', null, array(
445 'multiple' => false,
446 'expanded' => true,
447 'required' => false,
448 'choices' => $this->choices,
449 ));
450
451 $form->submit(false);
452
453 $this->assertEmpty($form->getExtraData());
454 $this->assertNull($form->getData());
455 }
456
457 public function testSubmitSingleExpandedWithEmptyChild()
458 {
459 $form = $this->factory->create('choice', null, array(
460 'multiple' => false,
461 'expanded' => true,
462 'choices' => array(
463 '' => 'Empty',
464 1 => 'Not empty',
465 ),
466 ));
467
468 $form->submit('');
469
470 $this->assertNull($form->getData());
471 $this->assertTrue($form[0]->getData());
472 $this->assertFalse($form[1]->getData());
473 $this->assertSame('', $form[0]->getViewData());
474 $this->assertNull($form[1]->getViewData());
475 }
476
477 public function testSubmitSingleExpandedObjectChoices()
478 {
479 $form = $this->factory->create('choice', null, array(
480 'multiple' => false,
481 'expanded' => true,
482 'choice_list' => new ObjectChoiceList(
483 $this->objectChoices,
484 // label path
485 'name',
486 array(),
487 null,
488 // value path
489 'id'
490 ),
491 ));
492
493 $form->submit('2');
494
495 $this->assertSame($this->objectChoices[1], $form->getData());
496 $this->assertFalse($form[0]->getData());
497 $this->assertTrue($form[1]->getData());
498 $this->assertFalse($form[2]->getData());
499 $this->assertFalse($form[3]->getData());
500 $this->assertFalse($form[4]->getData());
501 $this->assertNull($form[0]->getViewData());
502 $this->assertSame('2', $form[1]->getViewData());
503 $this->assertNull($form[2]->getViewData());
504 $this->assertNull($form[3]->getViewData());
505 $this->assertNull($form[4]->getViewData());
506 }
507
508 public function testSubmitSingleExpandedNumericChoices()
509 {
510 $form = $this->factory->create('choice', null, array(
511 'multiple' => false,
512 'expanded' => true,
513 'choices' => $this->numericChoices,
514 ));
515
516 $form->submit('1');
517
518 $this->assertSame(1, $form->getData());
519 $this->assertFalse($form[0]->getData());
520 $this->assertTrue($form[1]->getData());
521 $this->assertFalse($form[2]->getData());
522 $this->assertFalse($form[3]->getData());
523 $this->assertFalse($form[4]->getData());
524 $this->assertNull($form[0]->getViewData());
525 $this->assertSame('1', $form[1]->getViewData());
526 $this->assertNull($form[2]->getViewData());
527 $this->assertNull($form[3]->getViewData());
528 $this->assertNull($form[4]->getViewData());
529 }
530
531 public function testSubmitMultipleExpanded()
532 {
533 $form = $this->factory->create('choice', null, array(
534 'multiple' => true,
535 'expanded' => true,
536 'choices' => $this->choices,
537 ));
538
539 $form->submit(array('a', 'c'));
540
541 $this->assertSame(array('a', 'c'), $form->getData());
542 $this->assertTrue($form[0]->getData());
543 $this->assertFalse($form[1]->getData());
544 $this->assertTrue($form[2]->getData());
545 $this->assertFalse($form[3]->getData());
546 $this->assertFalse($form[4]->getData());
547 $this->assertSame('a', $form[0]->getViewData());
548 $this->assertNull($form[1]->getViewData());
549 $this->assertSame('c', $form[2]->getViewData());
550 $this->assertNull($form[3]->getViewData());
551 $this->assertNull($form[4]->getViewData());
552 }
553
554 public function testSubmitMultipleExpandedEmpty()
555 {
556 $form = $this->factory->create('choice', null, array(
557 'multiple' => true,
558 'expanded' => true,
559 'choices' => $this->choices,
560 ));
561
562 $form->submit(array());
563
564 $this->assertSame(array(), $form->getData());
565 $this->assertFalse($form[0]->getData());
566 $this->assertFalse($form[1]->getData());
567 $this->assertFalse($form[2]->getData());
568 $this->assertFalse($form[3]->getData());
569 $this->assertFalse($form[4]->getData());
570 $this->assertNull($form[0]->getViewData());
571 $this->assertNull($form[1]->getViewData());
572 $this->assertNull($form[2]->getViewData());
573 $this->assertNull($form[3]->getViewData());
574 $this->assertNull($form[4]->getViewData());
575 }
576
577 public function testSubmitMultipleExpandedWithEmptyChild()
578 {
579 $form = $this->factory->create('choice', null, array(
580 'multiple' => true,
581 'expanded' => true,
582 'choices' => array(
583 '' => 'Empty',
584 1 => 'Not Empty',
585 2 => 'Not Empty 2',
586 )
587 ));
588
589 $form->submit(array('', '2'));
590
591 $this->assertSame(array('', 2), $form->getData());
592 $this->assertTrue($form[0]->getData());
593 $this->assertFalse($form[1]->getData());
594 $this->assertTrue($form[2]->getData());
595 $this->assertSame('', $form[0]->getViewData());
596 $this->assertNull($form[1]->getViewData());
597 $this->assertSame('2', $form[2]->getViewData());
598 }
599
600 public function testSubmitMultipleExpandedObjectChoices()
601 {
602 $form = $this->factory->create('choice', null, array(
603 'multiple' => true,
604 'expanded' => true,
605 'choice_list' => new ObjectChoiceList(
606 $this->objectChoices,
607 // label path
608 'name',
609 array(),
610 null,
611 // value path
612 'id'
613 ),
614 ));
615
616 $form->submit(array('1', '2'));
617
618 $this->assertSame(array($this->objectChoices[0], $this->objectChoices[1]), $form->getData());
619 $this->assertTrue($form[0]->getData());
620 $this->assertTrue($form[1]->getData());
621 $this->assertFalse($form[2]->getData());
622 $this->assertFalse($form[3]->getData());
623 $this->assertFalse($form[4]->getData());
624 $this->assertSame('1', $form[0]->getViewData());
625 $this->assertSame('2', $form[1]->getViewData());
626 $this->assertNull($form[2]->getViewData());
627 $this->assertNull($form[3]->getViewData());
628 $this->assertNull($form[4]->getViewData());
629 }
630
631 public function testSubmitMultipleExpandedNumericChoices()
632 {
633 $form = $this->factory->create('choice', null, array(
634 'multiple' => true,
635 'expanded' => true,
636 'choices' => $this->numericChoices,
637 ));
638
639 $form->submit(array('1', '2'));
640
641 $this->assertSame(array(1, 2), $form->getData());
642 $this->assertFalse($form[0]->getData());
643 $this->assertTrue($form[1]->getData());
644 $this->assertTrue($form[2]->getData());
645 $this->assertFalse($form[3]->getData());
646 $this->assertFalse($form[4]->getData());
647 $this->assertNull($form[0]->getViewData());
648 $this->assertSame('1', $form[1]->getViewData());
649 $this->assertSame('2', $form[2]->getViewData());
650 $this->assertNull($form[3]->getViewData());
651 $this->assertNull($form[4]->getViewData());
652 }
653
654 /*
655 * We need this functionality to create choice fields for Boolean types,
656 * e.g. false => 'No', true => 'Yes'
657 */
658 public function testSetDataSingleNonExpandedAcceptsBoolean()
659 {
660 $form = $this->factory->create('choice', null, array(
661 'multiple' => false,
662 'expanded' => false,
663 'choices' => $this->numericChoices,
664 ));
665
666 $form->setData(false);
667
668 $this->assertFalse($form->getData());
669 $this->assertEquals('0', $form->getViewData());
670 }
671
672 public function testSetDataMultipleNonExpandedAcceptsBoolean()
673 {
674 $form = $this->factory->create('choice', null, array(
675 'multiple' => true,
676 'expanded' => false,
677 'choices' => $this->numericChoices,
678 ));
679
680 $form->setData(array(false, true));
681
682 $this->assertEquals(array(false, true), $form->getData());
683 $this->assertEquals(array('0', '1'), $form->getViewData());
684 }
685
686 public function testPassRequiredToView()
687 {
688 $form = $this->factory->create('choice', null, array(
689 'choices' => $this->choices,
690 ));
691 $view = $form->createView();
692
693 $this->assertTrue($view->vars['required']);
694 }
695
696 public function testPassNonRequiredToView()
697 {
698 $form = $this->factory->create('choice', null, array(
699 'required' => false,
700 'choices' => $this->choices,
701 ));
702 $view = $form->createView();
703
704 $this->assertFalse($view->vars['required']);
705 }
706
707 public function testPassMultipleToView()
708 {
709 $form = $this->factory->create('choice', null, array(
710 'multiple' => true,
711 'choices' => $this->choices,
712 ));
713 $view = $form->createView();
714
715 $this->assertTrue($view->vars['multiple']);
716 }
717
718 public function testPassExpandedToView()
719 {
720 $form = $this->factory->create('choice', null, array(
721 'expanded' => true,
722 'choices' => $this->choices,
723 ));
724 $view = $form->createView();
725
726 $this->assertTrue($view->vars['expanded']);
727 }
728
729 public function testEmptyValueIsNullByDefaultIfRequired()
730 {
731 $form = $this->factory->create('choice', null, array(
732 'multiple' => false,
733 'required' => true,
734 'choices' => $this->choices,
735 ));
736 $view = $form->createView();
737
738 $this->assertNull($view->vars['empty_value']);
739 }
740
741 public function testEmptyValueIsEmptyStringByDefaultIfNotRequired()
742 {
743 $form = $this->factory->create('choice', null, array(
744 'multiple' => false,
745 'required' => false,
746 'choices' => $this->choices,
747 ));
748 $view = $form->createView();
749
750 $this->assertSame('', $view->vars['empty_value']);
751 }
752
753 /**
754 * @dataProvider getOptionsWithEmptyValue
755 */
756 public function testPassEmptyValueToView($multiple, $expanded, $required, $emptyValue, $viewValue)
757 {
758 $form = $this->factory->create('choice', null, array(
759 'multiple' => $multiple,
760 'expanded' => $expanded,
761 'required' => $required,
762 'empty_value' => $emptyValue,
763 'choices' => $this->choices,
764 ));
765 $view = $form->createView();
766
767 $this->assertEquals($viewValue, $view->vars['empty_value']);
768 }
769
770 /**
771 * @dataProvider getOptionsWithEmptyValue
772 */
773 public function testDontPassEmptyValueIfContainedInChoices($multiple, $expanded, $required, $emptyValue, $viewValue)
774 {
775 $form = $this->factory->create('choice', null, array(
776 'multiple' => $multiple,
777 'expanded' => $expanded,
778 'required' => $required,
779 'empty_value' => $emptyValue,
780 'choices' => array('a' => 'A', '' => 'Empty'),
781 ));
782 $view = $form->createView();
783
784 $this->assertNull($view->vars['empty_value']);
785 }
786
787 public function getOptionsWithEmptyValue()
788 {
789 return array(
790 // single non-expanded
791 array(false, false, false, 'foobar', 'foobar'),
792 array(false, false, false, '', ''),
793 array(false, false, false, null, null),
794 array(false, false, false, false, null),
795 array(false, false, true, 'foobar', 'foobar'),
796 array(false, false, true, '', ''),
797 array(false, false, true, null, null),
798 array(false, false, true, false, null),
799 // single expanded
800 array(false, true, false, 'foobar', 'foobar'),
801 // radios should never have an empty label
802 array(false, true, false, '', 'None'),
803 array(false, true, false, null, null),
804 array(false, true, false, false, null),
805 array(false, true, true, 'foobar', 'foobar'),
806 // radios should never have an empty label
807 array(false, true, true, '', 'None'),
808 array(false, true, true, null, null),
809 array(false, true, true, false, null),
810 // multiple non-expanded
811 array(true, false, false, 'foobar', null),
812 array(true, false, false, '', null),
813 array(true, false, false, null, null),
814 array(true, false, false, false, null),
815 array(true, false, true, 'foobar', null),
816 array(true, false, true, '', null),
817 array(true, false, true, null, null),
818 array(true, false, true, false, null),
819 // multiple expanded
820 array(true, true, false, 'foobar', null),
821 array(true, true, false, '', null),
822 array(true, true, false, null, null),
823 array(true, true, false, false, null),
824 array(true, true, true, 'foobar', null),
825 array(true, true, true, '', null),
826 array(true, true, true, null, null),
827 array(true, true, true, false, null),
828 );
829 }
830
831 public function testPassChoicesToView()
832 {
833 $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D');
834 $form = $this->factory->create('choice', null, array(
835 'choices' => $choices,
836 ));
837 $view = $form->createView();
838
839 $this->assertEquals(array(
840 new ChoiceView('a', 'a', 'A'),
841 new ChoiceView('b', 'b', 'B'),
842 new ChoiceView('c', 'c', 'C'),
843 new ChoiceView('d', 'd', 'D'),
844 ), $view->vars['choices']);
845 }
846
847 public function testPassPreferredChoicesToView()
848 {
849 $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D');
850 $form = $this->factory->create('choice', null, array(
851 'choices' => $choices,
852 'preferred_choices' => array('b', 'd'),
853 ));
854 $view = $form->createView();
855
856 $this->assertEquals(array(
857 0 => new ChoiceView('a', 'a', 'A'),
858 2 => new ChoiceView('c', 'c', 'C'),
859 ), $view->vars['choices']);
860 $this->assertEquals(array(
861 1 => new ChoiceView('b', 'b', 'B'),
862 3 => new ChoiceView('d', 'd', 'D'),
863 ), $view->vars['preferred_choices']);
864 }
865
866 public function testPassHierarchicalChoicesToView()
867 {
868 $form = $this->factory->create('choice', null, array(
869 'choices' => $this->groupedChoices,
870 'preferred_choices' => array('b', 'd'),
871 ));
872 $view = $form->createView();
873
874 $this->assertEquals(array(
875 'Symfony' => array(
876 0 => new ChoiceView('a', 'a', 'Bernhard'),
877 2 => new ChoiceView('c', 'c', 'Kris'),
878 ),
879 'Doctrine' => array(
880 4 => new ChoiceView('e', 'e', 'Roman'),
881 ),
882 ), $view->vars['choices']);
883 $this->assertEquals(array(
884 'Symfony' => array(
885 1 => new ChoiceView('b', 'b', 'Fabien'),
886 ),
887 'Doctrine' => array(
888 3 => new ChoiceView('d', 'd', 'Jon'),
889 ),
890 ), $view->vars['preferred_choices']);
891 }
892
893 public function testPassChoiceDataToView()
894 {
895 $obj1 = (object) array('value' => 'a', 'label' => 'A');
896 $obj2 = (object) array('value' => 'b', 'label' => 'B');
897 $obj3 = (object) array('value' => 'c', 'label' => 'C');
898 $obj4 = (object) array('value' => 'd', 'label' => 'D');
899 $form = $this->factory->create('choice', null, array(
900 'choice_list' => new ObjectChoiceList(array($obj1, $obj2, $obj3, $obj4), 'label', array(), null, 'value'),
901 ));
902 $view = $form->createView();
903
904 $this->assertEquals(array(
905 new ChoiceView($obj1, 'a', 'A'),
906 new ChoiceView($obj2, 'b', 'B'),
907 new ChoiceView($obj3, 'c', 'C'),
908 new ChoiceView($obj4, 'd', 'D'),
909 ), $view->vars['choices']);
910 }
911
912 public function testAdjustFullNameForMultipleNonExpanded()
913 {
914 $form = $this->factory->createNamed('name', 'choice', null, array(
915 'multiple' => true,
916 'expanded' => false,
917 'choices' => $this->choices,
918 ));
919 $view = $form->createView();
920
921 $this->assertSame('name[]', $view->vars['full_name']);
922 }
923
924 // https://github.com/symfony/symfony/issues/3298
925 public function testInitializeWithEmptyChoices()
926 {
927 $this->factory->createNamed('name', 'choice', null, array(
928 'choices' => array(),
929 ));
930 }
931
932 public function testInitializeWithDefaultObjectChoice()
933 {
934 $obj1 = (object) array('value' => 'a', 'label' => 'A');
935 $obj2 = (object) array('value' => 'b', 'label' => 'B');
936 $obj3 = (object) array('value' => 'c', 'label' => 'C');
937 $obj4 = (object) array('value' => 'd', 'label' => 'D');
938
939 $form = $this->factory->create('choice', null, array(
940 'choice_list' => new ObjectChoiceList(array($obj1, $obj2, $obj3, $obj4), 'label', array(), null, 'value'),
941 // Used to break because "data_class" was inferred, which needs to
942 // remain null in every case (because it refers to the view format)
943 'data' => $obj3,
944 ));
945
946 // Trigger data initialization
947 $form->getViewData();
948 }
949}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php
new file mode 100644
index 00000000..be3ad9db
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php
@@ -0,0 +1,200 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Form;
15
16class CollectionTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
17{
18 public function testContainsNoChildByDefault()
19 {
20 $form = $this->factory->create('collection', null, array(
21 'type' => 'text',
22 ));
23
24 $this->assertCount(0, $form);
25 }
26
27 public function testSetDataAdjustsSize()
28 {
29 $form = $this->factory->create('collection', null, array(
30 'type' => 'text',
31 'options' => array(
32 'max_length' => 20,
33 ),
34 ));
35 $form->setData(array('foo@foo.com', 'foo@bar.com'));
36
37 $this->assertInstanceOf('Symfony\Component\Form\Form', $form[0]);
38 $this->assertInstanceOf('Symfony\Component\Form\Form', $form[1]);
39 $this->assertCount(2, $form);
40 $this->assertEquals('foo@foo.com', $form[0]->getData());
41 $this->assertEquals('foo@bar.com', $form[1]->getData());
42 $this->assertEquals(20, $form[0]->getConfig()->getOption('max_length'));
43 $this->assertEquals(20, $form[1]->getConfig()->getOption('max_length'));
44
45 $form->setData(array('foo@baz.com'));
46 $this->assertInstanceOf('Symfony\Component\Form\Form', $form[0]);
47 $this->assertFalse(isset($form[1]));
48 $this->assertCount(1, $form);
49 $this->assertEquals('foo@baz.com', $form[0]->getData());
50 $this->assertEquals(20, $form[0]->getConfig()->getOption('max_length'));
51 }
52
53 public function testThrowsExceptionIfObjectIsNotTraversable()
54 {
55 $form = $this->factory->create('collection', null, array(
56 'type' => 'text',
57 ));
58 $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
59 $form->setData(new \stdClass());
60 }
61
62 public function testNotResizedIfSubmittedWithMissingData()
63 {
64 $form = $this->factory->create('collection', null, array(
65 'type' => 'text',
66 ));
67 $form->setData(array('foo@foo.com', 'bar@bar.com'));
68 $form->submit(array('foo@bar.com'));
69
70 $this->assertTrue($form->has('0'));
71 $this->assertTrue($form->has('1'));
72 $this->assertEquals('foo@bar.com', $form[0]->getData());
73 $this->assertEquals('', $form[1]->getData());
74 }
75
76 public function testResizedDownIfSubmittedWithMissingDataAndAllowDelete()
77 {
78 $form = $this->factory->create('collection', null, array(
79 'type' => 'text',
80 'allow_delete' => true,
81 ));
82 $form->setData(array('foo@foo.com', 'bar@bar.com'));
83 $form->submit(array('foo@foo.com'));
84
85 $this->assertTrue($form->has('0'));
86 $this->assertFalse($form->has('1'));
87 $this->assertEquals('foo@foo.com', $form[0]->getData());
88 $this->assertEquals(array('foo@foo.com'), $form->getData());
89 }
90
91 public function testNotResizedIfSubmittedWithExtraData()
92 {
93 $form = $this->factory->create('collection', null, array(
94 'type' => 'text',
95 ));
96 $form->setData(array('foo@bar.com'));
97 $form->submit(array('foo@foo.com', 'bar@bar.com'));
98
99 $this->assertTrue($form->has('0'));
100 $this->assertFalse($form->has('1'));
101 $this->assertEquals('foo@foo.com', $form[0]->getData());
102 }
103
104 public function testResizedUpIfSubmittedWithExtraDataAndAllowAdd()
105 {
106 $form = $this->factory->create('collection', null, array(
107 'type' => 'text',
108 'allow_add' => true,
109 ));
110 $form->setData(array('foo@bar.com'));
111 $form->submit(array('foo@bar.com', 'bar@bar.com'));
112
113 $this->assertTrue($form->has('0'));
114 $this->assertTrue($form->has('1'));
115 $this->assertEquals('foo@bar.com', $form[0]->getData());
116 $this->assertEquals('bar@bar.com', $form[1]->getData());
117 $this->assertEquals(array('foo@bar.com', 'bar@bar.com'), $form->getData());
118 }
119
120 public function testAllowAddButNoPrototype()
121 {
122 $form = $this->factory->create('collection', null, array(
123 'type' => 'form',
124 'allow_add' => true,
125 'prototype' => false,
126 ));
127
128 $this->assertFalse($form->has('__name__'));
129 }
130
131 public function testPrototypeMultipartPropagation()
132 {
133 $form = $this->factory
134 ->create('collection', null, array(
135 'type' => 'file',
136 'allow_add' => true,
137 'prototype' => true,
138 ))
139 ;
140
141 $this->assertTrue($form->createView()->vars['multipart']);
142 }
143
144 public function testGetDataDoesNotContainsPrototypeNameBeforeDataAreSet()
145 {
146 $form = $this->factory->create('collection', array(), array(
147 'type' => 'file',
148 'prototype' => true,
149 'allow_add' => true,
150 ));
151
152 $data = $form->getData();
153 $this->assertFalse(isset($data['__name__']));
154 }
155
156 public function testGetDataDoesNotContainsPrototypeNameAfterDataAreSet()
157 {
158 $form = $this->factory->create('collection', array(), array(
159 'type' => 'file',
160 'allow_add' => true,
161 'prototype' => true,
162 ));
163
164 $form->setData(array('foobar.png'));
165 $data = $form->getData();
166 $this->assertFalse(isset($data['__name__']));
167 }
168
169 public function testPrototypeNameOption()
170 {
171 $form = $this->factory->create('collection', null, array(
172 'type' => 'form',
173 'prototype' => true,
174 'allow_add' => true,
175 ));
176
177 $this->assertSame('__name__', $form->getConfig()->getAttribute('prototype')->getName(), '__name__ is the default');
178
179 $form = $this->factory->create('collection', null, array(
180 'type' => 'form',
181 'prototype' => true,
182 'allow_add' => true,
183 'prototype_name' => '__test__',
184 ));
185
186 $this->assertSame('__test__', $form->getConfig()->getAttribute('prototype')->getName());
187 }
188
189 public function testPrototypeDefaultLabel()
190 {
191 $form = $this->factory->create('collection', array(), array(
192 'type' => 'file',
193 'allow_add' => true,
194 'prototype' => true,
195 'prototype_name' => '__test__',
196 ));
197
198 $this->assertSame('__test__label__', $form->createView()->vars['prototype']->vars['label']);
199 }
200}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php
new file mode 100644
index 00000000..1d56e2a0
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php
@@ -0,0 +1,52 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Extension\Core\View\ChoiceView;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class CountryTypeTest extends TypeTestCase
18{
19 protected function setUp()
20 {
21 IntlTestHelper::requireIntl($this);
22
23 parent::setUp();
24 }
25
26 public function testCountriesAreSelectable()
27 {
28 $form = $this->factory->create('country');
29 $view = $form->createView();
30 $choices = $view->vars['choices'];
31
32 // Don't check objects for identity
33 $this->assertContains(new ChoiceView('DE', 'DE', 'Germany'), $choices, '', false, false);
34 $this->assertContains(new ChoiceView('GB', 'GB', 'United Kingdom'), $choices, '', false, false);
35 $this->assertContains(new ChoiceView('US', 'US', 'United States'), $choices, '', false, false);
36 $this->assertContains(new ChoiceView('FR', 'FR', 'France'), $choices, '', false, false);
37 $this->assertContains(new ChoiceView('MY', 'MY', 'Malaysia'), $choices, '', false, false);
38 }
39
40 public function testUnknownCountryIsNotIncluded()
41 {
42 $form = $this->factory->create('country', 'country');
43 $view = $form->createView();
44 $choices = $view->vars['choices'];
45
46 foreach ($choices as $choice) {
47 if ('ZZ' === $choice->value) {
48 $this->fail('Should not contain choice "ZZ"');
49 }
50 }
51 }
52}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php
new file mode 100644
index 00000000..b0eb6dc0
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php
@@ -0,0 +1,37 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Extension\Core\View\ChoiceView;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class CurrencyTypeTest extends TypeTestCase
18{
19 protected function setUp()
20 {
21 IntlTestHelper::requireIntl($this);
22
23 parent::setUp();
24 }
25
26 public function testCurrenciesAreSelectable()
27 {
28 $form = $this->factory->create('currency');
29 $view = $form->createView();
30 $choices = $view->vars['choices'];
31
32 $this->assertContains(new ChoiceView('EUR', 'EUR', 'Euro'), $choices, '', false, false);
33 $this->assertContains(new ChoiceView('USD', 'USD', 'US Dollar'), $choices, '', false, false);
34 $this->assertContains(new ChoiceView('SIT', 'SIT', 'Slovenian Tolar'), $choices, '', false, false);
35 }
36
37}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php
new file mode 100644
index 00000000..b9c1ebad
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php
@@ -0,0 +1,477 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\FormError;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class DateTimeTypeTest extends TypeTestCase
18{
19 protected function setUp()
20 {
21 IntlTestHelper::requireIntl($this);
22
23 parent::setUp();
24 }
25
26 public function testSubmitDateTime()
27 {
28 $form = $this->factory->create('datetime', null, array(
29 'model_timezone' => 'UTC',
30 'view_timezone' => 'UTC',
31 'date_widget' => 'choice',
32 'time_widget' => 'choice',
33 'input' => 'datetime',
34 ));
35
36 $form->submit(array(
37 'date' => array(
38 'day' => '2',
39 'month' => '6',
40 'year' => '2010',
41 ),
42 'time' => array(
43 'hour' => '3',
44 'minute' => '4',
45 ),
46 ));
47
48 $dateTime = new \DateTime('2010-06-02 03:04:00 UTC');
49
50 $this->assertDateTimeEquals($dateTime, $form->getData());
51 }
52
53 public function testSubmitString()
54 {
55 $form = $this->factory->create('datetime', null, array(
56 'model_timezone' => 'UTC',
57 'view_timezone' => 'UTC',
58 'input' => 'string',
59 'date_widget' => 'choice',
60 'time_widget' => 'choice',
61 ));
62
63 $form->submit(array(
64 'date' => array(
65 'day' => '2',
66 'month' => '6',
67 'year' => '2010',
68 ),
69 'time' => array(
70 'hour' => '3',
71 'minute' => '4',
72 ),
73 ));
74
75 $this->assertEquals('2010-06-02 03:04:00', $form->getData());
76 }
77
78 public function testSubmitTimestamp()
79 {
80 $form = $this->factory->create('datetime', null, array(
81 'model_timezone' => 'UTC',
82 'view_timezone' => 'UTC',
83 'input' => 'timestamp',
84 'date_widget' => 'choice',
85 'time_widget' => 'choice',
86 ));
87
88 $form->submit(array(
89 'date' => array(
90 'day' => '2',
91 'month' => '6',
92 'year' => '2010',
93 ),
94 'time' => array(
95 'hour' => '3',
96 'minute' => '4',
97 ),
98 ));
99
100 $dateTime = new \DateTime('2010-06-02 03:04:00 UTC');
101
102 $this->assertEquals($dateTime->format('U'), $form->getData());
103 }
104
105 public function testSubmitWithoutMinutes()
106 {
107 $form = $this->factory->create('datetime', null, array(
108 'model_timezone' => 'UTC',
109 'view_timezone' => 'UTC',
110 'date_widget' => 'choice',
111 'time_widget' => 'choice',
112 'input' => 'datetime',
113 'with_minutes' => false,
114 ));
115
116 $form->setData(new \DateTime('2010-06-02 03:04:05 UTC'));
117
118 $input = array(
119 'date' => array(
120 'day' => '2',
121 'month' => '6',
122 'year' => '2010',
123 ),
124 'time' => array(
125 'hour' => '3',
126 ),
127 );
128
129 $form->submit($input);
130
131 $this->assertDateTimeEquals(new \DateTime('2010-06-02 03:00:00 UTC'), $form->getData());
132 }
133
134 public function testSubmitWithSeconds()
135 {
136 $form = $this->factory->create('datetime', null, array(
137 'model_timezone' => 'UTC',
138 'view_timezone' => 'UTC',
139 'date_widget' => 'choice',
140 'time_widget' => 'choice',
141 'input' => 'datetime',
142 'with_seconds' => true,
143 ));
144
145 $form->setData(new \DateTime('2010-06-02 03:04:05 UTC'));
146
147 $input = array(
148 'date' => array(
149 'day' => '2',
150 'month' => '6',
151 'year' => '2010',
152 ),
153 'time' => array(
154 'hour' => '3',
155 'minute' => '4',
156 'second' => '5',
157 ),
158 );
159
160 $form->submit($input);
161
162 $this->assertDateTimeEquals(new \DateTime('2010-06-02 03:04:05 UTC'), $form->getData());
163 }
164
165 public function testSubmitDifferentTimezones()
166 {
167 $form = $this->factory->create('datetime', null, array(
168 'model_timezone' => 'America/New_York',
169 'view_timezone' => 'Pacific/Tahiti',
170 'date_widget' => 'choice',
171 'time_widget' => 'choice',
172 'input' => 'string',
173 'with_seconds' => true,
174 ));
175
176 $dateTime = new \DateTime('2010-06-02 03:04:05 Pacific/Tahiti');
177
178 $form->submit(array(
179 'date' => array(
180 'day' => (int) $dateTime->format('d'),
181 'month' => (int) $dateTime->format('m'),
182 'year' => (int) $dateTime->format('Y'),
183 ),
184 'time' => array(
185 'hour' => (int) $dateTime->format('H'),
186 'minute' => (int) $dateTime->format('i'),
187 'second' => (int) $dateTime->format('s'),
188 ),
189 ));
190
191 $dateTime->setTimezone(new \DateTimeZone('America/New_York'));
192
193 $this->assertEquals($dateTime->format('Y-m-d H:i:s'), $form->getData());
194 }
195
196 public function testSubmitDifferentTimezonesDateTime()
197 {
198 $form = $this->factory->create('datetime', null, array(
199 'model_timezone' => 'America/New_York',
200 'view_timezone' => 'Pacific/Tahiti',
201 'widget' => 'single_text',
202 'input' => 'datetime',
203 ));
204
205 $outputTime = new \DateTime('2010-06-02 03:04:00 Pacific/Tahiti');
206
207 $form->submit('2010-06-02T03:04:00-10:00');
208
209 $outputTime->setTimezone(new \DateTimeZone('America/New_York'));
210
211 $this->assertDateTimeEquals($outputTime, $form->getData());
212 $this->assertEquals('2010-06-02T03:04:00-10:00', $form->getViewData());
213 }
214
215 public function testSubmitStringSingleText()
216 {
217 $form = $this->factory->create('datetime', null, array(
218 'model_timezone' => 'UTC',
219 'view_timezone' => 'UTC',
220 'input' => 'string',
221 'widget' => 'single_text',
222 ));
223
224 $form->submit('2010-06-02T03:04:00Z');
225
226 $this->assertEquals('2010-06-02 03:04:00', $form->getData());
227 $this->assertEquals('2010-06-02T03:04:00Z', $form->getViewData());
228 }
229
230 public function testSubmitStringSingleTextWithSeconds()
231 {
232 $form = $this->factory->create('datetime', null, array(
233 'model_timezone' => 'UTC',
234 'view_timezone' => 'UTC',
235 'input' => 'string',
236 'widget' => 'single_text',
237 'with_seconds' => true,
238 ));
239
240 $form->submit('2010-06-02T03:04:05Z');
241
242 $this->assertEquals('2010-06-02 03:04:05', $form->getData());
243 $this->assertEquals('2010-06-02T03:04:05Z', $form->getViewData());
244 }
245
246 public function testSubmitDifferentPattern()
247 {
248 $form = $this->factory->create('datetime', null, array(
249 'date_format' => 'MM*yyyy*dd',
250 'date_widget' => 'single_text',
251 'time_widget' => 'single_text',
252 'input' => 'datetime',
253 ));
254
255 $dateTime = new \DateTime('2010-06-02 03:04');
256
257 $form->submit(array(
258 'date' => '06*2010*02',
259 'time' => '03:04',
260 ));
261
262 $this->assertDateTimeEquals($dateTime, $form->getData());
263 }
264
265 // Bug fix
266 public function testInitializeWithDateTime()
267 {
268 // Throws an exception if "data_class" option is not explicitly set
269 // to null in the type
270 $this->factory->create('datetime', new \DateTime());
271 }
272
273 public function testSingleTextWidgetShouldUseTheRightInputType()
274 {
275 $form = $this->factory->create('datetime', null, array(
276 'widget' => 'single_text',
277 ));
278
279 $view = $form->createView();
280 $this->assertEquals('datetime', $view->vars['type']);
281 }
282
283 public function testPassDefaultEmptyValueToViewIfNotRequired()
284 {
285 $form = $this->factory->create('datetime', null, array(
286 'required' => false,
287 'with_seconds' => true,
288 ));
289
290 $view = $form->createView();
291 $this->assertSame('', $view['date']['year']->vars['empty_value']);
292 $this->assertSame('', $view['date']['month']->vars['empty_value']);
293 $this->assertSame('', $view['date']['day']->vars['empty_value']);
294 $this->assertSame('', $view['time']['hour']->vars['empty_value']);
295 $this->assertSame('', $view['time']['minute']->vars['empty_value']);
296 $this->assertSame('', $view['time']['second']->vars['empty_value']);
297 }
298
299 public function testPassNoEmptyValueToViewIfRequired()
300 {
301 $form = $this->factory->create('datetime', null, array(
302 'required' => true,
303 'with_seconds' => true,
304 ));
305
306 $view = $form->createView();
307 $this->assertNull($view['date']['year']->vars['empty_value']);
308 $this->assertNull($view['date']['month']->vars['empty_value']);
309 $this->assertNull($view['date']['day']->vars['empty_value']);
310 $this->assertNull($view['time']['hour']->vars['empty_value']);
311 $this->assertNull($view['time']['minute']->vars['empty_value']);
312 $this->assertNull($view['time']['second']->vars['empty_value']);
313 }
314
315 public function testPassEmptyValueAsString()
316 {
317 $form = $this->factory->create('datetime', null, array(
318 'empty_value' => 'Empty',
319 'with_seconds' => true,
320 ));
321
322 $view = $form->createView();
323 $this->assertSame('Empty', $view['date']['year']->vars['empty_value']);
324 $this->assertSame('Empty', $view['date']['month']->vars['empty_value']);
325 $this->assertSame('Empty', $view['date']['day']->vars['empty_value']);
326 $this->assertSame('Empty', $view['time']['hour']->vars['empty_value']);
327 $this->assertSame('Empty', $view['time']['minute']->vars['empty_value']);
328 $this->assertSame('Empty', $view['time']['second']->vars['empty_value']);
329 }
330
331 public function testPassEmptyValueAsArray()
332 {
333 $form = $this->factory->create('datetime', null, array(
334 'empty_value' => array(
335 'year' => 'Empty year',
336 'month' => 'Empty month',
337 'day' => 'Empty day',
338 'hour' => 'Empty hour',
339 'minute' => 'Empty minute',
340 'second' => 'Empty second',
341 ),
342 'with_seconds' => true,
343 ));
344
345 $view = $form->createView();
346 $this->assertSame('Empty year', $view['date']['year']->vars['empty_value']);
347 $this->assertSame('Empty month', $view['date']['month']->vars['empty_value']);
348 $this->assertSame('Empty day', $view['date']['day']->vars['empty_value']);
349 $this->assertSame('Empty hour', $view['time']['hour']->vars['empty_value']);
350 $this->assertSame('Empty minute', $view['time']['minute']->vars['empty_value']);
351 $this->assertSame('Empty second', $view['time']['second']->vars['empty_value']);
352 }
353
354 public function testPassEmptyValueAsPartialArrayAddEmptyIfNotRequired()
355 {
356 $form = $this->factory->create('datetime', null, array(
357 'required' => false,
358 'empty_value' => array(
359 'year' => 'Empty year',
360 'day' => 'Empty day',
361 'hour' => 'Empty hour',
362 'second' => 'Empty second',
363 ),
364 'with_seconds' => true,
365 ));
366
367 $view = $form->createView();
368 $this->assertSame('Empty year', $view['date']['year']->vars['empty_value']);
369 $this->assertSame('', $view['date']['month']->vars['empty_value']);
370 $this->assertSame('Empty day', $view['date']['day']->vars['empty_value']);
371 $this->assertSame('Empty hour', $view['time']['hour']->vars['empty_value']);
372 $this->assertSame('', $view['time']['minute']->vars['empty_value']);
373 $this->assertSame('Empty second', $view['time']['second']->vars['empty_value']);
374 }
375
376 public function testPassEmptyValueAsPartialArrayAddNullIfRequired()
377 {
378 $form = $this->factory->create('datetime', null, array(
379 'required' => true,
380 'empty_value' => array(
381 'year' => 'Empty year',
382 'day' => 'Empty day',
383 'hour' => 'Empty hour',
384 'second' => 'Empty second',
385 ),
386 'with_seconds' => true,
387 ));
388
389 $view = $form->createView();
390 $this->assertSame('Empty year', $view['date']['year']->vars['empty_value']);
391 $this->assertNull($view['date']['month']->vars['empty_value']);
392 $this->assertSame('Empty day', $view['date']['day']->vars['empty_value']);
393 $this->assertSame('Empty hour', $view['time']['hour']->vars['empty_value']);
394 $this->assertNull($view['time']['minute']->vars['empty_value']);
395 $this->assertSame('Empty second', $view['time']['second']->vars['empty_value']);
396 }
397
398 public function testPassHtml5TypeIfSingleTextAndHtml5Format()
399 {
400 $form = $this->factory->create('datetime', null, array(
401 'widget' => 'single_text',
402 ));
403
404 $view = $form->createView();
405 $this->assertSame('datetime', $view->vars['type']);
406 }
407
408 public function testDontPassHtml5TypeIfNotHtml5Format()
409 {
410 $form = $this->factory->create('datetime', null, array(
411 'widget' => 'single_text',
412 'format' => 'yyyy-MM-dd HH:mm',
413 ));
414
415 $view = $form->createView();
416 $this->assertFalse(isset($view->vars['type']));
417 }
418
419 public function testDontPassHtml5TypeIfNotSingleText()
420 {
421 $form = $this->factory->create('datetime', null, array(
422 'widget' => 'text',
423 ));
424
425 $view = $form->createView();
426 $this->assertFalse(isset($view->vars['type']));
427 }
428
429 public function testDateTypeChoiceErrorsBubbleUp()
430 {
431 $error = new FormError('Invalid!');
432 $form = $this->factory->create('datetime', null);
433
434 $form['date']->addError($error);
435
436 $this->assertSame(array(), $form['date']->getErrors());
437 $this->assertSame(array($error), $form->getErrors());
438 }
439
440 public function testDateTypeSingleTextErrorsBubbleUp()
441 {
442 $error = new FormError('Invalid!');
443 $form = $this->factory->create('datetime', null, array(
444 'date_widget' => 'single_text'
445 ));
446
447 $form['date']->addError($error);
448
449 $this->assertSame(array(), $form['date']->getErrors());
450 $this->assertSame(array($error), $form->getErrors());
451 }
452
453 public function testTimeTypeChoiceErrorsBubbleUp()
454 {
455 $error = new FormError('Invalid!');
456 $form = $this->factory->create('datetime', null);
457
458 $form['time']->addError($error);
459
460 $this->assertSame(array(), $form['time']->getErrors());
461 $this->assertSame(array($error), $form->getErrors());
462 }
463
464 public function testTimeTypeSingleTextErrorsBubbleUp()
465 {
466 $error = new FormError('Invalid!');
467 $form = $this->factory->create('datetime', null, array(
468 'time_widget' => 'single_text'
469 ));
470
471 $form['time']->addError($error);
472
473 $this->assertSame(array(), $form['time']->getErrors());
474 $this->assertSame(array($error), $form->getErrors());
475 }
476
477}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
new file mode 100644
index 00000000..2aa155e7
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
@@ -0,0 +1,781 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Extension\Core\View\ChoiceView;
15use Symfony\Component\Form\FormError;
16use Symfony\Component\Intl\Util\IntlTestHelper;
17
18class DateTypeTest extends TypeTestCase
19{
20 protected function setUp()
21 {
22 parent::setUp();
23
24 // we test against "de_AT", so we need the full implementation
25 IntlTestHelper::requireFullIntl($this);
26
27 \Locale::setDefault('de_AT');
28 }
29
30 /**
31 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
32 */
33 public function testInvalidWidgetOption()
34 {
35 $this->factory->create('date', null, array(
36 'widget' => 'fake_widget',
37 ));
38 }
39
40 /**
41 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
42 */
43 public function testInvalidInputOption()
44 {
45 $this->factory->create('date', null, array(
46 'input' => 'fake_input',
47 ));
48 }
49
50 public function testSubmitFromSingleTextDateTimeWithDefaultFormat()
51 {
52 $form = $this->factory->create('date', null, array(
53 'model_timezone' => 'UTC',
54 'view_timezone' => 'UTC',
55 'widget' => 'single_text',
56 'input' => 'datetime',
57 ));
58
59 $form->submit('2010-06-02');
60
61 $this->assertDateTimeEquals(new \DateTime('2010-06-02 UTC'), $form->getData());
62 $this->assertEquals('2010-06-02', $form->getViewData());
63 }
64
65 public function testSubmitFromSingleTextDateTime()
66 {
67 $form = $this->factory->create('date', null, array(
68 'format' => \IntlDateFormatter::MEDIUM,
69 'model_timezone' => 'UTC',
70 'view_timezone' => 'UTC',
71 'widget' => 'single_text',
72 'input' => 'datetime',
73 ));
74
75 $form->submit('2.6.2010');
76
77 $this->assertDateTimeEquals(new \DateTime('2010-06-02 UTC'), $form->getData());
78 $this->assertEquals('02.06.2010', $form->getViewData());
79 }
80
81 public function testSubmitFromSingleTextString()
82 {
83 $form = $this->factory->create('date', null, array(
84 'format' => \IntlDateFormatter::MEDIUM,
85 'model_timezone' => 'UTC',
86 'view_timezone' => 'UTC',
87 'widget' => 'single_text',
88 'input' => 'string',
89 ));
90
91 $form->submit('2.6.2010');
92
93 $this->assertEquals('2010-06-02', $form->getData());
94 $this->assertEquals('02.06.2010', $form->getViewData());
95 }
96
97 public function testSubmitFromSingleTextTimestamp()
98 {
99 $form = $this->factory->create('date', null, array(
100 'format' => \IntlDateFormatter::MEDIUM,
101 'model_timezone' => 'UTC',
102 'view_timezone' => 'UTC',
103 'widget' => 'single_text',
104 'input' => 'timestamp',
105 ));
106
107 $form->submit('2.6.2010');
108
109 $dateTime = new \DateTime('2010-06-02 UTC');
110
111 $this->assertEquals($dateTime->format('U'), $form->getData());
112 $this->assertEquals('02.06.2010', $form->getViewData());
113 }
114
115 public function testSubmitFromSingleTextRaw()
116 {
117 $form = $this->factory->create('date', null, array(
118 'format' => \IntlDateFormatter::MEDIUM,
119 'model_timezone' => 'UTC',
120 'view_timezone' => 'UTC',
121 'widget' => 'single_text',
122 'input' => 'array',
123 ));
124
125 $form->submit('2.6.2010');
126
127 $output = array(
128 'day' => '2',
129 'month' => '6',
130 'year' => '2010',
131 );
132
133 $this->assertEquals($output, $form->getData());
134 $this->assertEquals('02.06.2010', $form->getViewData());
135 }
136
137 public function testSubmitFromText()
138 {
139 $form = $this->factory->create('date', null, array(
140 'model_timezone' => 'UTC',
141 'view_timezone' => 'UTC',
142 'widget' => 'text',
143 ));
144
145 $text = array(
146 'day' => '2',
147 'month' => '6',
148 'year' => '2010',
149 );
150
151 $form->submit($text);
152
153 $dateTime = new \DateTime('2010-06-02 UTC');
154
155 $this->assertDateTimeEquals($dateTime, $form->getData());
156 $this->assertEquals($text, $form->getViewData());
157 }
158
159 public function testSubmitFromChoice()
160 {
161 $form = $this->factory->create('date', null, array(
162 'model_timezone' => 'UTC',
163 'view_timezone' => 'UTC',
164 'widget' => 'choice',
165 ));
166
167 $text = array(
168 'day' => '2',
169 'month' => '6',
170 'year' => '2010',
171 );
172
173 $form->submit($text);
174
175 $dateTime = new \DateTime('2010-06-02 UTC');
176
177 $this->assertDateTimeEquals($dateTime, $form->getData());
178 $this->assertEquals($text, $form->getViewData());
179 }
180
181 public function testSubmitFromChoiceEmpty()
182 {
183 $form = $this->factory->create('date', null, array(
184 'model_timezone' => 'UTC',
185 'view_timezone' => 'UTC',
186 'widget' => 'choice',
187 'required' => false,
188 ));
189
190 $text = array(
191 'day' => '',
192 'month' => '',
193 'year' => '',
194 );
195
196 $form->submit($text);
197
198 $this->assertNull($form->getData());
199 $this->assertEquals($text, $form->getViewData());
200 }
201
202 public function testSubmitFromInputDateTimeDifferentPattern()
203 {
204 $form = $this->factory->create('date', null, array(
205 'model_timezone' => 'UTC',
206 'view_timezone' => 'UTC',
207 'format' => 'MM*yyyy*dd',
208 'widget' => 'single_text',
209 'input' => 'datetime',
210 ));
211
212 $form->submit('06*2010*02');
213
214 $this->assertDateTimeEquals(new \DateTime('2010-06-02 UTC'), $form->getData());
215 $this->assertEquals('06*2010*02', $form->getViewData());
216 }
217
218 public function testSubmitFromInputStringDifferentPattern()
219 {
220 $form = $this->factory->create('date', null, array(
221 'model_timezone' => 'UTC',
222 'view_timezone' => 'UTC',
223 'format' => 'MM*yyyy*dd',
224 'widget' => 'single_text',
225 'input' => 'string',
226 ));
227
228 $form->submit('06*2010*02');
229
230 $this->assertEquals('2010-06-02', $form->getData());
231 $this->assertEquals('06*2010*02', $form->getViewData());
232 }
233
234 public function testSubmitFromInputTimestampDifferentPattern()
235 {
236 $form = $this->factory->create('date', null, array(
237 'model_timezone' => 'UTC',
238 'view_timezone' => 'UTC',
239 'format' => 'MM*yyyy*dd',
240 'widget' => 'single_text',
241 'input' => 'timestamp',
242 ));
243
244 $form->submit('06*2010*02');
245
246 $dateTime = new \DateTime('2010-06-02 UTC');
247
248 $this->assertEquals($dateTime->format('U'), $form->getData());
249 $this->assertEquals('06*2010*02', $form->getViewData());
250 }
251
252 public function testSubmitFromInputRawDifferentPattern()
253 {
254 $form = $this->factory->create('date', null, array(
255 'model_timezone' => 'UTC',
256 'view_timezone' => 'UTC',
257 'format' => 'MM*yyyy*dd',
258 'widget' => 'single_text',
259 'input' => 'array',
260 ));
261
262 $form->submit('06*2010*02');
263
264 $output = array(
265 'day' => '2',
266 'month' => '6',
267 'year' => '2010',
268 );
269
270 $this->assertEquals($output, $form->getData());
271 $this->assertEquals('06*2010*02', $form->getViewData());
272 }
273
274 /**
275 * @dataProvider provideDateFormats
276 */
277 public function testDatePatternWithFormatOption($format, $pattern)
278 {
279 $form = $this->factory->create('date', null, array(
280 'format' => $format,
281 ));
282
283 $view = $form->createView();
284
285 $this->assertEquals($pattern, $view->vars['date_pattern']);
286 }
287
288 public function provideDateFormats()
289 {
290 return array(
291 array('dMy', '{{ day }}{{ month }}{{ year }}'),
292 array('d-M-yyyy', '{{ day }}-{{ month }}-{{ year }}'),
293 array('M d y', '{{ month }} {{ day }} {{ year }}'),
294 );
295 }
296
297 /**
298 * This test is to check that the strings '0', '1', '2', '3' are no accepted
299 * as valid IntlDateFormatter constants for FULL, LONG, MEDIUM or SHORT respectively.
300 *
301 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
302 */
303 public function testThrowExceptionIfFormatIsNoPattern()
304 {
305 $this->factory->create('date', null, array(
306 'format' => '0',
307 'widget' => 'single_text',
308 'input' => 'string',
309 ));
310 }
311
312 /**
313 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
314 */
315 public function testThrowExceptionIfFormatDoesNotContainYearMonthAndDay()
316 {
317 $this->factory->create('date', null, array(
318 'months' => array(6, 7),
319 'format' => 'yy',
320 ));
321 }
322
323 /**
324 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
325 */
326 public function testThrowExceptionIfFormatIsNoConstant()
327 {
328 $this->factory->create('date', null, array(
329 'format' => 105,
330 ));
331 }
332
333 /**
334 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
335 */
336 public function testThrowExceptionIfFormatIsInvalid()
337 {
338 $this->factory->create('date', null, array(
339 'format' => array(),
340 ));
341 }
342
343 public function testSetDataWithDifferentTimezones()
344 {
345 $form = $this->factory->create('date', null, array(
346 'format' => \IntlDateFormatter::MEDIUM,
347 'model_timezone' => 'America/New_York',
348 'view_timezone' => 'Pacific/Tahiti',
349 'input' => 'string',
350 'widget' => 'single_text',
351 ));
352
353 $form->setData('2010-06-02');
354
355 $this->assertEquals('01.06.2010', $form->getViewData());
356 }
357
358 public function testSetDataWithDifferentTimezonesDateTime()
359 {
360 $form = $this->factory->create('date', null, array(
361 'format' => \IntlDateFormatter::MEDIUM,
362 'model_timezone' => 'America/New_York',
363 'view_timezone' => 'Pacific/Tahiti',
364 'input' => 'datetime',
365 'widget' => 'single_text',
366 ));
367
368 $dateTime = new \DateTime('2010-06-02 America/New_York');
369
370 $form->setData($dateTime);
371
372 $this->assertDateTimeEquals($dateTime, $form->getData());
373 $this->assertEquals('01.06.2010', $form->getViewData());
374 }
375
376 public function testYearsOption()
377 {
378 $form = $this->factory->create('date', null, array(
379 'years' => array(2010, 2011),
380 ));
381
382 $view = $form->createView();
383
384 $this->assertEquals(array(
385 new ChoiceView('2010', '2010', '2010'),
386 new ChoiceView('2011', '2011', '2011'),
387 ), $view['year']->vars['choices']);
388 }
389
390 public function testMonthsOption()
391 {
392 $form = $this->factory->create('date', null, array(
393 'months' => array(6, 7),
394 ));
395
396 $view = $form->createView();
397
398 $this->assertEquals(array(
399 new ChoiceView('6', '6', '06'),
400 new ChoiceView('7', '7', '07'),
401 ), $view['month']->vars['choices']);
402 }
403
404 public function testMonthsOptionShortFormat()
405 {
406 $form = $this->factory->create('date', null, array(
407 'months' => array(1, 4),
408 'format' => 'dd.MMM.yy',
409 ));
410
411 $view = $form->createView();
412
413 $this->assertEquals(array(
414 new ChoiceView('1', '1', 'Jän'),
415 new ChoiceView('4', '4', 'Apr.')
416 ), $view['month']->vars['choices']);
417 }
418
419 public function testMonthsOptionLongFormat()
420 {
421 $form = $this->factory->create('date', null, array(
422 'months' => array(1, 4),
423 'format' => 'dd.MMMM.yy',
424 ));
425
426 $view = $form->createView();
427
428 $this->assertEquals(array(
429 new ChoiceView('1', '1', 'Jänner'),
430 new ChoiceView('4', '4', 'April'),
431 ), $view['month']->vars['choices']);
432 }
433
434 public function testMonthsOptionLongFormatWithDifferentTimezone()
435 {
436 $form = $this->factory->create('date', null, array(
437 'months' => array(1, 4),
438 'format' => 'dd.MMMM.yy',
439 ));
440
441 $view = $form->createView();
442
443 $this->assertEquals(array(
444 new ChoiceView('1', '1', 'Jänner'),
445 new ChoiceView('4', '4', 'April'),
446 ), $view['month']->vars['choices']);
447 }
448
449 public function testIsDayWithinRangeReturnsTrueIfWithin()
450 {
451 $form = $this->factory->create('date', null, array(
452 'days' => array(6, 7),
453 ));
454
455 $view = $form->createView();
456
457 $this->assertEquals(array(
458 new ChoiceView('6', '6', '06'),
459 new ChoiceView('7', '7', '07'),
460 ), $view['day']->vars['choices']);
461 }
462
463 public function testIsPartiallyFilledReturnsFalseIfSingleText()
464 {
465 $this->markTestIncomplete('Needs to be reimplemented using validators');
466
467 $form = $this->factory->create('date', null, array(
468 'model_timezone' => 'UTC',
469 'view_timezone' => 'UTC',
470 'widget' => 'single_text',
471 ));
472
473 $form->submit('7.6.2010');
474
475 $this->assertFalse($form->isPartiallyFilled());
476 }
477
478 public function testIsPartiallyFilledReturnsFalseIfChoiceAndCompletelyEmpty()
479 {
480 $this->markTestIncomplete('Needs to be reimplemented using validators');
481
482 $form = $this->factory->create('date', null, array(
483 'model_timezone' => 'UTC',
484 'view_timezone' => 'UTC',
485 'widget' => 'choice',
486 ));
487
488 $form->submit(array(
489 'day' => '',
490 'month' => '',
491 'year' => '',
492 ));
493
494 $this->assertFalse($form->isPartiallyFilled());
495 }
496
497 public function testIsPartiallyFilledReturnsFalseIfChoiceAndCompletelyFilled()
498 {
499 $this->markTestIncomplete('Needs to be reimplemented using validators');
500
501 $form = $this->factory->create('date', null, array(
502 'model_timezone' => 'UTC',
503 'view_timezone' => 'UTC',
504 'widget' => 'choice',
505 ));
506
507 $form->submit(array(
508 'day' => '2',
509 'month' => '6',
510 'year' => '2010',
511 ));
512
513 $this->assertFalse($form->isPartiallyFilled());
514 }
515
516 public function testIsPartiallyFilledReturnsTrueIfChoiceAndDayEmpty()
517 {
518 $this->markTestIncomplete('Needs to be reimplemented using validators');
519
520 $form = $this->factory->create('date', null, array(
521 'model_timezone' => 'UTC',
522 'view_timezone' => 'UTC',
523 'widget' => 'choice',
524 ));
525
526 $form->submit(array(
527 'day' => '',
528 'month' => '6',
529 'year' => '2010',
530 ));
531
532 $this->assertTrue($form->isPartiallyFilled());
533 }
534
535 public function testPassDatePatternToView()
536 {
537 $form = $this->factory->create('date');
538 $view = $form->createView();
539
540 $this->assertSame('{{ day }}{{ month }}{{ year }}', $view->vars['date_pattern']);
541 }
542
543 public function testPassDatePatternToViewDifferentFormat()
544 {
545 $form = $this->factory->create('date', null, array(
546 'format' => \IntlDateFormatter::LONG,
547 ));
548
549 $view = $form->createView();
550
551 $this->assertSame('{{ day }}{{ month }}{{ year }}', $view->vars['date_pattern']);
552 }
553
554 public function testPassDatePatternToViewDifferentPattern()
555 {
556 $form = $this->factory->create('date', null, array(
557 'format' => 'MMyyyydd'
558 ));
559
560 $view = $form->createView();
561
562 $this->assertSame('{{ month }}{{ year }}{{ day }}', $view->vars['date_pattern']);
563 }
564
565 public function testPassDatePatternToViewDifferentPatternWithSeparators()
566 {
567 $form = $this->factory->create('date', null, array(
568 'format' => 'MM*yyyy*dd'
569 ));
570
571 $view = $form->createView();
572
573 $this->assertSame('{{ month }}*{{ year }}*{{ day }}', $view->vars['date_pattern']);
574 }
575
576 public function testDontPassDatePatternIfText()
577 {
578 $form = $this->factory->create('date', null, array(
579 'widget' => 'single_text',
580 ));
581 $view = $form->createView();
582
583 $this->assertFalse(isset($view->vars['date_pattern']));
584 }
585
586 public function testPassWidgetToView()
587 {
588 $form = $this->factory->create('date', null, array(
589 'widget' => 'single_text',
590 ));
591 $view = $form->createView();
592
593 $this->assertSame('single_text', $view->vars['widget']);
594 }
595
596 // Bug fix
597 public function testInitializeWithDateTime()
598 {
599 // Throws an exception if "data_class" option is not explicitly set
600 // to null in the type
601 $this->factory->create('date', new \DateTime());
602 }
603
604 public function testSingleTextWidgetShouldUseTheRightInputType()
605 {
606 $form = $this->factory->create('date', null, array(
607 'widget' => 'single_text',
608 ));
609
610 $view = $form->createView();
611 $this->assertEquals('date', $view->vars['type']);
612 }
613
614 public function testPassDefaultEmptyValueToViewIfNotRequired()
615 {
616 $form = $this->factory->create('date', null, array(
617 'required' => false,
618 ));
619
620 $view = $form->createView();
621 $this->assertSame('', $view['year']->vars['empty_value']);
622 $this->assertSame('', $view['month']->vars['empty_value']);
623 $this->assertSame('', $view['day']->vars['empty_value']);
624 }
625
626 public function testPassNoEmptyValueToViewIfRequired()
627 {
628 $form = $this->factory->create('date', null, array(
629 'required' => true,
630 ));
631
632 $view = $form->createView();
633 $this->assertNull($view['year']->vars['empty_value']);
634 $this->assertNull($view['month']->vars['empty_value']);
635 $this->assertNull($view['day']->vars['empty_value']);
636 }
637
638 public function testPassEmptyValueAsString()
639 {
640 $form = $this->factory->create('date', null, array(
641 'empty_value' => 'Empty',
642 ));
643
644 $view = $form->createView();
645 $this->assertSame('Empty', $view['year']->vars['empty_value']);
646 $this->assertSame('Empty', $view['month']->vars['empty_value']);
647 $this->assertSame('Empty', $view['day']->vars['empty_value']);
648 }
649
650 public function testPassEmptyValueAsArray()
651 {
652 $form = $this->factory->create('date', null, array(
653 'empty_value' => array(
654 'year' => 'Empty year',
655 'month' => 'Empty month',
656 'day' => 'Empty day',
657 ),
658 ));
659
660 $view = $form->createView();
661 $this->assertSame('Empty year', $view['year']->vars['empty_value']);
662 $this->assertSame('Empty month', $view['month']->vars['empty_value']);
663 $this->assertSame('Empty day', $view['day']->vars['empty_value']);
664 }
665
666 public function testPassEmptyValueAsPartialArrayAddEmptyIfNotRequired()
667 {
668 $form = $this->factory->create('date', null, array(
669 'required' => false,
670 'empty_value' => array(
671 'year' => 'Empty year',
672 'day' => 'Empty day',
673 ),
674 ));
675
676 $view = $form->createView();
677 $this->assertSame('Empty year', $view['year']->vars['empty_value']);
678 $this->assertSame('', $view['month']->vars['empty_value']);
679 $this->assertSame('Empty day', $view['day']->vars['empty_value']);
680 }
681
682 public function testPassEmptyValueAsPartialArrayAddNullIfRequired()
683 {
684 $form = $this->factory->create('date', null, array(
685 'required' => true,
686 'empty_value' => array(
687 'year' => 'Empty year',
688 'day' => 'Empty day',
689 ),
690 ));
691
692 $view = $form->createView();
693 $this->assertSame('Empty year', $view['year']->vars['empty_value']);
694 $this->assertNull($view['month']->vars['empty_value']);
695 $this->assertSame('Empty day', $view['day']->vars['empty_value']);
696 }
697
698 public function testPassHtml5TypeIfSingleTextAndHtml5Format()
699 {
700 $form = $this->factory->create('date', null, array(
701 'widget' => 'single_text',
702 ));
703
704 $view = $form->createView();
705 $this->assertSame('date', $view->vars['type']);
706 }
707
708 public function testDontPassHtml5TypeIfNotHtml5Format()
709 {
710 $form = $this->factory->create('date', null, array(
711 'widget' => 'single_text',
712 'format' => \IntlDateFormatter::MEDIUM,
713 ));
714
715 $view = $form->createView();
716 $this->assertFalse(isset($view->vars['type']));
717 }
718
719 public function testDontPassHtml5TypeIfNotSingleText()
720 {
721 $form = $this->factory->create('date', null, array(
722 'widget' => 'text',
723 ));
724
725 $view = $form->createView();
726 $this->assertFalse(isset($view->vars['type']));
727 }
728
729 public function provideCompoundWidgets()
730 {
731 return array(
732 array('text'),
733 array('choice'),
734 );
735 }
736
737 /**
738 * @dataProvider provideCompoundWidgets
739 */
740 public function testYearErrorsBubbleUp($widget)
741 {
742 $error = new FormError('Invalid!');
743 $form = $this->factory->create('date', null, array(
744 'widget' => $widget,
745 ));
746 $form['year']->addError($error);
747
748 $this->assertSame(array(), $form['year']->getErrors());
749 $this->assertSame(array($error), $form->getErrors());
750 }
751
752 /**
753 * @dataProvider provideCompoundWidgets
754 */
755 public function testMonthErrorsBubbleUp($widget)
756 {
757 $error = new FormError('Invalid!');
758 $form = $this->factory->create('date', null, array(
759 'widget' => $widget,
760 ));
761 $form['month']->addError($error);
762
763 $this->assertSame(array(), $form['month']->getErrors());
764 $this->assertSame(array($error), $form->getErrors());
765 }
766
767 /**
768 * @dataProvider provideCompoundWidgets
769 */
770 public function testDayErrorsBubbleUp($widget)
771 {
772 $error = new FormError('Invalid!');
773 $form = $this->factory->create('date', null, array(
774 'widget' => $widget,
775 ));
776 $form['day']->addError($error);
777
778 $this->assertSame(array(), $form['day']->getErrors());
779 $this->assertSame(array($error), $form->getErrors());
780 }
781}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php
new file mode 100644
index 00000000..63556eb5
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php
@@ -0,0 +1,83 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14class FileTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
15{
16 // https://github.com/symfony/symfony/pull/5028
17 public function testSetData()
18 {
19 $form = $this->factory->createBuilder('file')->getForm();
20 $data = $this->createUploadedFileMock('abcdef', 'original.jpg', true);
21
22 $form->setData($data);
23
24 $this->assertSame($data, $form->getData());
25 }
26
27 public function testSubmit()
28 {
29 $form = $this->factory->createBuilder('file')->getForm();
30 $data = $this->createUploadedFileMock('abcdef', 'original.jpg', true);
31
32 $form->submit($data);
33
34 $this->assertSame($data, $form->getData());
35 }
36
37 // https://github.com/symfony/symfony/issues/6134
38 public function testSubmitEmpty()
39 {
40 $form = $this->factory->createBuilder('file')->getForm();
41
42 $form->submit(null);
43
44 $this->assertNull($form->getData());
45 }
46
47 public function testDontPassValueToView()
48 {
49 $form = $this->factory->create('file');
50 $form->submit(array(
51 'file' => $this->createUploadedFileMock('abcdef', 'original.jpg', true),
52 ));
53 $view = $form->createView();
54
55 $this->assertEquals('', $view->vars['value']);
56 }
57
58 private function createUploadedFileMock($name, $originalName, $valid)
59 {
60 $file = $this
61 ->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
62 ->disableOriginalConstructor()
63 ->getMock()
64 ;
65 $file
66 ->expects($this->any())
67 ->method('getBasename')
68 ->will($this->returnValue($name))
69 ;
70 $file
71 ->expects($this->any())
72 ->method('getClientOriginalName')
73 ->will($this->returnValue($originalName))
74 ;
75 $file
76 ->expects($this->any())
77 ->method('isValid')
78 ->will($this->returnValue($valid))
79 ;
80
81 return $file;
82 }
83}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php
new file mode 100644
index 00000000..cced82f4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php
@@ -0,0 +1,578 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\PropertyAccess\PropertyPath;
15use Symfony\Component\Form\Form;
16use Symfony\Component\Form\CallbackTransformer;
17use Symfony\Component\Form\Tests\Fixtures\Author;
18use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
19use Symfony\Component\Form\FormError;
20
21class FormTest_AuthorWithoutRefSetter
22{
23 protected $reference;
24
25 protected $referenceCopy;
26
27 public function __construct($reference)
28 {
29 $this->reference = $reference;
30 $this->referenceCopy = $reference;
31 }
32
33 // The returned object should be modified by reference without having
34 // to provide a setReference() method
35 public function getReference()
36 {
37 return $this->reference;
38 }
39
40 // The returned object is a copy, so setReferenceCopy() must be used
41 // to update it
42 public function getReferenceCopy()
43 {
44 return is_object($this->referenceCopy) ? clone $this->referenceCopy : $this->referenceCopy;
45 }
46
47 public function setReferenceCopy($reference)
48 {
49 $this->referenceCopy = $reference;
50 }
51}
52
53class FormTypeTest extends BaseTypeTest
54{
55 public function testCreateFormInstances()
56 {
57 $this->assertInstanceOf('Symfony\Component\Form\Form', $this->factory->create('form'));
58 }
59
60 public function testPassRequiredAsOption()
61 {
62 $form = $this->factory->create('form', null, array('required' => false));
63
64 $this->assertFalse($form->isRequired());
65
66 $form = $this->factory->create('form', null, array('required' => true));
67
68 $this->assertTrue($form->isRequired());
69 }
70
71 public function testSubmittedDataIsTrimmedBeforeTransforming()
72 {
73 $form = $this->factory->createBuilder('form')
74 ->addViewTransformer(new FixedDataTransformer(array(
75 null => '',
76 'reverse[a]' => 'a',
77 )))
78 ->setCompound(false)
79 ->getForm();
80
81 $form->submit(' a ');
82
83 $this->assertEquals('a', $form->getViewData());
84 $this->assertEquals('reverse[a]', $form->getData());
85 }
86
87 public function testSubmittedDataIsNotTrimmedBeforeTransformingIfNoTrimming()
88 {
89 $form = $this->factory->createBuilder('form', null, array('trim' => false))
90 ->addViewTransformer(new FixedDataTransformer(array(
91 null => '',
92 'reverse[ a ]' => ' a ',
93 )))
94 ->setCompound(false)
95 ->getForm();
96
97 $form->submit(' a ');
98
99 $this->assertEquals(' a ', $form->getViewData());
100 $this->assertEquals('reverse[ a ]', $form->getData());
101 }
102
103 public function testNonReadOnlyFormWithReadOnlyParentIsReadOnly()
104 {
105 $view = $this->factory->createNamedBuilder('parent', 'form', null, array('read_only' => true))
106 ->add('child', 'form')
107 ->getForm()
108 ->createView();
109
110 $this->assertTrue($view['child']->vars['read_only']);
111 }
112
113 public function testReadOnlyFormWithNonReadOnlyParentIsReadOnly()
114 {
115 $view = $this->factory->createNamedBuilder('parent', 'form')
116 ->add('child', 'form', array('read_only' => true))
117 ->getForm()
118 ->createView();
119
120 $this->assertTrue($view['child']->vars['read_only']);
121 }
122
123 public function testNonReadOnlyFormWithNonReadOnlyParentIsNotReadOnly()
124 {
125 $view = $this->factory->createNamedBuilder('parent', 'form')
126 ->add('child', 'form')
127 ->getForm()
128 ->createView();
129
130 $this->assertFalse($view['child']->vars['read_only']);
131 }
132
133 public function testPassMaxLengthToView()
134 {
135 $form = $this->factory->create('form', null, array('max_length' => 10));
136 $view = $form->createView();
137
138 $this->assertSame(10, $view->vars['max_length']);
139 }
140
141 public function testSubmitWithEmptyDataCreatesObjectIfClassAvailable()
142 {
143 $builder = $this->factory->createBuilder('form', null, array(
144 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
145 'required' => false,
146 ));
147 $builder->add('firstName', 'text');
148 $builder->add('lastName', 'text');
149 $form = $builder->getForm();
150
151 $form->setData(null);
152 // partially empty, still an object is created
153 $form->submit(array('firstName' => 'Bernhard', 'lastName' => ''));
154
155 $author = new Author();
156 $author->firstName = 'Bernhard';
157 $author->setLastName('');
158
159 $this->assertEquals($author, $form->getData());
160 }
161
162 public function testSubmitWithEmptyDataCreatesObjectIfInitiallySubmittedWithObject()
163 {
164 $builder = $this->factory->createBuilder('form', null, array(
165 // data class is inferred from the passed object
166 'data' => new Author(),
167 'required' => false,
168 ));
169 $builder->add('firstName', 'text');
170 $builder->add('lastName', 'text');
171 $form = $builder->getForm();
172
173 $form->setData(null);
174 // partially empty, still an object is created
175 $form->submit(array('firstName' => 'Bernhard', 'lastName' => ''));
176
177 $author = new Author();
178 $author->firstName = 'Bernhard';
179 $author->setLastName('');
180
181 $this->assertEquals($author, $form->getData());
182 }
183
184 public function testSubmitWithEmptyDataCreatesArrayIfDataClassIsNull()
185 {
186 $builder = $this->factory->createBuilder('form', null, array(
187 'data_class' => null,
188 'required' => false,
189 ));
190 $builder->add('firstName', 'text');
191 $form = $builder->getForm();
192
193 $form->setData(null);
194 $form->submit(array('firstName' => 'Bernhard'));
195
196 $this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
197 }
198
199 public function testSubmitEmptyWithEmptyDataCreatesNoObjectIfNotRequired()
200 {
201 $builder = $this->factory->createBuilder('form', null, array(
202 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
203 'required' => false,
204 ));
205 $builder->add('firstName', 'text');
206 $builder->add('lastName', 'text');
207 $form = $builder->getForm();
208
209 $form->setData(null);
210 $form->submit(array('firstName' => '', 'lastName' => ''));
211
212 $this->assertNull($form->getData());
213 }
214
215 public function testSubmitEmptyWithEmptyDataCreatesObjectIfRequired()
216 {
217 $builder = $this->factory->createBuilder('form', null, array(
218 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
219 'required' => true,
220 ));
221 $builder->add('firstName', 'text');
222 $builder->add('lastName', 'text');
223 $form = $builder->getForm();
224
225 $form->setData(null);
226 $form->submit(array('firstName' => '', 'lastName' => ''));
227
228 $this->assertEquals(new Author(), $form->getData());
229 }
230
231 /*
232 * We need something to write the field values into
233 */
234 public function testSubmitWithEmptyDataStoresArrayIfNoClassAvailable()
235 {
236 $form = $this->factory->createBuilder('form')
237 ->add('firstName', 'text')
238 ->getForm();
239
240 $form->setData(null);
241 $form->submit(array('firstName' => 'Bernhard'));
242
243 $this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
244 }
245
246 public function testSubmitWithEmptyDataPassesEmptyStringToTransformerIfNotCompound()
247 {
248 $form = $this->factory->createBuilder('form')
249 ->addViewTransformer(new FixedDataTransformer(array(
250 // required for the initial, internal setData(null)
251 null => 'null',
252 // required to test that submit(null) is converted to ''
253 'empty' => '',
254 )))
255 ->setCompound(false)
256 ->getForm();
257
258 $form->submit(null);
259
260 $this->assertSame('empty', $form->getData());
261 }
262
263 public function testSubmitWithEmptyDataUsesEmptyDataOption()
264 {
265 $author = new Author();
266
267 $builder = $this->factory->createBuilder('form', null, array(
268 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
269 'empty_data' => $author,
270 ));
271 $builder->add('firstName', 'text');
272 $form = $builder->getForm();
273
274 $form->submit(array('firstName' => 'Bernhard'));
275
276 $this->assertSame($author, $form->getData());
277 $this->assertEquals('Bernhard', $author->firstName);
278 }
279
280 public function provideZeros()
281 {
282 return array(
283 array(0, '0'),
284 array('0', '0'),
285 array('00000', '00000'),
286 );
287 }
288
289 /**
290 * @dataProvider provideZeros
291 * @see https://github.com/symfony/symfony/issues/1986
292 */
293 public function testSetDataThroughParamsWithZero($data, $dataAsString)
294 {
295 $form = $this->factory->create('form', null, array(
296 'data' => $data,
297 'compound' => false,
298 ));
299 $view = $form->createView();
300
301 $this->assertFalse($form->isEmpty());
302
303 $this->assertSame($dataAsString, $view->vars['value']);
304 $this->assertSame($dataAsString, $form->getData());
305 }
306
307 /**
308 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
309 */
310 public function testAttributesException()
311 {
312 $this->factory->create('form', null, array('attr' => ''));
313 }
314
315 public function testNameCanBeEmptyString()
316 {
317 $form = $this->factory->createNamed('', 'form');
318
319 $this->assertEquals('', $form->getName());
320 }
321
322 public function testSubformDoesntCallSetters()
323 {
324 $author = new FormTest_AuthorWithoutRefSetter(new Author());
325
326 $builder = $this->factory->createBuilder('form', $author);
327 $builder->add('reference', 'form', array(
328 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
329 ));
330 $builder->get('reference')->add('firstName', 'text');
331 $form = $builder->getForm();
332
333 $form->submit(array(
334 // reference has a getter, but not setter
335 'reference' => array(
336 'firstName' => 'Foo',
337 )
338 ));
339
340 $this->assertEquals('Foo', $author->getReference()->firstName);
341 }
342
343 public function testSubformCallsSettersIfTheObjectChanged()
344 {
345 // no reference
346 $author = new FormTest_AuthorWithoutRefSetter(null);
347 $newReference = new Author();
348
349 $builder = $this->factory->createBuilder('form', $author);
350 $builder->add('referenceCopy', 'form', array(
351 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
352 ));
353 $builder->get('referenceCopy')->add('firstName', 'text');
354 $form = $builder->getForm();
355
356 $form['referenceCopy']->setData($newReference); // new author object
357
358 $form->submit(array(
359 // referenceCopy has a getter that returns a copy
360 'referenceCopy' => array(
361 'firstName' => 'Foo',
362 )
363 ));
364
365 $this->assertEquals('Foo', $author->getReferenceCopy()->firstName);
366 }
367
368 public function testSubformCallsSettersIfByReferenceIsFalse()
369 {
370 $author = new FormTest_AuthorWithoutRefSetter(new Author());
371
372 $builder = $this->factory->createBuilder('form', $author);
373 $builder->add('referenceCopy', 'form', array(
374 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
375 'by_reference' => false
376 ));
377 $builder->get('referenceCopy')->add('firstName', 'text');
378 $form = $builder->getForm();
379
380 $form->submit(array(
381 // referenceCopy has a getter that returns a copy
382 'referenceCopy' => array(
383 'firstName' => 'Foo',
384 )
385 ));
386
387 // firstName can only be updated if setReferenceCopy() was called
388 $this->assertEquals('Foo', $author->getReferenceCopy()->firstName);
389 }
390
391 public function testSubformCallsSettersIfReferenceIsScalar()
392 {
393 $author = new FormTest_AuthorWithoutRefSetter('scalar');
394
395 $builder = $this->factory->createBuilder('form', $author);
396 $builder->add('referenceCopy', 'form');
397 $builder->get('referenceCopy')->addViewTransformer(new CallbackTransformer(
398 function () {},
399 function ($value) { // reverseTransform
400
401 return 'foobar';
402 }
403 ));
404 $form = $builder->getForm();
405
406 $form->submit(array(
407 'referenceCopy' => array(), // doesn't matter actually
408 ));
409
410 // firstName can only be updated if setReferenceCopy() was called
411 $this->assertEquals('foobar', $author->getReferenceCopy());
412 }
413
414 public function testSubformAlwaysInsertsIntoArrays()
415 {
416 $ref1 = new Author();
417 $ref2 = new Author();
418 $author = array('referenceCopy' => $ref1);
419
420 $builder = $this->factory->createBuilder('form');
421 $builder->setData($author);
422 $builder->add('referenceCopy', 'form');
423 $builder->get('referenceCopy')->addViewTransformer(new CallbackTransformer(
424 function () {},
425 function ($value) use ($ref2) { // reverseTransform
426
427 return $ref2;
428 }
429 ));
430 $form = $builder->getForm();
431
432 $form->submit(array(
433 'referenceCopy' => array('a' => 'b'), // doesn't matter actually
434 ));
435
436 // the new reference was inserted into the array
437 $author = $form->getData();
438 $this->assertSame($ref2, $author['referenceCopy']);
439 }
440
441 public function testPassMultipartTrueIfAnyChildIsMultipartToView()
442 {
443 $view = $this->factory->createBuilder('form')
444 ->add('foo', 'text')
445 ->add('bar', 'file')
446 ->getForm()
447 ->createView();
448
449 $this->assertTrue($view->vars['multipart']);
450 }
451
452 public function testViewIsNotRenderedByDefault()
453 {
454 $view = $this->factory->createBuilder('form')
455 ->add('foo', 'form')
456 ->getForm()
457 ->createView();
458
459 $this->assertFalse($view->isRendered());
460 }
461
462 public function testErrorBubblingIfCompound()
463 {
464 $form = $this->factory->create('form', null, array(
465 'compound' => true,
466 ));
467
468 $this->assertTrue($form->getConfig()->getErrorBubbling());
469 }
470
471 public function testNoErrorBubblingIfNotCompound()
472 {
473 $form = $this->factory->create('form', null, array(
474 'compound' => false,
475 ));
476
477 $this->assertFalse($form->getConfig()->getErrorBubbling());
478 }
479
480 public function testOverrideErrorBubbling()
481 {
482 $form = $this->factory->create('form', null, array(
483 'compound' => false,
484 'error_bubbling' => true,
485 ));
486
487 $this->assertTrue($form->getConfig()->getErrorBubbling());
488 }
489
490 public function testPropertyPath()
491 {
492 $form = $this->factory->create('form', null, array(
493 'property_path' => 'foo',
494 ));
495
496 $this->assertEquals(new PropertyPath('foo'), $form->getPropertyPath());
497 $this->assertTrue($form->getConfig()->getMapped());
498 }
499
500 public function testPropertyPathNullImpliesDefault()
501 {
502 $form = $this->factory->createNamed('name', 'form', null, array(
503 'property_path' => null,
504 ));
505
506 $this->assertEquals(new PropertyPath('name'), $form->getPropertyPath());
507 $this->assertTrue($form->getConfig()->getMapped());
508 }
509
510 public function testNotMapped()
511 {
512 $form = $this->factory->create('form', null, array(
513 'property_path' => 'foo',
514 'mapped' => false,
515 ));
516
517 $this->assertEquals(new PropertyPath('foo'), $form->getPropertyPath());
518 $this->assertFalse($form->getConfig()->getMapped());
519 }
520
521 public function testViewValidNotSubmitted()
522 {
523 $form = $this->factory->create('form');
524 $view = $form->createView();
525 $this->assertTrue($view->vars['valid']);
526 }
527
528 public function testViewNotValidSubmitted()
529 {
530 $form = $this->factory->create('form');
531 $form->submit(array());
532 $form->addError(new FormError('An error'));
533 $view = $form->createView();
534 $this->assertFalse($view->vars['valid']);
535 }
536
537 public function testDataOptionSupersedesSetDataCalls()
538 {
539 $form = $this->factory->create('form', null, array(
540 'data' => 'default',
541 'compound' => false,
542 ));
543
544 $form->setData('foobar');
545
546 $this->assertSame('default', $form->getData());
547 }
548
549 public function testNormDataIsPassedToView()
550 {
551 $view = $this->factory->createBuilder('form')
552 ->addViewTransformer(new FixedDataTransformer(array(
553 'foo' => 'bar',
554 )))
555 ->setData('foo')
556 ->getForm()
557 ->createView();
558
559 $this->assertSame('foo', $view->vars['data']);
560 $this->assertSame('bar', $view->vars['value']);
561 }
562
563 // https://github.com/symfony/symfony/issues/6862
564 public function testPassZeroLabelToView()
565 {
566 $view = $this->factory->create('form', null, array(
567 'label' => '0'
568 ))
569 ->createView();
570
571 $this->assertSame('0', $view->vars['label']);
572 }
573
574 protected function getTestedType()
575 {
576 return 'form';
577 }
578}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php
new file mode 100644
index 00000000..998bbe01
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php
@@ -0,0 +1,34 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Intl\Util\IntlTestHelper;
15
16class IntegerTypeTest extends TypeTestCase
17{
18 protected function setUp()
19 {
20 IntlTestHelper::requireIntl($this);
21
22 parent::setUp();
23 }
24
25 public function testSubmitCastsToInteger()
26 {
27 $form = $this->factory->create('integer');
28
29 $form->submit('1.678');
30
31 $this->assertSame(1, $form->getData());
32 $this->assertSame('1', $form->getViewData());
33 }
34}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/LanguageTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/LanguageTypeTest.php
new file mode 100644
index 00000000..24434b21
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/LanguageTypeTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Extension\Core\View\ChoiceView;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class LanguageTypeTest extends TypeTestCase
18{
19 protected function setUp()
20 {
21 IntlTestHelper::requireIntl($this);
22
23 parent::setUp();
24 }
25
26 public function testCountriesAreSelectable()
27 {
28 $form = $this->factory->create('language');
29 $view = $form->createView();
30 $choices = $view->vars['choices'];
31
32 $this->assertContains(new ChoiceView('en', 'en', 'English'), $choices, '', false, false);
33 $this->assertContains(new ChoiceView('en_GB', 'en_GB', 'British English'), $choices, '', false, false);
34 $this->assertContains(new ChoiceView('en_US', 'en_US', 'U.S. English'), $choices, '', false, false);
35 $this->assertContains(new ChoiceView('fr', 'fr', 'French'), $choices, '', false, false);
36 $this->assertContains(new ChoiceView('my', 'my', 'Burmese'), $choices, '', false, false);
37 }
38
39 public function testMultipleLanguagesIsNotIncluded()
40 {
41 $form = $this->factory->create('language', 'language');
42 $view = $form->createView();
43 $choices = $view->vars['choices'];
44
45 $this->assertNotContains(new ChoiceView('mul', 'mul', 'Mehrsprachig'), $choices, '', false, false);
46 }
47}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php
new file mode 100644
index 00000000..e402cb4b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/LocaleTypeTest.php
@@ -0,0 +1,36 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Extension\Core\View\ChoiceView;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17class LocaleTypeTest extends TypeTestCase
18{
19 protected function setUp()
20 {
21 IntlTestHelper::requireIntl($this);
22
23 parent::setUp();
24 }
25
26 public function testLocalesAreSelectable()
27 {
28 $form = $this->factory->create('locale');
29 $view = $form->createView();
30 $choices = $view->vars['choices'];
31
32 $this->assertContains(new ChoiceView('en', 'en', 'English'), $choices, '', false, false);
33 $this->assertContains(new ChoiceView('en_GB', 'en_GB', 'English (United Kingdom)'), $choices, '', false, false);
34 $this->assertContains(new ChoiceView('zh_Hant_MO', 'zh_Hant_MO', 'Chinese (Traditional, Macau SAR China)'), $choices, '', false, false);
35 }
36}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/MoneyTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/MoneyTypeTest.php
new file mode 100644
index 00000000..97fc37fa
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/MoneyTypeTest.php
@@ -0,0 +1,59 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Intl\Util\IntlTestHelper;
15
16class MoneyTypeTest extends TypeTestCase
17{
18 protected function setUp()
19 {
20 // we test against different locales, so we need the full
21 // implementation
22 IntlTestHelper::requireFullIntl($this);
23
24 parent::setUp();
25 }
26
27 public function testPassMoneyPatternToView()
28 {
29 \Locale::setDefault('de_DE');
30
31 $form = $this->factory->create('money');
32 $view = $form->createView();
33
34 $this->assertSame('{{ widget }} €', $view->vars['money_pattern']);
35 }
36
37 public function testMoneyPatternWorksForYen()
38 {
39 \Locale::setDefault('en_US');
40
41 $form = $this->factory->create('money', null, array('currency' => 'JPY'));
42 $view = $form->createView();
43 $this->assertTrue((Boolean) strstr($view->vars['money_pattern'], 'Â¥'));
44 }
45
46 // https://github.com/symfony/symfony/issues/5458
47 public function testPassDifferentPatternsForDifferentCurrencies()
48 {
49 \Locale::setDefault('de_DE');
50
51 $form1 = $this->factory->create('money', null, array('currency' => 'GBP'));
52 $form2 = $this->factory->create('money', null, array('currency' => 'EUR'));
53 $view1 = $form1->createView();
54 $view2 = $form2->createView();
55
56 $this->assertSame('{{ widget }} £', $view1->vars['money_pattern']);
57 $this->assertSame('{{ widget }} €', $view2->vars['money_pattern']);
58 }
59}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php
new file mode 100644
index 00000000..e5b3dd74
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php
@@ -0,0 +1,63 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Intl\Util\IntlTestHelper;
15
16class NumberTypeTest extends TypeTestCase
17{
18 protected function setUp()
19 {
20 parent::setUp();
21
22 // we test against "de_DE", so we need the full implementation
23 IntlTestHelper::requireFullIntl($this);
24
25 \Locale::setDefault('de_DE');
26 }
27
28 public function testDefaultFormatting()
29 {
30 $form = $this->factory->create('number');
31 $form->setData('12345.67890');
32 $view = $form->createView();
33
34 $this->assertSame('12345,679', $view->vars['value']);
35 }
36
37 public function testDefaultFormattingWithGrouping()
38 {
39 $form = $this->factory->create('number', null, array('grouping' => true));
40 $form->setData('12345.67890');
41 $view = $form->createView();
42
43 $this->assertSame('12.345,679', $view->vars['value']);
44 }
45
46 public function testDefaultFormattingWithPrecision()
47 {
48 $form = $this->factory->create('number', null, array('precision' => 2));
49 $form->setData('12345.67890');
50 $view = $form->createView();
51
52 $this->assertSame('12345,68', $view->vars['value']);
53 }
54
55 public function testDefaultFormattingWithRounding()
56 {
57 $form = $this->factory->create('number', null, array('precision' => 0, 'rounding_mode' => \NumberFormatter::ROUND_UP));
58 $form->setData('12345.54321');
59 $view = $form->createView();
60
61 $this->assertSame('12346', $view->vars['value']);
62 }
63}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/PasswordTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/PasswordTypeTest.php
new file mode 100644
index 00000000..bccb6f7b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/PasswordTypeTest.php
@@ -0,0 +1,51 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14class PasswordTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
15{
16 public function testEmptyIfNotSubmitted()
17 {
18 $form = $this->factory->create('password');
19 $form->setData('pAs5w0rd');
20 $view = $form->createView();
21
22 $this->assertSame('', $view->vars['value']);
23 }
24
25 public function testEmptyIfSubmitted()
26 {
27 $form = $this->factory->create('password');
28 $form->submit('pAs5w0rd');
29 $view = $form->createView();
30
31 $this->assertSame('', $view->vars['value']);
32 }
33
34 public function testNotEmptyIfSubmittedAndNotAlwaysEmpty()
35 {
36 $form = $this->factory->create('password', null, array('always_empty' => false));
37 $form->submit('pAs5w0rd');
38 $view = $form->createView();
39
40 $this->assertSame('pAs5w0rd', $view->vars['value']);
41 }
42
43 public function testNotTrimmed()
44 {
45 $form = $this->factory->create('password', null);
46 $form->submit(' pAs5w0rd ');
47 $data = $form->getData();
48
49 $this->assertSame(' pAs5w0rd ', $data);
50 }
51}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php
new file mode 100644
index 00000000..9e125d78
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php
@@ -0,0 +1,149 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14class RepeatedTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
15{
16 protected $form;
17
18 protected function setUp()
19 {
20 parent::setUp();
21
22 $this->form = $this->factory->create('repeated', null, array(
23 'type' => 'text',
24 ));
25 $this->form->setData(null);
26 }
27
28 public function testSetData()
29 {
30 $this->form->setData('foobar');
31
32 $this->assertEquals('foobar', $this->form['first']->getData());
33 $this->assertEquals('foobar', $this->form['second']->getData());
34 }
35
36 public function testSetOptions()
37 {
38 $form = $this->factory->create('repeated', null, array(
39 'type' => 'text',
40 'options' => array('label' => 'Global'),
41 ));
42
43 $this->assertEquals('Global', $form['first']->getConfig()->getOption('label'));
44 $this->assertEquals('Global', $form['second']->getConfig()->getOption('label'));
45 $this->assertTrue($form['first']->isRequired());
46 $this->assertTrue($form['second']->isRequired());
47 }
48
49 public function testSetOptionsPerChild()
50 {
51 $form = $this->factory->create('repeated', null, array(
52 // the global required value cannot be overridden
53 'type' => 'text',
54 'first_options' => array('label' => 'Test', 'required' => false),
55 'second_options' => array('label' => 'Test2')
56 ));
57
58 $this->assertEquals('Test', $form['first']->getConfig()->getOption('label'));
59 $this->assertEquals('Test2', $form['second']->getConfig()->getOption('label'));
60 $this->assertTrue($form['first']->isRequired());
61 $this->assertTrue($form['second']->isRequired());
62 }
63
64 public function testSetRequired()
65 {
66 $form = $this->factory->create('repeated', null, array(
67 'required' => false,
68 'type' => 'text',
69 ));
70
71 $this->assertFalse($form['first']->isRequired());
72 $this->assertFalse($form['second']->isRequired());
73 }
74
75 public function testSetErrorBubblingToTrue()
76 {
77 $form = $this->factory->create('repeated', null, array(
78 'error_bubbling' => true,
79 ));
80
81 $this->assertTrue($form->getConfig()->getOption('error_bubbling'));
82 $this->assertTrue($form['first']->getConfig()->getOption('error_bubbling'));
83 $this->assertTrue($form['second']->getConfig()->getOption('error_bubbling'));
84 }
85
86 public function testSetErrorBubblingToFalse()
87 {
88 $form = $this->factory->create('repeated', null, array(
89 'error_bubbling' => false,
90 ));
91
92 $this->assertFalse($form->getConfig()->getOption('error_bubbling'));
93 $this->assertFalse($form['first']->getConfig()->getOption('error_bubbling'));
94 $this->assertFalse($form['second']->getConfig()->getOption('error_bubbling'));
95 }
96
97 public function testSetErrorBubblingIndividually()
98 {
99 $form = $this->factory->create('repeated', null, array(
100 'error_bubbling' => true,
101 'options' => array('error_bubbling' => false),
102 'second_options' => array('error_bubbling' => true),
103 ));
104
105 $this->assertTrue($form->getConfig()->getOption('error_bubbling'));
106 $this->assertFalse($form['first']->getConfig()->getOption('error_bubbling'));
107 $this->assertTrue($form['second']->getConfig()->getOption('error_bubbling'));
108 }
109
110 public function testSetOptionsPerChildAndOverwrite()
111 {
112 $form = $this->factory->create('repeated', null, array(
113 'type' => 'text',
114 'options' => array('label' => 'Label'),
115 'second_options' => array('label' => 'Second label')
116 ));
117
118 $this->assertEquals('Label', $form['first']->getConfig()->getOption('label'));
119 $this->assertEquals('Second label', $form['second']->getConfig()->getOption('label'));
120 $this->assertTrue($form['first']->isRequired());
121 $this->assertTrue($form['second']->isRequired());
122 }
123
124 public function testSubmitUnequal()
125 {
126 $input = array('first' => 'foo', 'second' => 'bar');
127
128 $this->form->submit($input);
129
130 $this->assertEquals('foo', $this->form['first']->getViewData());
131 $this->assertEquals('bar', $this->form['second']->getViewData());
132 $this->assertFalse($this->form->isSynchronized());
133 $this->assertEquals($input, $this->form->getViewData());
134 $this->assertNull($this->form->getData());
135 }
136
137 public function testSubmitEqual()
138 {
139 $input = array('first' => 'foo', 'second' => 'foo');
140
141 $this->form->submit($input);
142
143 $this->assertEquals('foo', $this->form['first']->getViewData());
144 $this->assertEquals('foo', $this->form['second']->getViewData());
145 $this->assertTrue($this->form->isSynchronized());
146 $this->assertEquals($input, $this->form->getViewData());
147 $this->assertEquals('foo', $this->form->getData());
148 }
149}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/SubmitTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/SubmitTypeTest.php
new file mode 100644
index 00000000..8cc72281
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/SubmitTypeTest.php
@@ -0,0 +1,54 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class SubmitTypeTest extends TypeTestCase
18{
19 public function testCreateSubmitButtonInstances()
20 {
21 $this->assertInstanceOf('Symfony\Component\Form\SubmitButton', $this->factory->create('submit'));
22 }
23
24 public function testNotClickedByDefault()
25 {
26 $button = $this->factory->create('submit');
27
28 $this->assertFalse($button->isClicked());
29 }
30
31 public function testNotClickedIfSubmittedWithNull()
32 {
33 $button = $this->factory->create('submit');
34 $button->submit(null);
35
36 $this->assertFalse($button->isClicked());
37 }
38
39 public function testClickedIfSubmittedWithEmptyString()
40 {
41 $button = $this->factory->create('submit');
42 $button->submit('');
43
44 $this->assertTrue($button->isClicked());
45 }
46
47 public function testClickedIfSubmittedWithUnemptyString()
48 {
49 $button = $this->factory->create('submit');
50 $button->submit('foo');
51
52 $this->assertTrue($button->isClicked());
53 }
54}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php
new file mode 100644
index 00000000..9bdfe156
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php
@@ -0,0 +1,649 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Extension\Core\View\ChoiceView;
15use Symfony\Component\Form\FormError;
16use Symfony\Component\Intl\Util\IntlTestHelper;
17
18class TimeTypeTest extends TypeTestCase
19{
20 protected function setUp()
21 {
22 IntlTestHelper::requireIntl($this);
23
24 parent::setUp();
25 }
26
27 public function testSubmitDateTime()
28 {
29 $form = $this->factory->create('time', null, array(
30 'model_timezone' => 'UTC',
31 'view_timezone' => 'UTC',
32 'input' => 'datetime',
33 ));
34
35 $input = array(
36 'hour' => '3',
37 'minute' => '4',
38 );
39
40 $form->submit($input);
41
42 $dateTime = new \DateTime('1970-01-01 03:04:00 UTC');
43
44 $this->assertEquals($dateTime, $form->getData());
45 $this->assertEquals($input, $form->getViewData());
46 }
47
48 public function testSubmitString()
49 {
50 $form = $this->factory->create('time', null, array(
51 'model_timezone' => 'UTC',
52 'view_timezone' => 'UTC',
53 'input' => 'string',
54 ));
55
56 $input = array(
57 'hour' => '3',
58 'minute' => '4',
59 );
60
61 $form->submit($input);
62
63 $this->assertEquals('03:04:00', $form->getData());
64 $this->assertEquals($input, $form->getViewData());
65 }
66
67 public function testSubmitTimestamp()
68 {
69 $form = $this->factory->create('time', null, array(
70 'model_timezone' => 'UTC',
71 'view_timezone' => 'UTC',
72 'input' => 'timestamp',
73 ));
74
75 $input = array(
76 'hour' => '3',
77 'minute' => '4',
78 );
79
80 $form->submit($input);
81
82 $dateTime = new \DateTime('1970-01-01 03:04:00 UTC');
83
84 $this->assertEquals($dateTime->format('U'), $form->getData());
85 $this->assertEquals($input, $form->getViewData());
86 }
87
88 public function testSubmitArray()
89 {
90 $form = $this->factory->create('time', null, array(
91 'model_timezone' => 'UTC',
92 'view_timezone' => 'UTC',
93 'input' => 'array',
94 ));
95
96 $input = array(
97 'hour' => '3',
98 'minute' => '4',
99 );
100
101 $form->submit($input);
102
103 $this->assertEquals($input, $form->getData());
104 $this->assertEquals($input, $form->getViewData());
105 }
106
107 public function testSubmitDatetimeSingleText()
108 {
109 $form = $this->factory->create('time', null, array(
110 'model_timezone' => 'UTC',
111 'view_timezone' => 'UTC',
112 'input' => 'datetime',
113 'widget' => 'single_text',
114 ));
115
116 $form->submit('03:04');
117
118 $this->assertEquals(new \DateTime('1970-01-01 03:04:00 UTC'), $form->getData());
119 $this->assertEquals('03:04', $form->getViewData());
120 }
121
122 public function testSubmitDatetimeSingleTextWithoutMinutes()
123 {
124 $form = $this->factory->create('time', null, array(
125 'model_timezone' => 'UTC',
126 'view_timezone' => 'UTC',
127 'input' => 'datetime',
128 'widget' => 'single_text',
129 'with_minutes' => false,
130 ));
131
132 $form->submit('03');
133
134 $this->assertEquals(new \DateTime('1970-01-01 03:00:00 UTC'), $form->getData());
135 $this->assertEquals('03', $form->getViewData());
136 }
137
138 public function testSubmitArraySingleText()
139 {
140 $form = $this->factory->create('time', null, array(
141 'model_timezone' => 'UTC',
142 'view_timezone' => 'UTC',
143 'input' => 'array',
144 'widget' => 'single_text',
145 ));
146
147 $data = array(
148 'hour' => '3',
149 'minute' => '4',
150 );
151
152 $form->submit('03:04');
153
154 $this->assertEquals($data, $form->getData());
155 $this->assertEquals('03:04', $form->getViewData());
156 }
157
158 public function testSubmitArraySingleTextWithoutMinutes()
159 {
160 $form = $this->factory->create('time', null, array(
161 'model_timezone' => 'UTC',
162 'view_timezone' => 'UTC',
163 'input' => 'array',
164 'widget' => 'single_text',
165 'with_minutes' => false,
166 ));
167
168 $data = array(
169 'hour' => '3',
170 );
171
172 $form->submit('03');
173
174 $this->assertEquals($data, $form->getData());
175 $this->assertEquals('03', $form->getViewData());
176 }
177
178 public function testSubmitArraySingleTextWithSeconds()
179 {
180 $form = $this->factory->create('time', null, array(
181 'model_timezone' => 'UTC',
182 'view_timezone' => 'UTC',
183 'input' => 'array',
184 'widget' => 'single_text',
185 'with_seconds' => true,
186 ));
187
188 $data = array(
189 'hour' => '3',
190 'minute' => '4',
191 'second' => '5',
192 );
193
194 $form->submit('03:04:05');
195
196 $this->assertEquals($data, $form->getData());
197 $this->assertEquals('03:04:05', $form->getViewData());
198 }
199
200 public function testSubmitStringSingleText()
201 {
202 $form = $this->factory->create('time', null, array(
203 'model_timezone' => 'UTC',
204 'view_timezone' => 'UTC',
205 'input' => 'string',
206 'widget' => 'single_text',
207 ));
208
209 $form->submit('03:04');
210
211 $this->assertEquals('03:04:00', $form->getData());
212 $this->assertEquals('03:04', $form->getViewData());
213 }
214
215 public function testSubmitStringSingleTextWithoutMinutes()
216 {
217 $form = $this->factory->create('time', null, array(
218 'model_timezone' => 'UTC',
219 'view_timezone' => 'UTC',
220 'input' => 'string',
221 'widget' => 'single_text',
222 'with_minutes' => false,
223 ));
224
225 $form->submit('03');
226
227 $this->assertEquals('03:00:00', $form->getData());
228 $this->assertEquals('03', $form->getViewData());
229 }
230
231 public function testSetDataWithoutMinutes()
232 {
233 $form = $this->factory->create('time', null, array(
234 'model_timezone' => 'UTC',
235 'view_timezone' => 'UTC',
236 'input' => 'datetime',
237 'with_minutes' => false,
238 ));
239
240 $form->setData(new \DateTime('03:04:05 UTC'));
241
242 $this->assertEquals(array('hour' => 3), $form->getViewData());
243 }
244
245 public function testSetDataWithSeconds()
246 {
247 $form = $this->factory->create('time', null, array(
248 'model_timezone' => 'UTC',
249 'view_timezone' => 'UTC',
250 'input' => 'datetime',
251 'with_seconds' => true,
252 ));
253
254 $form->setData(new \DateTime('03:04:05 UTC'));
255
256 $this->assertEquals(array('hour' => 3, 'minute' => 4, 'second' => 5), $form->getViewData());
257 }
258
259 public function testSetDataDifferentTimezones()
260 {
261 $form = $this->factory->create('time', null, array(
262 'model_timezone' => 'America/New_York',
263 'view_timezone' => 'Asia/Hong_Kong',
264 'input' => 'string',
265 'with_seconds' => true,
266 ));
267
268 $dateTime = new \DateTime('2013-01-01 12:04:05');
269 $dateTime->setTimezone(new \DateTimeZone('America/New_York'));
270
271 $form->setData($dateTime->format('H:i:s'));
272
273 $outputTime = clone $dateTime;
274 $outputTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
275
276 $displayedData = array(
277 'hour' => (int) $outputTime->format('H'),
278 'minute' => (int) $outputTime->format('i'),
279 'second' => (int) $outputTime->format('s')
280 );
281
282 $this->assertEquals($displayedData, $form->getViewData());
283 }
284
285 public function testSetDataDifferentTimezonesDateTime()
286 {
287 $form = $this->factory->create('time', null, array(
288 'model_timezone' => 'America/New_York',
289 'view_timezone' => 'Asia/Hong_Kong',
290 'input' => 'datetime',
291 'with_seconds' => true,
292 ));
293
294 $dateTime = new \DateTime('12:04:05');
295 $dateTime->setTimezone(new \DateTimeZone('America/New_York'));
296
297 $form->setData($dateTime);
298
299 $outputTime = clone $dateTime;
300 $outputTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
301
302 $displayedData = array(
303 'hour' => (int) $outputTime->format('H'),
304 'minute' => (int) $outputTime->format('i'),
305 'second' => (int) $outputTime->format('s')
306 );
307
308 $this->assertDateTimeEquals($dateTime, $form->getData());
309 $this->assertEquals($displayedData, $form->getViewData());
310 }
311
312 public function testHoursOption()
313 {
314 $form = $this->factory->create('time', null, array(
315 'hours' => array(6, 7),
316 ));
317
318 $view = $form->createView();
319
320 $this->assertEquals(array(
321 new ChoiceView('6', '6', '06'),
322 new ChoiceView('7', '7', '07'),
323 ), $view['hour']->vars['choices']);
324 }
325
326 public function testIsMinuteWithinRangeReturnsTrueIfWithin()
327 {
328 $form = $this->factory->create('time', null, array(
329 'minutes' => array(6, 7),
330 ));
331
332 $view = $form->createView();
333
334 $this->assertEquals(array(
335 new ChoiceView('6', '6', '06'),
336 new ChoiceView('7', '7', '07'),
337 ), $view['minute']->vars['choices']);
338 }
339
340 public function testIsSecondWithinRangeReturnsTrueIfWithin()
341 {
342 $form = $this->factory->create('time', null, array(
343 'seconds' => array(6, 7),
344 'with_seconds' => true,
345 ));
346
347 $view = $form->createView();
348
349 $this->assertEquals(array(
350 new ChoiceView('6', '6', '06'),
351 new ChoiceView('7', '7', '07'),
352 ), $view['second']->vars['choices']);
353 }
354
355 public function testIsPartiallyFilledReturnsFalseIfCompletelyEmpty()
356 {
357 $this->markTestIncomplete('Needs to be reimplemented using validators');
358
359 $form = $this->factory->create('time', null, array(
360 'widget' => 'choice',
361 ));
362
363 $form->submit(array(
364 'hour' => '',
365 'minute' => '',
366 ));
367
368 $this->assertFalse($form->isPartiallyFilled());
369 }
370
371 public function testIsPartiallyFilledReturnsFalseIfCompletelyEmptyWithSeconds()
372 {
373 $this->markTestIncomplete('Needs to be reimplemented using validators');
374
375 $form = $this->factory->create('time', null, array(
376 'widget' => 'choice',
377 'with_seconds' => true,
378 ));
379
380 $form->submit(array(
381 'hour' => '',
382 'minute' => '',
383 'second' => '',
384 ));
385
386 $this->assertFalse($form->isPartiallyFilled());
387 }
388
389 public function testIsPartiallyFilledReturnsFalseIfCompletelyFilled()
390 {
391 $this->markTestIncomplete('Needs to be reimplemented using validators');
392
393 $form = $this->factory->create('time', null, array(
394 'widget' => 'choice',
395 ));
396
397 $form->submit(array(
398 'hour' => '0',
399 'minute' => '0',
400 ));
401
402 $this->assertFalse($form->isPartiallyFilled());
403 }
404
405 public function testIsPartiallyFilledReturnsFalseIfCompletelyFilledWithSeconds()
406 {
407 $this->markTestIncomplete('Needs to be reimplemented using validators');
408
409 $form = $this->factory->create('time', null, array(
410 'widget' => 'choice',
411 'with_seconds' => true,
412 ));
413
414 $form->submit(array(
415 'hour' => '0',
416 'minute' => '0',
417 'second' => '0',
418 ));
419
420 $this->assertFalse($form->isPartiallyFilled());
421 }
422
423 public function testIsPartiallyFilledReturnsTrueIfChoiceAndHourEmpty()
424 {
425 $this->markTestIncomplete('Needs to be reimplemented using validators');
426
427 $form = $this->factory->create('time', null, array(
428 'widget' => 'choice',
429 'with_seconds' => true,
430 ));
431
432 $form->submit(array(
433 'hour' => '',
434 'minute' => '0',
435 'second' => '0',
436 ));
437
438 $this->assertTrue($form->isPartiallyFilled());
439 }
440
441 public function testIsPartiallyFilledReturnsTrueIfChoiceAndMinuteEmpty()
442 {
443 $this->markTestIncomplete('Needs to be reimplemented using validators');
444
445 $form = $this->factory->create('time', null, array(
446 'widget' => 'choice',
447 'with_seconds' => true,
448 ));
449
450 $form->submit(array(
451 'hour' => '0',
452 'minute' => '',
453 'second' => '0',
454 ));
455
456 $this->assertTrue($form->isPartiallyFilled());
457 }
458
459 public function testIsPartiallyFilledReturnsTrueIfChoiceAndSecondsEmpty()
460 {
461 $this->markTestIncomplete('Needs to be reimplemented using validators');
462
463 $form = $this->factory->create('time', null, array(
464 'widget' => 'choice',
465 'with_seconds' => true,
466 ));
467
468 $form->submit(array(
469 'hour' => '0',
470 'minute' => '0',
471 'second' => '',
472 ));
473
474 $this->assertTrue($form->isPartiallyFilled());
475 }
476
477 // Bug fix
478 public function testInitializeWithDateTime()
479 {
480 // Throws an exception if "data_class" option is not explicitly set
481 // to null in the type
482 $this->factory->create('time', new \DateTime());
483 }
484
485 public function testSingleTextWidgetShouldUseTheRightInputType()
486 {
487 $form = $this->factory->create('time', null, array(
488 'widget' => 'single_text',
489 ));
490
491 $view = $form->createView();
492 $this->assertEquals('time', $view->vars['type']);
493 }
494
495 public function testPassDefaultEmptyValueToViewIfNotRequired()
496 {
497 $form = $this->factory->create('time', null, array(
498 'required' => false,
499 'with_seconds' => true,
500 ));
501
502 $view = $form->createView();
503 $this->assertSame('', $view['hour']->vars['empty_value']);
504 $this->assertSame('', $view['minute']->vars['empty_value']);
505 $this->assertSame('', $view['second']->vars['empty_value']);
506 }
507
508 public function testPassNoEmptyValueToViewIfRequired()
509 {
510 $form = $this->factory->create('time', null, array(
511 'required' => true,
512 'with_seconds' => true,
513 ));
514
515 $view = $form->createView();
516 $this->assertNull($view['hour']->vars['empty_value']);
517 $this->assertNull($view['minute']->vars['empty_value']);
518 $this->assertNull($view['second']->vars['empty_value']);
519 }
520
521 public function testPassEmptyValueAsString()
522 {
523 $form = $this->factory->create('time', null, array(
524 'empty_value' => 'Empty',
525 'with_seconds' => true,
526 ));
527
528 $view = $form->createView();
529 $this->assertSame('Empty', $view['hour']->vars['empty_value']);
530 $this->assertSame('Empty', $view['minute']->vars['empty_value']);
531 $this->assertSame('Empty', $view['second']->vars['empty_value']);
532 }
533
534 public function testPassEmptyValueAsArray()
535 {
536 $form = $this->factory->create('time', null, array(
537 'empty_value' => array(
538 'hour' => 'Empty hour',
539 'minute' => 'Empty minute',
540 'second' => 'Empty second',
541 ),
542 'with_seconds' => true,
543 ));
544
545 $view = $form->createView();
546 $this->assertSame('Empty hour', $view['hour']->vars['empty_value']);
547 $this->assertSame('Empty minute', $view['minute']->vars['empty_value']);
548 $this->assertSame('Empty second', $view['second']->vars['empty_value']);
549 }
550
551 public function testPassEmptyValueAsPartialArrayAddEmptyIfNotRequired()
552 {
553 $form = $this->factory->create('time', null, array(
554 'required' => false,
555 'empty_value' => array(
556 'hour' => 'Empty hour',
557 'second' => 'Empty second',
558 ),
559 'with_seconds' => true,
560 ));
561
562 $view = $form->createView();
563 $this->assertSame('Empty hour', $view['hour']->vars['empty_value']);
564 $this->assertSame('', $view['minute']->vars['empty_value']);
565 $this->assertSame('Empty second', $view['second']->vars['empty_value']);
566 }
567
568 public function testPassEmptyValueAsPartialArrayAddNullIfRequired()
569 {
570 $form = $this->factory->create('time', null, array(
571 'required' => true,
572 'empty_value' => array(
573 'hour' => 'Empty hour',
574 'second' => 'Empty second',
575 ),
576 'with_seconds' => true,
577 ));
578
579 $view = $form->createView();
580 $this->assertSame('Empty hour', $view['hour']->vars['empty_value']);
581 $this->assertNull($view['minute']->vars['empty_value']);
582 $this->assertSame('Empty second', $view['second']->vars['empty_value']);
583 }
584
585 public function provideCompoundWidgets()
586 {
587 return array(
588 array('text'),
589 array('choice'),
590 );
591 }
592
593 /**
594 * @dataProvider provideCompoundWidgets
595 */
596 public function testHourErrorsBubbleUp($widget)
597 {
598 $error = new FormError('Invalid!');
599 $form = $this->factory->create('time', null, array(
600 'widget' => $widget,
601 ));
602 $form['hour']->addError($error);
603
604 $this->assertSame(array(), $form['hour']->getErrors());
605 $this->assertSame(array($error), $form->getErrors());
606 }
607
608 /**
609 * @dataProvider provideCompoundWidgets
610 */
611 public function testMinuteErrorsBubbleUp($widget)
612 {
613 $error = new FormError('Invalid!');
614 $form = $this->factory->create('time', null, array(
615 'widget' => $widget,
616 ));
617 $form['minute']->addError($error);
618
619 $this->assertSame(array(), $form['minute']->getErrors());
620 $this->assertSame(array($error), $form->getErrors());
621 }
622
623 /**
624 * @dataProvider provideCompoundWidgets
625 */
626 public function testSecondErrorsBubbleUp($widget)
627 {
628 $error = new FormError('Invalid!');
629 $form = $this->factory->create('time', null, array(
630 'widget' => $widget,
631 'with_seconds' => true,
632 ));
633 $form['second']->addError($error);
634
635 $this->assertSame(array(), $form['second']->getErrors());
636 $this->assertSame(array($error), $form->getErrors());
637 }
638
639 /**
640 * @expectedException \Symfony\Component\Form\Exception\InvalidConfigurationException
641 */
642 public function testInitializeWithSecondsAndWithoutMinutes()
643 {
644 $this->factory->create('time', null, array(
645 'with_minutes' => false,
646 'with_seconds' => true,
647 ));
648 }
649}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TimezoneTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TimezoneTypeTest.php
new file mode 100644
index 00000000..81df20cb
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TimezoneTypeTest.php
@@ -0,0 +1,30 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Extension\Core\View\ChoiceView;
15
16class TimezoneTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
17{
18 public function testTimezonesAreSelectable()
19 {
20 $form = $this->factory->create('timezone');
21 $view = $form->createView();
22 $choices = $view->vars['choices'];
23
24 $this->assertArrayHasKey('Africa', $choices);
25 $this->assertContains(new ChoiceView('Africa/Kinshasa', 'Africa/Kinshasa', 'Kinshasa'), $choices['Africa'], '', false, false);
26
27 $this->assertArrayHasKey('America', $choices);
28 $this->assertContains(new ChoiceView('America/New_York', 'America/New_York', 'New York'), $choices['America'], '', false, false);
29 }
30}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TypeTestCase.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TypeTestCase.php
new file mode 100644
index 00000000..733546e3
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/TypeTestCase.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14use Symfony\Component\Form\Test\TypeTestCase as BaseTypeTestCase;
15
16/**
17 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use Symfony\Component\Form\Test\TypeTestCase instead.
18 */
19abstract class TypeTestCase extends BaseTypeTestCase
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php
new file mode 100644
index 00000000..254b2a8e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Core/Type/UrlTypeTest.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13
14class UrlTypeTest extends TypeTestCase
15{
16 public function testSubmitAddsDefaultProtocolIfNoneIsIncluded()
17 {
18 $form = $this->factory->create('url', 'name');
19
20 $form->submit('www.domain.com');
21
22 $this->assertSame('http://www.domain.com', $form->getData());
23 $this->assertSame('http://www.domain.com', $form->getViewData());
24 }
25
26 public function testSubmitAddsNoDefaultProtocolIfAlreadyIncluded()
27 {
28 $form = $this->factory->create('url', null, array(
29 'default_protocol' => 'http',
30 ));
31
32 $form->submit('ftp://www.domain.com');
33
34 $this->assertSame('ftp://www.domain.com', $form->getData());
35 $this->assertSame('ftp://www.domain.com', $form->getViewData());
36 }
37
38 public function testSubmitAddsNoDefaultProtocolIfEmpty()
39 {
40 $form = $this->factory->create('url', null, array(
41 'default_protocol' => 'http',
42 ));
43
44 $form->submit('');
45
46 $this->assertNull($form->getData());
47 $this->assertSame('', $form->getViewData());
48 }
49
50 public function testSubmitAddsNoDefaultProtocolIfSetToNull()
51 {
52 $form = $this->factory->create('url', null, array(
53 'default_protocol' => null,
54 ));
55
56 $form->submit('www.domain.com');
57
58 $this->assertSame('www.domain.com', $form->getData());
59 $this->assertSame('www.domain.com', $form->getViewData());
60 }
61}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/CsrfProvider/DefaultCsrfProviderTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/CsrfProvider/DefaultCsrfProviderTest.php
new file mode 100644
index 00000000..a99b5444
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/CsrfProvider/DefaultCsrfProviderTest.php
@@ -0,0 +1,81 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Csrf\CsrfProvider;
13
14use Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider;
15
16/**
17 * @runTestsInSeparateProcesses
18 */
19class DefaultCsrfProviderTest extends \PHPUnit_Framework_TestCase
20{
21 protected $provider;
22
23 public static function setUpBeforeClass()
24 {
25 ini_set('session.save_handler', 'files');
26 ini_set('session.save_path', sys_get_temp_dir());
27 }
28
29 protected function setUp()
30 {
31 $this->provider = new DefaultCsrfProvider('SECRET');
32 }
33
34 protected function tearDown()
35 {
36 $this->provider = null;
37 }
38
39 public function testGenerateCsrfToken()
40 {
41 session_start();
42
43 $token = $this->provider->generateCsrfToken('foo');
44
45 $this->assertEquals(sha1('SECRET'.'foo'.session_id()), $token);
46 }
47
48 public function testGenerateCsrfTokenOnUnstartedSession()
49 {
50 session_id('touti');
51
52 if (!version_compare(PHP_VERSION, '5.4', '>=')) {
53 $this->markTestSkipped('This test requires PHP >= 5.4');
54 }
55
56 $this->assertSame(PHP_SESSION_NONE, session_status());
57
58 $token = $this->provider->generateCsrfToken('foo');
59
60 $this->assertEquals(sha1('SECRET'.'foo'.session_id()), $token);
61 $this->assertSame(PHP_SESSION_ACTIVE, session_status());
62 }
63
64 public function testIsCsrfTokenValidSucceeds()
65 {
66 session_start();
67
68 $token = sha1('SECRET'.'foo'.session_id());
69
70 $this->assertTrue($this->provider->isCsrfTokenValid('foo', $token));
71 }
72
73 public function testIsCsrfTokenValidFails()
74 {
75 session_start();
76
77 $token = sha1('SECRET'.'bar'.session_id());
78
79 $this->assertFalse($this->provider->isCsrfTokenValid('foo', $token));
80 }
81}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/CsrfProvider/SessionCsrfProviderTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/CsrfProvider/SessionCsrfProviderTest.php
new file mode 100644
index 00000000..1dcc6b4c
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/CsrfProvider/SessionCsrfProviderTest.php
@@ -0,0 +1,75 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Csrf\CsrfProvider;
13
14use Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider;
15
16class SessionCsrfProviderTest extends \PHPUnit_Framework_TestCase
17{
18 protected $provider;
19 protected $session;
20
21 protected function setUp()
22 {
23 if (!class_exists('Symfony\Component\HttpFoundation\Session\Session')) {
24 $this->markTestSkipped('The "HttpFoundation" component is not available');
25 }
26
27 $this->session = $this->getMock(
28 'Symfony\Component\HttpFoundation\Session\Session',
29 array(),
30 array(),
31 '',
32 false // don't call constructor
33 );
34 $this->provider = new SessionCsrfProvider($this->session, 'SECRET');
35 }
36
37 protected function tearDown()
38 {
39 $this->provider = null;
40 $this->session = null;
41 }
42
43 public function testGenerateCsrfToken()
44 {
45 $this->session->expects($this->once())
46 ->method('getId')
47 ->will($this->returnValue('ABCDEF'));
48
49 $token = $this->provider->generateCsrfToken('foo');
50
51 $this->assertEquals(sha1('SECRET'.'foo'.'ABCDEF'), $token);
52 }
53
54 public function testIsCsrfTokenValidSucceeds()
55 {
56 $this->session->expects($this->once())
57 ->method('getId')
58 ->will($this->returnValue('ABCDEF'));
59
60 $token = sha1('SECRET'.'foo'.'ABCDEF');
61
62 $this->assertTrue($this->provider->isCsrfTokenValid('foo', $token));
63 }
64
65 public function testIsCsrfTokenValidFails()
66 {
67 $this->session->expects($this->once())
68 ->method('getId')
69 ->will($this->returnValue('ABCDEF'));
70
71 $token = sha1('SECRET'.'bar'.'ABCDEF');
72
73 $this->assertFalse($this->provider->isCsrfTokenValid('foo', $token));
74 }
75}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php
new file mode 100644
index 00000000..0bcfe74e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php
@@ -0,0 +1,78 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener;
13
14use Symfony\Component\Form\FormBuilder;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
17
18class CsrfValidationListenerTest extends \PHPUnit_Framework_TestCase
19{
20 protected $dispatcher;
21 protected $factory;
22 protected $csrfProvider;
23
24 protected function setUp()
25 {
26 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
27 $this->markTestSkipped('The "EventDispatcher" component is not available');
28 }
29
30 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
31 $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
32 $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
33 $this->form = $this->getBuilder('post')
34 ->setDataMapper($this->getDataMapper())
35 ->getForm();
36 }
37
38 protected function tearDown()
39 {
40 $this->dispatcher = null;
41 $this->factory = null;
42 $this->csrfProvider = null;
43 $this->form = null;
44 }
45
46 protected function getBuilder($name = 'name')
47 {
48 return new FormBuilder($name, null, $this->dispatcher, $this->factory, array('compound' => true));
49 }
50
51 protected function getForm($name = 'name')
52 {
53 return $this->getBuilder($name)->getForm();
54 }
55
56 protected function getDataMapper()
57 {
58 return $this->getMock('Symfony\Component\Form\DataMapperInterface');
59 }
60
61 protected function getMockForm()
62 {
63 return $this->getMock('Symfony\Component\Form\Test\FormInterface');
64 }
65
66 // https://github.com/symfony/symfony/pull/5838
67 public function testStringFormData()
68 {
69 $data = "XP4HUzmHPi";
70 $event = new FormEvent($this->form, $data);
71
72 $validation = new CsrfValidationListener('csrf', $this->csrfProvider, 'unknown', 'Invalid.');
73 $validation->preSubmit($event);
74
75 // Validate accordingly
76 $this->assertSame($data, $event->getData());
77 }
78}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php
new file mode 100644
index 00000000..0a1f0dc4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php
@@ -0,0 +1,301 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Csrf\Type;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilderInterface;
16use Symfony\Component\Form\FormError;
17use Symfony\Component\Form\Test\TypeTestCase;
18use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
19
20class FormTypeCsrfExtensionTest_ChildType extends AbstractType
21{
22 public function buildForm(FormBuilderInterface $builder, array $options)
23 {
24 // The form needs a child in order to trigger CSRF protection by
25 // default
26 $builder->add('name', 'text');
27 }
28
29 public function getName()
30 {
31 return 'csrf_collection_test';
32 }
33}
34
35class FormTypeCsrfExtensionTest extends TypeTestCase
36{
37 /**
38 * @var \PHPUnit_Framework_MockObject_MockObject
39 */
40 protected $csrfProvider;
41
42 /**
43 * @var \PHPUnit_Framework_MockObject_MockObject
44 */
45 protected $translator;
46
47 protected function setUp()
48 {
49 $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
50 $this->translator = $this->getMock('Symfony\Component\Translation\TranslatorInterface');
51
52 parent::setUp();
53 }
54
55 protected function tearDown()
56 {
57 $this->csrfProvider = null;
58 $this->translator = null;
59
60 parent::tearDown();
61 }
62
63 protected function getExtensions()
64 {
65 return array_merge(parent::getExtensions(), array(
66 new CsrfExtension($this->csrfProvider, $this->translator),
67 ));
68 }
69
70 public function testCsrfProtectionByDefaultIfRootAndCompound()
71 {
72 $view = $this->factory
73 ->create('form', null, array(
74 'csrf_field_name' => 'csrf',
75 'compound' => true,
76 ))
77 ->createView();
78
79 $this->assertTrue(isset($view['csrf']));
80 }
81
82 public function testNoCsrfProtectionByDefaultIfCompoundButNotRoot()
83 {
84 $view = $this->factory
85 ->createNamedBuilder('root', 'form')
86 ->add($this->factory
87 ->createNamedBuilder('form', 'form', null, array(
88 'csrf_field_name' => 'csrf',
89 'compound' => true,
90 ))
91 )
92 ->getForm()
93 ->get('form')
94 ->createView();
95
96 $this->assertFalse(isset($view['csrf']));
97 }
98
99 public function testNoCsrfProtectionByDefaultIfRootButNotCompound()
100 {
101 $view = $this->factory
102 ->create('form', null, array(
103 'csrf_field_name' => 'csrf',
104 'compound' => false,
105 ))
106 ->createView();
107
108 $this->assertFalse(isset($view['csrf']));
109 }
110
111 public function testCsrfProtectionCanBeDisabled()
112 {
113 $view = $this->factory
114 ->create('form', null, array(
115 'csrf_field_name' => 'csrf',
116 'csrf_protection' => false,
117 'compound' => true,
118 ))
119 ->createView();
120
121 $this->assertFalse(isset($view['csrf']));
122 }
123
124 public function testGenerateCsrfToken()
125 {
126 $this->csrfProvider->expects($this->once())
127 ->method('generateCsrfToken')
128 ->with('%INTENTION%')
129 ->will($this->returnValue('token'));
130
131 $view = $this->factory
132 ->create('form', null, array(
133 'csrf_field_name' => 'csrf',
134 'csrf_provider' => $this->csrfProvider,
135 'intention' => '%INTENTION%',
136 'compound' => true,
137 ))
138 ->createView();
139
140 $this->assertEquals('token', $view['csrf']->vars['value']);
141 }
142
143 public function provideBoolean()
144 {
145 return array(
146 array(true),
147 array(false),
148 );
149 }
150
151 /**
152 * @dataProvider provideBoolean
153 */
154 public function testValidateTokenOnSubmitIfRootAndCompound($valid)
155 {
156 $this->csrfProvider->expects($this->once())
157 ->method('isCsrfTokenValid')
158 ->with('%INTENTION%', 'token')
159 ->will($this->returnValue($valid));
160
161 $form = $this->factory
162 ->createBuilder('form', null, array(
163 'csrf_field_name' => 'csrf',
164 'csrf_provider' => $this->csrfProvider,
165 'intention' => '%INTENTION%',
166 'compound' => true,
167 ))
168 ->add('child', 'text')
169 ->getForm();
170
171 $form->submit(array(
172 'child' => 'foobar',
173 'csrf' => 'token',
174 ));
175
176 // Remove token from data
177 $this->assertSame(array('child' => 'foobar'), $form->getData());
178
179 // Validate accordingly
180 $this->assertSame($valid, $form->isValid());
181 }
182
183 public function testFailIfRootAndCompoundAndTokenMissing()
184 {
185 $this->csrfProvider->expects($this->never())
186 ->method('isCsrfTokenValid');
187
188 $form = $this->factory
189 ->createBuilder('form', null, array(
190 'csrf_field_name' => 'csrf',
191 'csrf_provider' => $this->csrfProvider,
192 'intention' => '%INTENTION%',
193 'compound' => true,
194 ))
195 ->add('child', 'text')
196 ->getForm();
197
198 $form->submit(array(
199 'child' => 'foobar',
200 // token is missing
201 ));
202
203 // Remove token from data
204 $this->assertSame(array('child' => 'foobar'), $form->getData());
205
206 // Validate accordingly
207 $this->assertFalse($form->isValid());
208 }
209
210 public function testDontValidateTokenIfCompoundButNoRoot()
211 {
212 $this->csrfProvider->expects($this->never())
213 ->method('isCsrfTokenValid');
214
215 $form = $this->factory
216 ->createNamedBuilder('root', 'form')
217 ->add($this->factory
218 ->createNamedBuilder('form', 'form', null, array(
219 'csrf_field_name' => 'csrf',
220 'csrf_provider' => $this->csrfProvider,
221 'intention' => '%INTENTION%',
222 'compound' => true,
223 ))
224 )
225 ->getForm()
226 ->get('form');
227
228 $form->submit(array(
229 'child' => 'foobar',
230 'csrf' => 'token',
231 ));
232 }
233
234 public function testDontValidateTokenIfRootButNotCompound()
235 {
236 $this->csrfProvider->expects($this->never())
237 ->method('isCsrfTokenValid');
238
239 $form = $this->factory
240 ->create('form', null, array(
241 'csrf_field_name' => 'csrf',
242 'csrf_provider' => $this->csrfProvider,
243 'intention' => '%INTENTION%',
244 'compound' => false,
245 ));
246
247 $form->submit(array(
248 'csrf' => 'token',
249 ));
250 }
251
252 public function testNoCsrfProtectionOnPrototype()
253 {
254 $prototypeView = $this->factory
255 ->create('collection', null, array(
256 'type' => new FormTypeCsrfExtensionTest_ChildType(),
257 'options' => array(
258 'csrf_field_name' => 'csrf',
259 ),
260 'prototype' => true,
261 'allow_add' => true,
262 ))
263 ->createView()
264 ->vars['prototype'];
265
266 $this->assertFalse(isset($prototypeView['csrf']));
267 $this->assertCount(1, $prototypeView);
268 }
269
270 public function testsTranslateCustomErrorMessage()
271 {
272 $this->csrfProvider->expects($this->once())
273 ->method('isCsrfTokenValid')
274 ->with('%INTENTION%', 'token')
275 ->will($this->returnValue(false));
276
277 $this->translator->expects($this->once())
278 ->method('trans')
279 ->with('Foobar')
280 ->will($this->returnValue('[trans]Foobar[/trans]'));
281
282 $form = $this->factory
283 ->createBuilder('form', null, array(
284 'csrf_field_name' => 'csrf',
285 'csrf_provider' => $this->csrfProvider,
286 'csrf_message' => 'Foobar',
287 'intention' => '%INTENTION%',
288 'compound' => true,
289 ))
290 ->getForm();
291
292 $form->submit(array(
293 'csrf' => 'token',
294 ));
295
296 $errors = $form->getErrors();
297
298 $this->assertGreaterThan(0, count($errors));
299 $this->assertEquals(new FormError('[trans]Foobar[/trans]'), $errors[0]);
300 }
301}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/HttpFoundation/EventListener/BindRequestListenerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/HttpFoundation/EventListener/BindRequestListenerTest.php
new file mode 100644
index 00000000..2ff072b2
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/HttpFoundation/EventListener/BindRequestListenerTest.php
@@ -0,0 +1,286 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\HttpFoundation\EventListener;
13
14use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
15use Symfony\Component\Form\Form;
16use Symfony\Component\Form\FormConfigBuilder;
17use Symfony\Component\Form\FormEvent;
18use Symfony\Component\Form\Test\DeprecationErrorHandler;
19use Symfony\Component\HttpFoundation\Request;
20use Symfony\Component\HttpFoundation\File\UploadedFile;
21
22/**
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
26{
27 private $values;
28
29 private $filesPlain;
30
31 private $filesNested;
32
33 /**
34 * @var UploadedFile
35 */
36 private $uploadedFile;
37
38 protected function setUp()
39 {
40 $path = tempnam(sys_get_temp_dir(), 'sf2');
41 touch($path);
42
43 $this->values = array(
44 'name' => 'Bernhard',
45 'image' => array('filename' => 'foobar.png'),
46 );
47
48 $this->filesPlain = array(
49 'image' => array(
50 'error' => UPLOAD_ERR_OK,
51 'name' => 'upload.png',
52 'size' => 123,
53 'tmp_name' => $path,
54 'type' => 'image/png'
55 ),
56 );
57
58 $this->filesNested = array(
59 'error' => array('image' => UPLOAD_ERR_OK),
60 'name' => array('image' => 'upload.png'),
61 'size' => array('image' => 123),
62 'tmp_name' => array('image' => $path),
63 'type' => array('image' => 'image/png'),
64 );
65
66 $this->uploadedFile = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
67 }
68
69 protected function tearDown()
70 {
71 unlink($this->uploadedFile->getRealPath());
72 }
73
74 public function requestMethodProvider()
75 {
76 return array(
77 array('POST'),
78 array('PUT'),
79 array('DELETE'),
80 array('PATCH'),
81 );
82 }
83
84 /**
85 * @dataProvider requestMethodProvider
86 */
87 public function testSubmitRequest($method)
88 {
89 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
90 $this->markTestSkipped('The "HttpFoundation" component is not available');
91 }
92
93 $values = array('author' => $this->values);
94 $files = array('author' => $this->filesNested);
95 $request = new Request(array(), $values, array(), array(), $files, array(
96 'REQUEST_METHOD' => $method,
97 ));
98
99 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
100 $config = new FormConfigBuilder('author', null, $dispatcher);
101 $form = new Form($config);
102 $event = new FormEvent($form, $request);
103
104 $listener = new BindRequestListener();
105 DeprecationErrorHandler::preBind($listener, $event);
106
107 $this->assertEquals(array(
108 'name' => 'Bernhard',
109 'image' => $this->uploadedFile,
110 ), $event->getData());
111 }
112
113 /**
114 * @dataProvider requestMethodProvider
115 */
116 public function testSubmitRequestWithEmptyName($method)
117 {
118 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
119 $this->markTestSkipped('The "HttpFoundation" component is not available');
120 }
121
122 $request = new Request(array(), $this->values, array(), array(), $this->filesPlain, array(
123 'REQUEST_METHOD' => $method,
124 ));
125
126 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
127 $config = new FormConfigBuilder('', null, $dispatcher);
128 $form = new Form($config);
129 $event = new FormEvent($form, $request);
130
131 $listener = new BindRequestListener();
132 DeprecationErrorHandler::preBind($listener, $event);
133
134 $this->assertEquals(array(
135 'name' => 'Bernhard',
136 'image' => $this->uploadedFile,
137 ), $event->getData());
138 }
139
140 /**
141 * @dataProvider requestMethodProvider
142 */
143 public function testSubmitEmptyRequestToCompoundForm($method)
144 {
145 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
146 $this->markTestSkipped('The "HttpFoundation" component is not available');
147 }
148
149 $request = new Request(array(), array(), array(), array(), array(), array(
150 'REQUEST_METHOD' => $method,
151 ));
152
153 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
154 $config = new FormConfigBuilder('author', null, $dispatcher);
155 $config->setCompound(true);
156 $config->setDataMapper($this->getMock('Symfony\Component\Form\DataMapperInterface'));
157 $form = new Form($config);
158 $event = new FormEvent($form, $request);
159
160 $listener = new BindRequestListener();
161 DeprecationErrorHandler::preBind($listener, $event);
162
163 // Default to empty array
164 $this->assertEquals(array(), $event->getData());
165 }
166
167 /**
168 * @dataProvider requestMethodProvider
169 */
170 public function testSubmitEmptyRequestToSimpleForm($method)
171 {
172 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
173 $this->markTestSkipped('The "HttpFoundation" component is not available');
174 }
175
176 $request = new Request(array(), array(), array(), array(), array(), array(
177 'REQUEST_METHOD' => $method,
178 ));
179
180 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
181 $config = new FormConfigBuilder('author', null, $dispatcher);
182 $config->setCompound(false);
183 $form = new Form($config);
184 $event = new FormEvent($form, $request);
185
186 $listener = new BindRequestListener();
187 DeprecationErrorHandler::preBind($listener, $event);
188
189 // Default to null
190 $this->assertNull($event->getData());
191 }
192
193 public function testSubmitGetRequest()
194 {
195 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
196 $this->markTestSkipped('The "HttpFoundation" component is not available');
197 }
198
199 $values = array('author' => $this->values);
200 $request = new Request($values, array(), array(), array(), array(), array(
201 'REQUEST_METHOD' => 'GET',
202 ));
203
204 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
205 $config = new FormConfigBuilder('author', null, $dispatcher);
206 $form = new Form($config);
207 $event = new FormEvent($form, $request);
208
209 $listener = new BindRequestListener();
210 DeprecationErrorHandler::preBind($listener, $event);
211
212 $this->assertEquals(array(
213 'name' => 'Bernhard',
214 'image' => array('filename' => 'foobar.png'),
215 ), $event->getData());
216 }
217
218 public function testSubmitGetRequestWithEmptyName()
219 {
220 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
221 $this->markTestSkipped('The "HttpFoundation" component is not available');
222 }
223
224 $request = new Request($this->values, array(), array(), array(), array(), array(
225 'REQUEST_METHOD' => 'GET',
226 ));
227
228 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
229 $config = new FormConfigBuilder('', null, $dispatcher);
230 $form = new Form($config);
231 $event = new FormEvent($form, $request);
232
233 $listener = new BindRequestListener();
234 DeprecationErrorHandler::preBind($listener, $event);
235
236 $this->assertEquals(array(
237 'name' => 'Bernhard',
238 'image' => array('filename' => 'foobar.png'),
239 ), $event->getData());
240 }
241
242 public function testSubmitEmptyGetRequestToCompoundForm()
243 {
244 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
245 $this->markTestSkipped('The "HttpFoundation" component is not available');
246 }
247
248 $request = new Request(array(), array(), array(), array(), array(), array(
249 'REQUEST_METHOD' => 'GET',
250 ));
251
252 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
253 $config = new FormConfigBuilder('author', null, $dispatcher);
254 $config->setCompound(true);
255 $config->setDataMapper($this->getMock('Symfony\Component\Form\DataMapperInterface'));
256 $form = new Form($config);
257 $event = new FormEvent($form, $request);
258
259 $listener = new BindRequestListener();
260 DeprecationErrorHandler::preBind($listener, $event);
261
262 $this->assertEquals(array(), $event->getData());
263 }
264
265 public function testSubmitEmptyGetRequestToSimpleForm()
266 {
267 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
268 $this->markTestSkipped('The "HttpFoundation" component is not available');
269 }
270
271 $request = new Request(array(), array(), array(), array(), array(), array(
272 'REQUEST_METHOD' => 'GET',
273 ));
274
275 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
276 $config = new FormConfigBuilder('author', null, $dispatcher);
277 $config->setCompound(false);
278 $form = new Form($config);
279 $event = new FormEvent($form, $request);
280
281 $listener = new BindRequestListener();
282 DeprecationErrorHandler::preBind($listener, $event);
283
284 $this->assertNull($event->getData());
285 }
286}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php
new file mode 100644
index 00000000..2d5cf776
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php
@@ -0,0 +1,54 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\HttpFoundation;
13
14use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
15use Symfony\Component\Form\Tests\AbstractRequestHandlerTest;
16use Symfony\Component\HttpFoundation\Request;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class HttpFoundationRequestHandlerTest extends AbstractRequestHandlerTest
22{
23 /**
24 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
25 */
26 public function testRequestShouldNotBeNull()
27 {
28 $this->requestHandler->handleRequest($this->getMockForm('name', 'GET'));
29 }
30 /**
31 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
32 */
33 public function testRequestShouldBeInstanceOfRequest()
34 {
35 $this->requestHandler->handleRequest($this->getMockForm('name', 'GET'), new \stdClass());
36 }
37
38 protected function setRequestData($method, $data, $files = array())
39 {
40 $this->request = Request::create('http://localhost', $method, $data, array(), $files);
41 }
42
43 protected function getRequestHandler()
44 {
45 return new HttpFoundationRequestHandler();
46 }
47
48 protected function getMockFile()
49 {
50 return $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
51 ->disableOriginalConstructor()
52 ->getMock();
53 }
54}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php
new file mode 100644
index 00000000..a8bdde8a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php
@@ -0,0 +1,748 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Validator\Constraints;
13
14use Symfony\Component\Form\FormBuilder;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16use Symfony\Component\Form\CallbackTransformer;
17use Symfony\Component\Form\FormInterface;
18use Symfony\Component\Form\Extension\Validator\Constraints\Form;
19use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
20use Symfony\Component\Form\SubmitButtonBuilder;
21use Symfony\Component\Validator\Constraint;
22use Symfony\Component\Validator\Constraints\NotNull;
23use Symfony\Component\Validator\Constraints\NotBlank;
24
25/**
26 * @author Bernhard Schussek <bschussek@gmail.com>
27 */
28class FormValidatorTest extends \PHPUnit_Framework_TestCase
29{
30 /**
31 * @var \PHPUnit_Framework_MockObject_MockObject
32 */
33 private $dispatcher;
34
35 /**
36 * @var \PHPUnit_Framework_MockObject_MockObject
37 */
38 private $factory;
39
40 /**
41 * @var \PHPUnit_Framework_MockObject_MockObject
42 */
43 private $serverParams;
44
45 /**
46 * @var FormValidator
47 */
48 private $validator;
49
50 protected function setUp()
51 {
52 if (!class_exists('Symfony\Component\EventDispatcher\Event')) {
53 $this->markTestSkipped('The "EventDispatcher" component is not available');
54 }
55
56 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
57 $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
58 $this->serverParams = $this->getMock(
59 'Symfony\Component\Form\Extension\Validator\Util\ServerParams',
60 array('getNormalizedIniPostMaxSize', 'getContentLength')
61 );
62 $this->validator = new FormValidator($this->serverParams);
63 }
64
65 public function testValidate()
66 {
67 $context = $this->getMockExecutionContext();
68 $object = $this->getMock('\stdClass');
69 $options = array('validation_groups' => array('group1', 'group2'));
70 $form = $this->getBuilder('name', '\stdClass', $options)
71 ->setData($object)
72 ->getForm();
73
74 $context->expects($this->at(0))
75 ->method('validate')
76 ->with($object, 'data', 'group1', true);
77 $context->expects($this->at(1))
78 ->method('validate')
79 ->with($object, 'data', 'group2', true);
80
81 $this->validator->initialize($context);
82 $this->validator->validate($form, new Form());
83 }
84
85 public function testValidateConstraints()
86 {
87 $context = $this->getMockExecutionContext();
88 $object = $this->getMock('\stdClass');
89 $constraint1 = new NotNull(array('groups' => array('group1', 'group2')));
90 $constraint2 = new NotBlank(array('groups' => 'group2'));
91
92 $options = array(
93 'validation_groups' => array('group1', 'group2'),
94 'constraints' => array($constraint1, $constraint2),
95 );
96 $form = $this->getBuilder('name', '\stdClass', $options)
97 ->setData($object)
98 ->getForm();
99
100 // First default constraints
101 $context->expects($this->at(0))
102 ->method('validate')
103 ->with($object, 'data', 'group1', true);
104 $context->expects($this->at(1))
105 ->method('validate')
106 ->with($object, 'data', 'group2', true);
107
108 // Then custom constraints
109 $context->expects($this->at(2))
110 ->method('validateValue')
111 ->with($object, $constraint1, 'data', 'group1');
112 $context->expects($this->at(3))
113 ->method('validateValue')
114 ->with($object, $constraint2, 'data', 'group2');
115
116 $this->validator->initialize($context);
117 $this->validator->validate($form, new Form());
118 }
119
120 public function testDontValidateIfParentWithoutCascadeValidation()
121 {
122 $context = $this->getMockExecutionContext();
123 $object = $this->getMock('\stdClass');
124
125 $parent = $this->getBuilder('parent', null, array('cascade_validation' => false))
126 ->setCompound(true)
127 ->setDataMapper($this->getDataMapper())
128 ->getForm();
129 $options = array('validation_groups' => array('group1', 'group2'));
130 $form = $this->getBuilder('name', '\stdClass', $options)->getForm();
131 $parent->add($form);
132
133 $form->setData($object);
134
135 $context->expects($this->never())
136 ->method('validate');
137
138 $this->validator->initialize($context);
139 $this->validator->validate($form, new Form());
140 }
141
142 public function testValidateConstraintsEvenIfNoCascadeValidation()
143 {
144 $context = $this->getMockExecutionContext();
145 $object = $this->getMock('\stdClass');
146 $constraint1 = new NotNull(array('groups' => array('group1', 'group2')));
147 $constraint2 = new NotBlank(array('groups' => 'group2'));
148
149 $parent = $this->getBuilder('parent', null, array('cascade_validation' => false))
150 ->setCompound(true)
151 ->setDataMapper($this->getDataMapper())
152 ->getForm();
153 $options = array(
154 'validation_groups' => array('group1', 'group2'),
155 'constraints' => array($constraint1, $constraint2),
156 );
157 $form = $this->getBuilder('name', '\stdClass', $options)
158 ->setData($object)
159 ->getForm();
160 $parent->add($form);
161
162 $context->expects($this->at(0))
163 ->method('validateValue')
164 ->with($object, $constraint1, 'data', 'group1');
165 $context->expects($this->at(1))
166 ->method('validateValue')
167 ->with($object, $constraint2, 'data', 'group2');
168
169 $this->validator->initialize($context);
170 $this->validator->validate($form, new Form());
171 }
172
173 public function testDontValidateIfNoValidationGroups()
174 {
175 $context = $this->getMockExecutionContext();
176 $object = $this->getMock('\stdClass');
177
178 $form = $this->getBuilder('name', '\stdClass', array(
179 'validation_groups' => array(),
180 ))
181 ->setData($object)
182 ->getForm();
183
184 $form->setData($object);
185
186 $context->expects($this->never())
187 ->method('validate');
188
189 $this->validator->initialize($context);
190 $this->validator->validate($form, new Form());
191 }
192
193 public function testDontValidateConstraintsIfNoValidationGroups()
194 {
195 $context = $this->getMockExecutionContext();
196 $object = $this->getMock('\stdClass');
197 $constraint1 = $this->getMock('Symfony\Component\Validator\Constraint');
198 $constraint2 = $this->getMock('Symfony\Component\Validator\Constraint');
199
200 $options = array(
201 'validation_groups' => array(),
202 'constraints' => array($constraint1, $constraint2),
203 );
204 $form = $this->getBuilder('name', '\stdClass', $options)
205 ->setData($object)
206 ->getForm();
207
208 // Launch transformer
209 $form->submit(array());
210
211 $context->expects($this->never())
212 ->method('validate');
213
214 $this->validator->initialize($context);
215 $this->validator->validate($form, new Form());
216 }
217
218 public function testDontValidateIfNotSynchronized()
219 {
220 $context = $this->getMockExecutionContext();
221 $object = $this->getMock('\stdClass');
222
223 $form = $this->getBuilder('name', '\stdClass', array(
224 'invalid_message' => 'invalid_message_key',
225 // Invalid message parameters must be supported, because the
226 // invalid message can be a translation key
227 // see https://github.com/symfony/symfony/issues/5144
228 'invalid_message_parameters' => array('{{ foo }}' => 'bar'),
229 ))
230 ->setData($object)
231 ->addViewTransformer(new CallbackTransformer(
232 function ($data) { return $data; },
233 function () { throw new TransformationFailedException(); }
234 ))
235 ->getForm();
236
237 // Launch transformer
238 $form->submit('foo');
239
240 $context->expects($this->never())
241 ->method('validate');
242
243 $context->expects($this->once())
244 ->method('addViolation')
245 ->with(
246 'invalid_message_key',
247 array('{{ value }}' => 'foo', '{{ foo }}' => 'bar'),
248 'foo'
249 );
250 $context->expects($this->never())
251 ->method('addViolationAt');
252
253 $this->validator->initialize($context);
254 $this->validator->validate($form, new Form());
255 }
256
257 public function testAddInvalidErrorEvenIfNoValidationGroups()
258 {
259 $context = $this->getMockExecutionContext();
260 $object = $this->getMock('\stdClass');
261
262 $form = $this->getBuilder('name', '\stdClass', array(
263 'invalid_message' => 'invalid_message_key',
264 // Invalid message parameters must be supported, because the
265 // invalid message can be a translation key
266 // see https://github.com/symfony/symfony/issues/5144
267 'invalid_message_parameters' => array('{{ foo }}' => 'bar'),
268 'validation_groups' => array(),
269 ))
270 ->setData($object)
271 ->addViewTransformer(new CallbackTransformer(
272 function ($data) { return $data; },
273 function () { throw new TransformationFailedException(); }
274 ))
275 ->getForm();
276
277 // Launch transformer
278 $form->submit('foo');
279
280 $context->expects($this->never())
281 ->method('validate');
282
283 $context->expects($this->once())
284 ->method('addViolation')
285 ->with(
286 'invalid_message_key',
287 array('{{ value }}' => 'foo', '{{ foo }}' => 'bar'),
288 'foo'
289 );
290 $context->expects($this->never())
291 ->method('addViolationAt');
292
293 $this->validator->initialize($context);
294 $this->validator->validate($form, new Form());
295 }
296
297 public function testDontValidateConstraintsIfNotSynchronized()
298 {
299 $context = $this->getMockExecutionContext();
300 $object = $this->getMock('\stdClass');
301 $constraint1 = $this->getMock('Symfony\Component\Validator\Constraint');
302 $constraint2 = $this->getMock('Symfony\Component\Validator\Constraint');
303
304 $options = array(
305 'validation_groups' => array('group1', 'group2'),
306 'constraints' => array($constraint1, $constraint2),
307 );
308 $form = $this->getBuilder('name', '\stdClass', $options)
309 ->setData($object)
310 ->addViewTransformer(new CallbackTransformer(
311 function ($data) { return $data; },
312 function () { throw new TransformationFailedException(); }
313 ))
314 ->getForm();
315
316 // Launch transformer
317 $form->submit(array());
318
319 $context->expects($this->never())
320 ->method('validate');
321
322 $this->validator->initialize($context);
323 $this->validator->validate($form, new Form());
324 }
325
326 // https://github.com/symfony/symfony/issues/4359
327 public function testDontMarkInvalidIfAnyChildIsNotSynchronized()
328 {
329 $context = $this->getMockExecutionContext();
330 $object = $this->getMock('\stdClass');
331
332 $failingTransformer = new CallbackTransformer(
333 function ($data) { return $data; },
334 function () { throw new TransformationFailedException(); }
335 );
336
337 $form = $this->getBuilder('name', '\stdClass')
338 ->setData($object)
339 ->addViewTransformer($failingTransformer)
340 ->setCompound(true)
341 ->setDataMapper($this->getDataMapper())
342 ->add(
343 $this->getBuilder('child')
344 ->addViewTransformer($failingTransformer)
345 )
346 ->getForm();
347
348 // Launch transformer
349 $form->submit(array('child' => 'foo'));
350
351 $context->expects($this->never())
352 ->method('addViolation');
353 $context->expects($this->never())
354 ->method('addViolationAt');
355
356 $this->validator->initialize($context);
357 $this->validator->validate($form, new Form());
358 }
359
360 public function testHandleCallbackValidationGroups()
361 {
362 $context = $this->getMockExecutionContext();
363 $object = $this->getMock('\stdClass');
364 $options = array('validation_groups' => array($this, 'getValidationGroups'));
365 $form = $this->getBuilder('name', '\stdClass', $options)
366 ->setData($object)
367 ->getForm();
368
369 $context->expects($this->at(0))
370 ->method('validate')
371 ->with($object, 'data', 'group1', true);
372 $context->expects($this->at(1))
373 ->method('validate')
374 ->with($object, 'data', 'group2', true);
375
376 $this->validator->initialize($context);
377 $this->validator->validate($form, new Form());
378 }
379
380 public function testDontExecuteFunctionNames()
381 {
382 $context = $this->getMockExecutionContext();
383 $object = $this->getMock('\stdClass');
384 $options = array('validation_groups' => 'header');
385 $form = $this->getBuilder('name', '\stdClass', $options)
386 ->setData($object)
387 ->getForm();
388
389 $context->expects($this->once())
390 ->method('validate')
391 ->with($object, 'data', 'header', true);
392
393 $this->validator->initialize($context);
394 $this->validator->validate($form, new Form());
395 }
396
397 public function testHandleClosureValidationGroups()
398 {
399 $context = $this->getMockExecutionContext();
400 $object = $this->getMock('\stdClass');
401 $options = array('validation_groups' => function(FormInterface $form){
402 return array('group1', 'group2');
403 });
404 $form = $this->getBuilder('name', '\stdClass', $options)
405 ->setData($object)
406 ->getForm();
407
408 $context->expects($this->at(0))
409 ->method('validate')
410 ->with($object, 'data', 'group1', true);
411 $context->expects($this->at(1))
412 ->method('validate')
413 ->with($object, 'data', 'group2', true);
414
415 $this->validator->initialize($context);
416 $this->validator->validate($form, new Form());
417 }
418
419 public function testUseValidationGroupOfClickedButton()
420 {
421 $context = $this->getMockExecutionContext();
422 $object = $this->getMock('\stdClass');
423
424 $parent = $this->getBuilder('parent', null, array('cascade_validation' => true))
425 ->setCompound(true)
426 ->setDataMapper($this->getDataMapper())
427 ->getForm();
428 $form = $this->getForm('name', '\stdClass', array(
429 'validation_groups' => 'form_group',
430 ));
431
432 $parent->add($form);
433 $parent->add($this->getClickedSubmitButton('submit', array(
434 'validation_groups' => 'button_group',
435 )));
436
437 $form->setData($object);
438
439 $context->expects($this->once())
440 ->method('validate')
441 ->with($object, 'data', 'button_group', true);
442
443 $this->validator->initialize($context);
444 $this->validator->validate($form, new Form());
445 }
446
447 public function testDontUseValidationGroupOfUnclickedButton()
448 {
449 $context = $this->getMockExecutionContext();
450 $object = $this->getMock('\stdClass');
451
452 $parent = $this->getBuilder('parent', null, array('cascade_validation' => true))
453 ->setCompound(true)
454 ->setDataMapper($this->getDataMapper())
455 ->getForm();
456 $form = $this->getForm('name', '\stdClass', array(
457 'validation_groups' => 'form_group',
458 ));
459
460 $parent->add($form);
461 $parent->add($this->getSubmitButton('submit', array(
462 'validation_groups' => 'button_group',
463 )));
464
465 $form->setData($object);
466
467 $context->expects($this->once())
468 ->method('validate')
469 ->with($object, 'data', 'form_group', true);
470
471 $this->validator->initialize($context);
472 $this->validator->validate($form, new Form());
473 }
474
475 public function testUseInheritedValidationGroup()
476 {
477 $context = $this->getMockExecutionContext();
478 $object = $this->getMock('\stdClass');
479
480 $parentOptions = array(
481 'validation_groups' => 'group',
482 'cascade_validation' => true,
483 );
484 $parent = $this->getBuilder('parent', null, $parentOptions)
485 ->setCompound(true)
486 ->setDataMapper($this->getDataMapper())
487 ->getForm();
488 $form = $this->getBuilder('name', '\stdClass')->getForm();
489 $parent->add($form);
490
491 $form->setData($object);
492
493 $context->expects($this->once())
494 ->method('validate')
495 ->with($object, 'data', 'group', true);
496
497 $this->validator->initialize($context);
498 $this->validator->validate($form, new Form());
499 }
500
501 public function testUseInheritedCallbackValidationGroup()
502 {
503 $context = $this->getMockExecutionContext();
504 $object = $this->getMock('\stdClass');
505
506 $parentOptions = array(
507 'validation_groups' => array($this, 'getValidationGroups'),
508 'cascade_validation' => true,
509 );
510 $parent = $this->getBuilder('parent', null, $parentOptions)
511 ->setCompound(true)
512 ->setDataMapper($this->getDataMapper())
513 ->getForm();
514 $form = $this->getBuilder('name', '\stdClass')->getForm();
515 $parent->add($form);
516
517 $form->setData($object);
518
519 $context->expects($this->at(0))
520 ->method('validate')
521 ->with($object, 'data', 'group1', true);
522 $context->expects($this->at(1))
523 ->method('validate')
524 ->with($object, 'data', 'group2', true);
525
526 $this->validator->initialize($context);
527 $this->validator->validate($form, new Form());
528 }
529
530 public function testUseInheritedClosureValidationGroup()
531 {
532 $context = $this->getMockExecutionContext();
533 $object = $this->getMock('\stdClass');
534
535 $parentOptions = array(
536 'validation_groups' => function(FormInterface $form){
537 return array('group1', 'group2');
538 },
539 'cascade_validation' => true,
540 );
541 $parent = $this->getBuilder('parent', null, $parentOptions)
542 ->setCompound(true)
543 ->setDataMapper($this->getDataMapper())
544 ->getForm();
545 $form = $this->getBuilder('name', '\stdClass')->getForm();
546 $parent->add($form);
547
548 $form->setData($object);
549
550 $context->expects($this->at(0))
551 ->method('validate')
552 ->with($object, 'data', 'group1', true);
553 $context->expects($this->at(1))
554 ->method('validate')
555 ->with($object, 'data', 'group2', true);
556
557 $this->validator->initialize($context);
558 $this->validator->validate($form, new Form());
559 }
560
561 public function testAppendPropertyPath()
562 {
563 $context = $this->getMockExecutionContext();
564 $object = $this->getMock('\stdClass');
565 $form = $this->getBuilder('name', '\stdClass')
566 ->setData($object)
567 ->getForm();
568
569 $context->expects($this->once())
570 ->method('validate')
571 ->with($object, 'data', 'Default', true);
572
573 $this->validator->initialize($context);
574 $this->validator->validate($form, new Form());
575 }
576
577 public function testDontWalkScalars()
578 {
579 $context = $this->getMockExecutionContext();
580
581 $form = $this->getBuilder()
582 ->setData('scalar')
583 ->getForm();
584
585 $context->expects($this->never())
586 ->method('validate');
587
588 $this->validator->initialize($context);
589 $this->validator->validate($form, new Form());
590 }
591
592 public function testViolationIfExtraData()
593 {
594 $context = $this->getMockExecutionContext();
595
596 $form = $this->getBuilder('parent', null, array('extra_fields_message' => 'Extra!'))
597 ->setCompound(true)
598 ->setDataMapper($this->getDataMapper())
599 ->add($this->getBuilder('child'))
600 ->getForm();
601
602 $form->submit(array('foo' => 'bar'));
603
604 $context->expects($this->once())
605 ->method('addViolation')
606 ->with(
607 'Extra!',
608 array('{{ extra_fields }}' => 'foo'),
609 array('foo' => 'bar')
610 );
611 $context->expects($this->never())
612 ->method('addViolationAt');
613
614 $this->validator->initialize($context);
615 $this->validator->validate($form, new Form());
616 }
617
618 /**
619 * @dataProvider getPostMaxSizeFixtures
620 */
621 public function testPostMaxSizeViolation($contentLength, $iniMax, $nbViolation, array $params = array())
622 {
623 $this->serverParams->expects($this->once())
624 ->method('getContentLength')
625 ->will($this->returnValue($contentLength));
626 $this->serverParams->expects($this->any())
627 ->method('getNormalizedIniPostMaxSize')
628 ->will($this->returnValue($iniMax));
629
630 $context = $this->getMockExecutionContext();
631 $options = array('post_max_size_message' => 'Max {{ max }}!');
632 $form = $this->getBuilder('name', null, $options)->getForm();
633
634 for ($i = 0; $i < $nbViolation; ++$i) {
635 if (0 === $i && count($params) > 0) {
636 $context->expects($this->at($i))
637 ->method('addViolation')
638 ->with($options['post_max_size_message'], $params);
639 } else {
640 $context->expects($this->at($i))
641 ->method('addViolation');
642 }
643 }
644
645 $context->expects($this->never())
646 ->method('addViolationAt');
647
648 $this->validator->initialize($context);
649 $this->validator->validate($form, new Form());
650 }
651
652 public function getPostMaxSizeFixtures()
653 {
654 return array(
655 array(pow(1024, 3) + 1, '1G', 1, array('{{ max }}' => '1G')),
656 array(pow(1024, 3), '1G', 0),
657 array(pow(1024, 2) + 1, '1M', 1, array('{{ max }}' => '1M')),
658 array(pow(1024, 2), '1M', 0),
659 array(1024 + 1, '1K', 1, array('{{ max }}' => '1K')),
660 array(1024, '1K', 0),
661 array(null, '1K', 0),
662 array(1024, '', 0),
663 array(1024, 0, 0),
664 );
665 }
666
667 public function testNoViolationIfNotRoot()
668 {
669 $this->serverParams->expects($this->once())
670 ->method('getContentLength')
671 ->will($this->returnValue(1025));
672 $this->serverParams->expects($this->never())
673 ->method('getNormalizedIniPostMaxSize');
674
675 $context = $this->getMockExecutionContext();
676 $parent = $this->getBuilder()
677 ->setCompound(true)
678 ->setDataMapper($this->getDataMapper())
679 ->getForm();
680 $form = $this->getForm();
681 $parent->add($form);
682
683 $context->expects($this->never())
684 ->method('addViolation');
685 $context->expects($this->never())
686 ->method('addViolationAt');
687
688 $this->validator->initialize($context);
689 $this->validator->validate($form, new Form());
690 }
691
692 /**
693 * Access has to be public, as this method is called via callback array
694 * in {@link testValidateFormDataCanHandleCallbackValidationGroups()}
695 * and {@link testValidateFormDataUsesInheritedCallbackValidationGroup()}
696 */
697 public function getValidationGroups(FormInterface $form)
698 {
699 return array('group1', 'group2');
700 }
701
702 private function getMockExecutionContext()
703 {
704 return $this->getMock('Symfony\Component\Validator\ExecutionContextInterface');
705 }
706
707 /**
708 * @param string $name
709 * @param string $dataClass
710 * @param array $options
711 *
712 * @return FormBuilder
713 */
714 private function getBuilder($name = 'name', $dataClass = null, array $options = array())
715 {
716 $options = array_replace(array(
717 'constraints' => array(),
718 'invalid_message_parameters' => array(),
719 ), $options);
720
721 return new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory, $options);
722 }
723
724 private function getForm($name = 'name', $dataClass = null, array $options = array())
725 {
726 return $this->getBuilder($name, $dataClass, $options)->getForm();
727 }
728
729 private function getSubmitButton($name = 'name', array $options = array())
730 {
731 $builder = new SubmitButtonBuilder($name, $options);
732
733 return $builder->getForm();
734 }
735
736 private function getClickedSubmitButton($name = 'name', array $options = array())
737 {
738 return $this->getSubmitButton($name, $options)->submit('');
739 }
740
741 /**
742 * @return \PHPUnit_Framework_MockObject_MockObject
743 */
744 private function getDataMapper()
745 {
746 return $this->getMock('Symfony\Component\Form\DataMapperInterface');
747 }
748}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php
new file mode 100644
index 00000000..528f9463
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php
@@ -0,0 +1,145 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Validator\EventListener;
13
14use Symfony\Component\Form\FormBuilder;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\Form\Extension\Validator\Constraints\Form;
17use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
18use Symfony\Component\PropertyAccess\PropertyPath;
19use Symfony\Component\Validator\ConstraintViolation;
20
21class ValidationListenerTest extends \PHPUnit_Framework_TestCase
22{
23 /**
24 * @var \PHPUnit_Framework_MockObject_MockObject
25 */
26 private $dispatcher;
27
28 /**
29 * @var \PHPUnit_Framework_MockObject_MockObject
30 */
31 private $factory;
32
33 /**
34 * @var \PHPUnit_Framework_MockObject_MockObject
35 */
36 private $validator;
37
38 /**
39 * @var \PHPUnit_Framework_MockObject_MockObject
40 */
41 private $violationMapper;
42
43 /**
44 * @var ValidationListener
45 */
46 private $listener;
47
48 private $message;
49
50 private $messageTemplate;
51
52 private $params;
53
54 protected function setUp()
55 {
56 if (!class_exists('Symfony\Component\EventDispatcher\Event')) {
57 $this->markTestSkipped('The "EventDispatcher" component is not available');
58 }
59
60 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
61 $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
62 $this->validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
63 $this->violationMapper = $this->getMock('Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface');
64 $this->listener = new ValidationListener($this->validator, $this->violationMapper);
65 $this->message = 'Message';
66 $this->messageTemplate = 'Message template';
67 $this->params = array('foo' => 'bar');
68 }
69
70 private function getConstraintViolation($code = null)
71 {
72 return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'prop.path', null, null, $code);
73 }
74
75 private function getBuilder($name = 'name', $propertyPath = null, $dataClass = null)
76 {
77 $builder = new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory);
78 $builder->setPropertyPath(new PropertyPath($propertyPath ?: $name));
79 $builder->setAttribute('error_mapping', array());
80 $builder->setErrorBubbling(false);
81 $builder->setMapped(true);
82
83 return $builder;
84 }
85
86 private function getForm($name = 'name', $propertyPath = null, $dataClass = null)
87 {
88 return $this->getBuilder($name, $propertyPath, $dataClass)->getForm();
89 }
90
91 private function getMockForm()
92 {
93 return $this->getMock('Symfony\Component\Form\Test\FormInterface');
94 }
95
96 // More specific mapping tests can be found in ViolationMapperTest
97 public function testMapViolation()
98 {
99 $violation = $this->getConstraintViolation();
100 $form = $this->getForm('street');
101
102 $this->validator->expects($this->once())
103 ->method('validate')
104 ->will($this->returnValue(array($violation)));
105
106 $this->violationMapper->expects($this->once())
107 ->method('mapViolation')
108 ->with($violation, $form, false);
109
110 $this->listener->validateForm(new FormEvent($form, null));
111 }
112
113 public function testMapViolationAllowsNonSyncIfInvalid()
114 {
115 $violation = $this->getConstraintViolation(Form::ERR_INVALID);
116 $form = $this->getForm('street');
117
118 $this->validator->expects($this->once())
119 ->method('validate')
120 ->will($this->returnValue(array($violation)));
121
122 $this->violationMapper->expects($this->once())
123 ->method('mapViolation')
124 // pass true now
125 ->with($violation, $form, true);
126
127 $this->listener->validateForm(new FormEvent($form, null));
128 }
129
130 public function testValidateIgnoresNonRoot()
131 {
132 $form = $this->getMockForm();
133 $form->expects($this->once())
134 ->method('isRoot')
135 ->will($this->returnValue(false));
136
137 $this->validator->expects($this->never())
138 ->method('validate');
139
140 $this->violationMapper->expects($this->never())
141 ->method('mapViolation');
142
143 $this->listener->validateForm(new FormEvent($form, null));
144 }
145}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php
new file mode 100644
index 00000000..66194105
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php
@@ -0,0 +1,85 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
13
14use Symfony\Component\Form\FormInterface;
15
16class FormTypeValidatorExtensionTest extends TypeTestCase
17{
18 public function testValidationGroupNullByDefault()
19 {
20 $form = $this->factory->create('form');
21
22 $this->assertNull($form->getConfig()->getOption('validation_groups'));
23 }
24
25 public function testValidationGroupsTransformedToArray()
26 {
27 $form = $this->factory->create('form', null, array(
28 'validation_groups' => 'group',
29 ));
30
31 $this->assertEquals(array('group'), $form->getConfig()->getOption('validation_groups'));
32 }
33
34 public function testValidationGroupsCanBeSetToArray()
35 {
36 $form = $this->factory->create('form', null, array(
37 'validation_groups' => array('group1', 'group2'),
38 ));
39
40 $this->assertEquals(array('group1', 'group2'), $form->getConfig()->getOption('validation_groups'));
41 }
42
43 public function testValidationGroupsCanBeSetToFalse()
44 {
45 $form = $this->factory->create('form', null, array(
46 'validation_groups' => false,
47 ));
48
49 $this->assertEquals(array(), $form->getConfig()->getOption('validation_groups'));
50 }
51
52 public function testValidationGroupsCanBeSetToCallback()
53 {
54 $form = $this->factory->create('form', null, array(
55 'validation_groups' => array($this, 'testValidationGroupsCanBeSetToCallback'),
56 ));
57
58 $this->assertTrue(is_callable($form->getConfig()->getOption('validation_groups')));
59 }
60
61 public function testValidationGroupsCanBeSetToClosure()
62 {
63 $form = $this->factory->create('form', null, array(
64 'validation_groups' => function(FormInterface $form){ return null; },
65 ));
66
67 $this->assertTrue(is_callable($form->getConfig()->getOption('validation_groups')));
68 }
69
70 public function testSubmitValidatesData()
71 {
72 $builder = $this->factory->createBuilder('form', null, array(
73 'validation_groups' => 'group',
74 ));
75 $builder->add('firstName', 'form');
76 $form = $builder->getForm();
77
78 $this->validator->expects($this->once())
79 ->method('validate')
80 ->with($this->equalTo($form));
81
82 // specific data is irrelevant
83 $form->submit(array());
84 }
85}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Type/TypeTestCase.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Type/TypeTestCase.php
new file mode 100644
index 00000000..d94d896a
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Type/TypeTestCase.php
@@ -0,0 +1,49 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
13
14use Symfony\Component\Form\Test\TypeTestCase as BaseTypeTestCase;
15use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
16
17abstract class TypeTestCase extends BaseTypeTestCase
18{
19 protected $validator;
20
21 protected function setUp()
22 {
23 if (!class_exists('Symfony\Component\Validator\Constraint')) {
24 $this->markTestSkipped('The "Validator" component is not available');
25 }
26
27 $this->validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
28 $metadataFactory = $this->getMock('Symfony\Component\Validator\MetadataFactoryInterface');
29 $this->validator->expects($this->once())->method('getMetadataFactory')->will($this->returnValue($metadataFactory));
30 $metadata = $this->getMockBuilder('Symfony\Component\Validator\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock();
31 $metadataFactory->expects($this->once())->method('getMetadataFor')->will($this->returnValue($metadata));
32
33 parent::setUp();
34 }
35
36 protected function tearDown()
37 {
38 $this->validator = null;
39
40 parent::tearDown();
41 }
42
43 protected function getExtensions()
44 {
45 return array_merge(parent::getExtensions(), array(
46 new ValidatorExtension($this->validator),
47 ));
48 }
49}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Util/ServerParamsTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Util/ServerParamsTest.php
new file mode 100644
index 00000000..7ad5b771
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/Util/ServerParamsTest.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Validator\Util;
13
14class ServerParamsTest extends \PHPUnit_Framework_TestCase
15{
16 /** @dataProvider getGetPostMaxSizeTestData */
17 public function testGetPostMaxSize($size, $bytes)
18 {
19 $serverParams = $this->getMock('Symfony\Component\Form\Extension\Validator\Util\ServerParams', array('getNormalizedIniPostMaxSize'));
20 $serverParams
21 ->expects($this->any())
22 ->method('getNormalizedIniPostMaxSize')
23 ->will($this->returnValue(strtoupper($size)));
24
25 $this->assertEquals($bytes, $serverParams->getPostMaxSize());
26 }
27
28 public function getGetPostMaxSizeTestData()
29 {
30 return array(
31 array('2k', 2048),
32 array('2 k', 2048),
33 array('8m', 8 * 1024 * 1024),
34 array('+2 k', 2048),
35 array('+2???k', 2048),
36 array('0x10', 16),
37 array('0xf', 15),
38 array('010', 8),
39 array('+0x10 k', 16 * 1024),
40 array('1g', 1024 * 1024 * 1024),
41 array('-1', -1),
42 array('0', 0),
43 array('2mk', 2048), // the unit must be the last char, so in this case 'k', not 'm'
44 );
45 }
46}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php
new file mode 100644
index 00000000..c802ea7e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php
@@ -0,0 +1,1481 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper;
13
14use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
15use Symfony\Component\Form\Exception\TransformationFailedException;
16use Symfony\Component\Form\CallbackTransformer;
17use Symfony\Component\Form\Form;
18use Symfony\Component\Form\FormConfigBuilder;
19use Symfony\Component\Form\FormError;
20use Symfony\Component\PropertyAccess\PropertyPath;
21use Symfony\Component\Validator\ConstraintViolation;
22
23/**
24 * @author Bernhard Schussek <bschussek@gmail.com>
25 */
26class ViolationMapperTest extends \PHPUnit_Framework_TestCase
27{
28 const LEVEL_0 = 0;
29
30 const LEVEL_1 = 1;
31
32 const LEVEL_1B = 2;
33
34 const LEVEL_2 = 3;
35
36 /**
37 * @var \PHPUnit_Framework_MockObject_MockObject
38 */
39 private $dispatcher;
40
41 /**
42 * @var ViolationMapper
43 */
44 private $mapper;
45
46 /**
47 * @var string
48 */
49 private $message;
50
51 /**
52 * @var string
53 */
54 private $messageTemplate;
55
56 /**
57 * @var array
58 */
59 private $params;
60
61 protected function setUp()
62 {
63 if (!class_exists('Symfony\Component\EventDispatcher\Event')) {
64 $this->markTestSkipped('The "EventDispatcher" component is not available');
65 }
66
67 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
68 $this->mapper = new ViolationMapper();
69 $this->message = 'Message';
70 $this->messageTemplate = 'Message template';
71 $this->params = array('foo' => 'bar');
72 }
73
74 protected function getForm($name = 'name', $propertyPath = null, $dataClass = null, $errorMapping = array(), $inheritData = false, $synchronized = true)
75 {
76 $config = new FormConfigBuilder($name, $dataClass, $this->dispatcher, array(
77 'error_mapping' => $errorMapping,
78 ));
79 $config->setMapped(true);
80 $config->setInheritData($inheritData);
81 $config->setPropertyPath($propertyPath);
82 $config->setCompound(true);
83 $config->setDataMapper($this->getDataMapper());
84
85 if (!$synchronized) {
86 $config->addViewTransformer(new CallbackTransformer(
87 function ($normData) { return $normData; },
88 function () { throw new TransformationFailedException(); }
89 ));
90 }
91
92 return new Form($config);
93 }
94
95 /**
96 * @return \PHPUnit_Framework_MockObject_MockObject
97 */
98 private function getDataMapper()
99 {
100 return $this->getMock('Symfony\Component\Form\DataMapperInterface');
101 }
102
103 /**
104 * @param $propertyPath
105 *
106 * @return ConstraintViolation
107 */
108 protected function getConstraintViolation($propertyPath)
109 {
110 return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, $propertyPath, null);
111 }
112
113 /**
114 * @return FormError
115 */
116 protected function getFormError()
117 {
118 return new FormError($this->message, $this->messageTemplate, $this->params);
119 }
120
121 public function testMapToFormInheritingParentDataIfDataDoesNotMatch()
122 {
123 $violation = $this->getConstraintViolation('children[address].data.foo');
124 $parent = $this->getForm('parent');
125 $child = $this->getForm('address', 'address', null, array(), true);
126 $grandChild = $this->getForm('street');
127
128 $parent->add($child);
129 $child->add($grandChild);
130
131 $this->mapper->mapViolation($violation, $parent);
132
133 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
134 $this->assertEquals(array($this->getFormError()), $child->getErrors(), $child->getName().' should have an error, but has none');
135 $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
136 }
137
138 public function testFollowDotRules()
139 {
140 $violation = $this->getConstraintViolation('data.foo');
141 $parent = $this->getForm('parent', null, null, array(
142 'foo' => 'address',
143 ));
144 $child = $this->getForm('address', null, null, array(
145 '.' => 'street',
146 ));
147 $grandChild = $this->getForm('street', null, null, array(
148 '.' => 'name',
149 ));
150 $grandGrandChild = $this->getForm('name');
151
152 $parent->add($child);
153 $child->add($grandChild);
154 $grandChild->add($grandGrandChild);
155
156 $this->mapper->mapViolation($violation, $parent);
157
158 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
159 $this->assertCount(0, $child->getErrors(), $child->getName().' should not have an error, but has one');
160 $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
161 $this->assertEquals(array($this->getFormError()), $grandGrandChild->getErrors(), $grandGrandChild->getName().' should have an error, but has none');
162 }
163
164 public function testAbortMappingIfNotSynchronized()
165 {
166 $violation = $this->getConstraintViolation('children[address].data.street');
167 $parent = $this->getForm('parent');
168 $child = $this->getForm('address', 'address', null, array(), false, false);
169 // even though "street" is synchronized, it should not have any errors
170 // due to its parent not being synchronized
171 $grandChild = $this->getForm('street' , 'street');
172
173 $parent->add($child);
174 $child->add($grandChild);
175
176 // submit to invoke the transformer and mark the form unsynchronized
177 $parent->submit(array());
178
179 $this->mapper->mapViolation($violation, $parent);
180
181 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
182 $this->assertCount(0, $child->getErrors(), $child->getName().' should not have an error, but has one');
183 $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
184 }
185
186 public function testAbortDotRuleMappingIfNotSynchronized()
187 {
188 $violation = $this->getConstraintViolation('data.address');
189 $parent = $this->getForm('parent');
190 $child = $this->getForm('address', 'address', null, array(
191 '.' => 'street',
192 ), false, false);
193 // even though "street" is synchronized, it should not have any errors
194 // due to its parent not being synchronized
195 $grandChild = $this->getForm('street');
196
197 $parent->add($child);
198 $child->add($grandChild);
199
200 // submit to invoke the transformer and mark the form unsynchronized
201 $parent->submit(array());
202
203 $this->mapper->mapViolation($violation, $parent);
204
205 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
206 $this->assertCount(0, $child->getErrors(), $child->getName().' should not have an error, but has one');
207 $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
208 }
209
210 public function provideDefaultTests()
211 {
212 // The mapping must be deterministic! If a child has the property path "[street]",
213 // "data[street]" should be mapped, but "data.street" should not!
214 return array(
215 // mapping target, child name, its property path, grand child name, its property path, violation path
216 array(self::LEVEL_0, 'address', 'address', 'street', 'street', ''),
217 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data'),
218
219 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].children[street].data'),
220 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].children[street].data.prop'),
221 array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data'),
222 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].data.street'),
223 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].data.street.prop'),
224 array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data[street]'),
225 array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data[street].prop'),
226 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'data.address.street'),
227 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'data.address.street.prop'),
228 array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'data.address[street]'),
229 array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'data.address[street].prop'),
230 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address].street'),
231 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address].street.prop'),
232 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address][street]'),
233 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address][street].prop'),
234
235 array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'children[address].children[street].data'),
236 array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'children[address].children[street].data.prop'),
237 array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address].data'),
238 array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address].data.street'),
239 array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address].data.street.prop'),
240 array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
241 array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'children[address].data[street].prop'),
242 array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'data.address.street'),
243 array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'data.address.street.prop'),
244 array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'data.address[street]'),
245 array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'data.address[street].prop'),
246 array(self::LEVEL_0, 'address', 'address', 'street', '[street]', 'data[address].street'),
247 array(self::LEVEL_0, 'address', 'address', 'street', '[street]', 'data[address].street.prop'),
248 array(self::LEVEL_0, 'address', 'address', 'street', '[street]', 'data[address][street]'),
249 array(self::LEVEL_0, 'address', 'address', 'street', '[street]', 'data[address][street].prop'),
250
251 array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'children[address].children[street].data'),
252 array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'children[address].children[street].data.prop'),
253 array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address].data'),
254 array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'children[address].data.street'),
255 array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'children[address].data.street.prop'),
256 array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
257 array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address].data[street].prop'),
258 array(self::LEVEL_0, 'address', '[address]', 'street', 'street', 'data.address.street'),
259 array(self::LEVEL_0, 'address', '[address]', 'street', 'street', 'data.address.street.prop'),
260 array(self::LEVEL_0, 'address', '[address]', 'street', 'street', 'data.address[street]'),
261 array(self::LEVEL_0, 'address', '[address]', 'street', 'street', 'data.address[street].prop'),
262 array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'data[address].street'),
263 array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'data[address].street.prop'),
264 array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'data[address][street]'),
265 array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'data[address][street].prop'),
266
267 array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'children[address].children[street].data'),
268 array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'children[address].children[street].data.prop'),
269 array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address].data'),
270 array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
271 array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address].data.street.prop'),
272 array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
273 array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'children[address].data[street].prop'),
274 array(self::LEVEL_0, 'address', '[address]', 'street', '[street]', 'data.address.street'),
275 array(self::LEVEL_0, 'address', '[address]', 'street', '[street]', 'data.address.street.prop'),
276 array(self::LEVEL_0, 'address', '[address]', 'street', '[street]', 'data.address[street]'),
277 array(self::LEVEL_0, 'address', '[address]', 'street', '[street]', 'data.address[street].prop'),
278 array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'data[address].street'),
279 array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'data[address].street.prop'),
280 array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'data[address][street]'),
281 array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'data[address][street].prop'),
282
283 array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'children[address].children[street].data'),
284 array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'children[address].children[street].data.prop'),
285 array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'children[address].data'),
286 array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'children[address].data.street'),
287 array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'children[address].data.street.prop'),
288 array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'children[address].data[street]'),
289 array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'children[address].data[street].prop'),
290 array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'data.person.address.street'),
291 array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'data.person.address.street.prop'),
292 array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'data.person.address[street]'),
293 array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'data.person.address[street].prop'),
294 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.person[address].street'),
295 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.person[address].street.prop'),
296 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.person[address][street]'),
297 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.person[address][street].prop'),
298 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person].address.street'),
299 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person].address.street.prop'),
300 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person].address[street]'),
301 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person].address[street].prop'),
302 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person][address].street'),
303 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person][address].street.prop'),
304 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person][address][street]'),
305 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person][address][street].prop'),
306
307 array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'children[address].children[street].data'),
308 array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'children[address].children[street].data.prop'),
309 array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'children[address].data'),
310 array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'children[address].data.street'),
311 array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'children[address].data.street.prop'),
312 array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'children[address].data[street]'),
313 array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'children[address].data[street].prop'),
314 array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'data.person.address.street'),
315 array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'data.person.address.street.prop'),
316 array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'data.person.address[street]'),
317 array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'data.person.address[street].prop'),
318 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data.person[address].street'),
319 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data.person[address].street.prop'),
320 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data.person[address][street]'),
321 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data.person[address][street].prop'),
322 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person].address.street'),
323 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person].address.street.prop'),
324 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person].address[street]'),
325 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person].address[street].prop'),
326 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person][address].street'),
327 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person][address].street.prop'),
328 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person][address][street]'),
329 array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person][address][street].prop'),
330
331 array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'children[address].children[street].data'),
332 array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'children[address].children[street].data.prop'),
333 array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'children[address].data'),
334 array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'children[address].data.street'),
335 array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'children[address].data.street.prop'),
336 array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'children[address].data[street]'),
337 array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'children[address].data[street].prop'),
338 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data.person.address.street'),
339 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data.person.address.street.prop'),
340 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data.person.address[street]'),
341 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data.person.address[street].prop'),
342 array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'data.person[address].street'),
343 array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'data.person[address].street.prop'),
344 array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'data.person[address][street]'),
345 array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'data.person[address][street].prop'),
346 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person].address.street'),
347 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person].address.street.prop'),
348 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person].address[street]'),
349 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person].address[street].prop'),
350 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person][address].street'),
351 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person][address].street.prop'),
352 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person][address][street]'),
353 array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person][address][street].prop'),
354
355 array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'children[address].children[street].data'),
356 array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'children[address].children[street].data.prop'),
357 array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'children[address].data'),
358 array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'children[address].data.street'),
359 array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'children[address].data.street.prop'),
360 array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'children[address].data[street]'),
361 array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'children[address].data[street].prop'),
362 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data.person.address.street'),
363 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data.person.address.street.prop'),
364 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data.person.address[street]'),
365 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data.person.address[street].prop'),
366 array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'data.person[address].street'),
367 array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'data.person[address].street.prop'),
368 array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'data.person[address][street]'),
369 array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'data.person[address][street].prop'),
370 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person].address.street'),
371 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person].address.street.prop'),
372 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person].address[street]'),
373 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person].address[street].prop'),
374 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person][address].street'),
375 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person][address].street.prop'),
376 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person][address][street]'),
377 array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person][address][street].prop'),
378
379 array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'children[address].children[street].data'),
380 array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'children[address].children[street].data.prop'),
381 array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'children[address].data'),
382 array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'children[address].data.street'),
383 array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'children[address].data.street.prop'),
384 array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'children[address].data[street]'),
385 array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'children[address].data[street].prop'),
386 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person.address.street'),
387 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person.address.street.prop'),
388 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person.address[street]'),
389 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person.address[street].prop'),
390 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person[address].street'),
391 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person[address].street.prop'),
392 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person[address][street]'),
393 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person[address][street].prop'),
394 array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'data[person].address.street'),
395 array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'data[person].address.street.prop'),
396 array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'data[person].address[street]'),
397 array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'data[person].address[street].prop'),
398 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data[person][address].street'),
399 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data[person][address].street.prop'),
400 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data[person][address][street]'),
401 array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data[person][address][street].prop'),
402
403 array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'children[address].children[street].data'),
404 array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'children[address].children[street].data.prop'),
405 array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'children[address].data'),
406 array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'children[address].data.street'),
407 array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'children[address].data.street.prop'),
408 array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'children[address].data[street]'),
409 array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'children[address].data[street].prop'),
410 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person.address.street'),
411 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person.address.street.prop'),
412 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person.address[street]'),
413 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person.address[street].prop'),
414 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person[address].street'),
415 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person[address].street.prop'),
416 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person[address][street]'),
417 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person[address][street].prop'),
418 array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'data[person].address.street'),
419 array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'data[person].address.street.prop'),
420 array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'data[person].address[street]'),
421 array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'data[person].address[street].prop'),
422 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data[person][address].street'),
423 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data[person][address].street.prop'),
424 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data[person][address][street]'),
425 array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data[person][address][street].prop'),
426
427 array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'children[address].children[street].data'),
428 array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'children[address].children[street].data.prop'),
429 array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'children[address]'),
430 array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'children[address].data'),
431 array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'children[address].data.street'),
432 array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'children[address].data.street.prop'),
433 array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'children[address].data[street]'),
434 array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'children[address].data[street].prop'),
435 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person.address.street'),
436 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person.address.street.prop'),
437 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person.address[street]'),
438 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person.address[street].prop'),
439 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person[address].street'),
440 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person[address].street.prop'),
441 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person[address][street]'),
442 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person[address][street].prop'),
443 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data[person].address.street'),
444 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data[person].address.street.prop'),
445 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data[person].address[street]'),
446 array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data[person].address[street].prop'),
447 array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'data[person][address].street'),
448 array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'data[person][address].street.prop'),
449 array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'data[person][address][street]'),
450 array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'data[person][address][street].prop'),
451
452 array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'children[address].children[street].data'),
453 array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'children[address].children[street].data.prop'),
454 array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'children[address].data'),
455 array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'children[address].data.street'),
456 array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'children[address].data.street.prop'),
457 array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'children[address].data[street]'),
458 array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'children[address].data[street].prop'),
459 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person.address.street'),
460 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person.address.street.prop'),
461 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person.address[street]'),
462 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person.address[street].prop'),
463 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person[address].street'),
464 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person[address].street.prop'),
465 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person[address][street]'),
466 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person[address][street].prop'),
467 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data[person].address.street'),
468 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data[person].address.street.prop'),
469 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data[person].address[street]'),
470 array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data[person].address[street].prop'),
471 array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'data[person][address].street'),
472 array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'data[person][address].street.prop'),
473 array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'data[person][address][street]'),
474 array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'data[person][address][street].prop'),
475
476 array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'children[address].children[street].data'),
477 array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'children[address].children[street].data.prop'),
478 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data'),
479 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data.office'),
480 array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'children[address].data.office.street'),
481 array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'children[address].data.office.street.prop'),
482 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data.office[street]'),
483 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data.office[street].prop'),
484 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office]'),
485 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office].street'),
486 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office].street.prop'),
487 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office][street]'),
488 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office][street].prop'),
489 array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'data.address.office.street'),
490 array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'data.address.office.street.prop'),
491 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address.office[street]'),
492 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address.office[street].prop'),
493 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address[office].street'),
494 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address[office].street.prop'),
495 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address[office][street]'),
496 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address[office][street].prop'),
497 array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address].office.street'),
498 array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address].office.street.prop'),
499 array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address].office[street]'),
500 array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address].office[street].prop'),
501 array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address][office].street'),
502 array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address][office].street.prop'),
503 array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address][office][street]'),
504 array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address][office][street].prop'),
505
506 array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'children[address].children[street].data'),
507 array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'children[address].children[street].data.prop'),
508 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data'),
509 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data.office'),
510 array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'children[address].data.office.street'),
511 array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'children[address].data.office.street.prop'),
512 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data.office[street]'),
513 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data.office[street].prop'),
514 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office]'),
515 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office].street'),
516 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office].street.prop'),
517 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office][street]'),
518 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office][street].prop'),
519 array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address.office.street'),
520 array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address.office.street.prop'),
521 array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address.office[street]'),
522 array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address.office[street].prop'),
523 array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address[office].street'),
524 array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address[office].street.prop'),
525 array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address[office][street]'),
526 array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address[office][street].prop'),
527 array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'data[address].office.street'),
528 array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'data[address].office.street.prop'),
529 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address].office[street]'),
530 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address].office[street].prop'),
531 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address][office].street'),
532 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address][office].street.prop'),
533 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address][office][street]'),
534 array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address][office][street].prop'),
535
536 array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'children[address].children[street].data'),
537 array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'children[address].children[street].data.prop'),
538 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data'),
539 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data.office'),
540 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data.office.street'),
541 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data.office.street.prop'),
542 array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'children[address].data.office[street]'),
543 array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'children[address].data.office[street].prop'),
544 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office]'),
545 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office].street'),
546 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office].street.prop'),
547 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office][street]'),
548 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office][street].prop'),
549 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address.office.street'),
550 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address.office.street.prop'),
551 array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'data.address.office[street]'),
552 array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'data.address.office[street].prop'),
553 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address[office].street'),
554 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address[office].street.prop'),
555 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address[office][street]'),
556 array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address[office][street].prop'),
557 array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address].office.street'),
558 array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address].office.street.prop'),
559 array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address].office[street]'),
560 array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address].office[street].prop'),
561 array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address][office].street'),
562 array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address][office].street.prop'),
563 array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address][office][street]'),
564 array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address][office][street].prop'),
565
566 array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'children[address].children[street].data'),
567 array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'children[address].children[street].data.prop'),
568 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data.office.street'),
569 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data.office.street.prop'),
570 array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'children[address].data.office[street]'),
571 array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'children[address].data.office[street].prop'),
572 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office]'),
573 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office].street'),
574 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office].street.prop'),
575 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office][street]'),
576 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office][street].prop'),
577 array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address.office.street'),
578 array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address.office.street.prop'),
579 array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address.office[street]'),
580 array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address.office[street].prop'),
581 array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address[office].street'),
582 array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address[office].street.prop'),
583 array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address[office][street]'),
584 array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address[office][street].prop'),
585 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address].office.street'),
586 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address].office.street.prop'),
587 array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'data[address].office[street]'),
588 array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'data[address].office[street].prop'),
589 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address][office].street'),
590 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address][office].street.prop'),
591 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address][office][street]'),
592 array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address][office][street].prop'),
593
594 array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'children[address].children[street].data'),
595 array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'children[address].children[street].data.prop'),
596 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data'),
597 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office'),
598 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office.street'),
599 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office.street.prop'),
600 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office[street]'),
601 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office[street].prop'),
602 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data[office]'),
603 array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'children[address].data[office].street'),
604 array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'children[address].data[office].street.prop'),
605 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data[office][street]'),
606 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data[office][street].prop'),
607 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address.office.street'),
608 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address.office.street.prop'),
609 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address.office[street]'),
610 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address.office[street].prop'),
611 array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'data.address[office].street'),
612 array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'data.address[office].street.prop'),
613 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address[office][street]'),
614 array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address[office][street].prop'),
615 array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address].office.street'),
616 array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address].office.street.prop'),
617 array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address].office[street]'),
618 array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address].office[street].prop'),
619 array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address][office].street'),
620 array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address][office].street.prop'),
621 array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address][office][street]'),
622 array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address][office][street].prop'),
623
624 array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'children[address].children[street].data'),
625 array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'children[address].children[street].data.prop'),
626 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data'),
627 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office'),
628 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office.street'),
629 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office.street.prop'),
630 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office[street]'),
631 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office[street].prop'),
632 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data[office]'),
633 array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'children[address].data[office].street'),
634 array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'children[address].data[office].street.prop'),
635 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data[office][street]'),
636 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data[office][street].prop'),
637 array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address.office.street'),
638 array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address.office.street.prop'),
639 array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address.office[street]'),
640 array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address.office[street].prop'),
641 array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address[office].street'),
642 array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address[office].street.prop'),
643 array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address[office][street]'),
644 array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address[office][street].prop'),
645 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address].office.street'),
646 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address].office.street.prop'),
647 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address].office[street]'),
648 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address].office[street].prop'),
649 array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'data[address][office].street'),
650 array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'data[address][office].street.prop'),
651 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address][office][street]'),
652 array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address][office][street].prop'),
653
654 array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'children[address].children[street].data'),
655 array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'children[address].children[street].data.prop'),
656 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data'),
657 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office'),
658 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office.street'),
659 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office.street.prop'),
660 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office[street]'),
661 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office[street].prop'),
662 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data[office]'),
663 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data[office].street'),
664 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data[office].street.prop'),
665 array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'children[address].data[office][street]'),
666 array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'children[address].data[office][street].prop'),
667 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address.office.street'),
668 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address.office.street.prop'),
669 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address.office[street]'),
670 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address.office[street].prop'),
671 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address[office].street'),
672 array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address[office].street.prop'),
673 array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'data.address[office][street]'),
674 array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'data.address[office][street].prop'),
675 array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address].office.street'),
676 array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address].office.street.prop'),
677 array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address].office[street]'),
678 array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address].office[street].prop'),
679 array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address][office].street'),
680 array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address][office].street.prop'),
681 array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address][office][street]'),
682 array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address][office][street].prop'),
683
684 array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'children[address].children[street].data'),
685 array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'children[address].children[street].data.prop'),
686 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data'),
687 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office'),
688 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office.street'),
689 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office.street.prop'),
690 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office[street]'),
691 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office[street].prop'),
692 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office]'),
693 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office].street'),
694 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office].street.prop'),
695 array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office][street]'),
696 array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office][street].prop'),
697 array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address.office.street'),
698 array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address.office.street.prop'),
699 array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address.office[street]'),
700 array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address.office[street].prop'),
701 array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address[office].street'),
702 array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address[office].street.prop'),
703 array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address[office][street]'),
704 array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address[office][street].prop'),
705 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address].office.street'),
706 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address].office.street.prop'),
707 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address].office[street]'),
708 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address].office[street].prop'),
709 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address][office].street'),
710 array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address][office].street.prop'),
711 array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'data[address][office][street]'),
712 array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'data[address][office][street].prop'),
713
714 // Edge cases which must not occur
715 array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address][street]'),
716 array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address][street].prop'),
717 array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address][street]'),
718 array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address][street].prop'),
719 array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address][street]'),
720 array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address][street].prop'),
721 array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address][street]'),
722 array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address][street].prop'),
723
724 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'children[person].children[address].children[street]'),
725 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'children[person].children[address].data.street'),
726 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'children[person].data.address.street'),
727 array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.address.street'),
728
729 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].children[office].children[street]'),
730 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].children[office].data.street'),
731 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data.street'),
732 array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address.street'),
733 );
734 }
735
736 /**
737 * @dataProvider provideDefaultTests
738 */
739 public function testDefaultErrorMapping($target, $childName, $childPath, $grandChildName, $grandChildPath, $violationPath)
740 {
741 $violation = $this->getConstraintViolation($violationPath);
742 $parent = $this->getForm('parent');
743 $child = $this->getForm($childName, $childPath);
744 $grandChild = $this->getForm($grandChildName, $grandChildPath);
745
746 $parent->add($child);
747 $child->add($grandChild);
748
749 $this->mapper->mapViolation($violation, $parent);
750
751 if (self::LEVEL_0 === $target) {
752 $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
753 $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
754 $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
755 } elseif (self::LEVEL_1 === $target) {
756 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
757 $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
758 $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
759 } else {
760 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
761 $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
762 $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
763 }
764 }
765
766 public function provideCustomDataErrorTests()
767 {
768 return array(
769 // mapping target, error mapping, child name, its property path, grand child name, its property path, violation path
770 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo'),
771 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo.prop'),
772 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo]'),
773 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo].prop'),
774
775 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address'),
776 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address.prop'),
777 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address]'),
778 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address].prop'),
779
780 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo'),
781 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.prop'),
782 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo]'),
783 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].prop'),
784
785 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address'),
786 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address.prop'),
787 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address]'),
788 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address].prop'),
789
790 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo'),
791 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.prop'),
792 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo]'),
793 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].prop'),
794
795 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address'),
796 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address.prop'),
797 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address]'),
798 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address].prop'),
799
800 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo'),
801 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo.prop'),
802 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo]'),
803 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo].prop'),
804
805 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address'),
806 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address.prop'),
807 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address]'),
808 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address].prop'),
809
810 array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo.street'),
811 array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo.street.prop'),
812 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo[street]'),
813 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo[street].prop'),
814 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo].street'),
815 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo].street.prop'),
816 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo][street]'),
817 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo][street].prop'),
818
819 array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address.street'),
820 array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address.street.prop'),
821 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address[street]'),
822 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address[street].prop'),
823 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address].street'),
824 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address].street.prop'),
825 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address][street]'),
826 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address][street].prop'),
827
828 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.foo.street'),
829 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.foo.street.prop'),
830 array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.foo[street]'),
831 array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.foo[street].prop'),
832 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[foo].street'),
833 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[foo].street.prop'),
834 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[foo][street]'),
835 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[foo][street].prop'),
836
837 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.address.street'),
838 array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.address.street.prop'),
839 array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.address[street]'),
840 array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.address[street].prop'),
841 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[address].street'),
842 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[address].street.prop'),
843 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[address][street]'),
844 array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[address][street].prop'),
845
846 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street'),
847 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street.prop'),
848 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street]'),
849 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street].prop'),
850 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street'),
851 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street.prop'),
852 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street]'),
853 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street].prop'),
854
855 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address.street'),
856 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address.street.prop'),
857 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address[street]'),
858 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address[street].prop'),
859 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address].street'),
860 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address].street.prop'),
861 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address][street]'),
862 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address][street].prop'),
863
864 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.foo.street'),
865 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.foo.street.prop'),
866 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.foo[street]'),
867 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.foo[street].prop'),
868 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[foo].street'),
869 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[foo].street.prop'),
870 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[foo][street]'),
871 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[foo][street].prop'),
872
873 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.address.street'),
874 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.address.street.prop'),
875 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.address[street]'),
876 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.address[street].prop'),
877 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[address].street'),
878 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[address].street.prop'),
879 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[address][street]'),
880 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[address][street].prop'),
881
882 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.street'),
883 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.street.prop'),
884 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo[street]'),
885 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo[street].prop'),
886 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].street'),
887 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].street.prop'),
888 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo][street]'),
889 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo][street].prop'),
890
891 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address.street'),
892 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address.street.prop'),
893 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address[street]'),
894 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address[street].prop'),
895 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address].street'),
896 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address].street.prop'),
897 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address][street]'),
898 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address][street].prop'),
899
900 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.street'),
901 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.street.prop'),
902 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[street]'),
903 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[street].prop'),
904 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].street'),
905 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].street.prop'),
906 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][street]'),
907 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][street].prop'),
908
909 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.address.street'),
910 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.address.street.prop'),
911 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.address[street]'),
912 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.address[street].prop'),
913 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[address].street'),
914 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[address].street.prop'),
915 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[address][street]'),
916 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[address][street].prop'),
917
918 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street'),
919 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street.prop'),
920 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street]'),
921 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street].prop'),
922 array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street'),
923 array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street.prop'),
924 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street]'),
925 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street].prop'),
926
927 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address.street'),
928 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address.street.prop'),
929 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address[street]'),
930 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address[street].prop'),
931 array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address].street'),
932 array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address].street.prop'),
933 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address][street]'),
934 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address][street].prop'),
935
936 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.foo.street'),
937 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.foo.street.prop'),
938 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.foo[street]'),
939 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.foo[street].prop'),
940 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[foo].street'),
941 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[foo].street.prop'),
942 array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[foo][street]'),
943 array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[foo][street].prop'),
944
945 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.address.street'),
946 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.address.street.prop'),
947 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.address[street]'),
948 array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.address[street].prop'),
949 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[address].street'),
950 array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[address].street.prop'),
951 array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[address][street]'),
952 array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[address][street].prop'),
953
954 array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar'),
955 array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
956 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
957 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
958 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar'),
959 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
960 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
961 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
962
963 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar'),
964 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
965 array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
966 array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
967 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar'),
968 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
969 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
970 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
971
972 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar'),
973 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
974 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
975 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
976 array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar'),
977 array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
978 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
979 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
980
981 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar'),
982 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
983 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
984 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
985 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar'),
986 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
987 array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
988 array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
989
990 array(self::LEVEL_2, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street'),
991 array(self::LEVEL_2, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street.prop'),
992 array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street]'),
993 array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street].prop'),
994 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street'),
995 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street.prop'),
996 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street]'),
997 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street].prop'),
998 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street'),
999 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street.prop'),
1000 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street]'),
1001 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street].prop'),
1002 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street'),
1003 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street.prop'),
1004 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street]'),
1005 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street].prop'),
1006
1007 array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street'),
1008 array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street.prop'),
1009 array(self::LEVEL_2, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street]'),
1010 array(self::LEVEL_2, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street].prop'),
1011 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street'),
1012 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street.prop'),
1013 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street]'),
1014 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street].prop'),
1015 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street'),
1016 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street.prop'),
1017 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street]'),
1018 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street].prop'),
1019 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street'),
1020 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street.prop'),
1021 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street]'),
1022 array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street].prop'),
1023
1024 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street'),
1025 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street.prop'),
1026 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street]'),
1027 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street].prop'),
1028 array(self::LEVEL_2, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street'),
1029 array(self::LEVEL_2, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street.prop'),
1030 array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street]'),
1031 array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street].prop'),
1032 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street'),
1033 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street.prop'),
1034 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street]'),
1035 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street].prop'),
1036 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street'),
1037 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street.prop'),
1038 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street]'),
1039 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street].prop'),
1040
1041 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street'),
1042 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street.prop'),
1043 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street]'),
1044 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street].prop'),
1045 array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street'),
1046 array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street.prop'),
1047 array(self::LEVEL_2, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street]'),
1048 array(self::LEVEL_2, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street].prop'),
1049 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street'),
1050 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street.prop'),
1051 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street]'),
1052 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street].prop'),
1053 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street'),
1054 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street.prop'),
1055 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street]'),
1056 array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street].prop'),
1057
1058 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street'),
1059 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street.prop'),
1060 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street]'),
1061 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street].prop'),
1062 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street'),
1063 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street.prop'),
1064 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street]'),
1065 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street].prop'),
1066 array(self::LEVEL_2, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street'),
1067 array(self::LEVEL_2, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street.prop'),
1068 array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street]'),
1069 array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street].prop'),
1070 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street'),
1071 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street.prop'),
1072 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street]'),
1073 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street].prop'),
1074
1075 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street'),
1076 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street.prop'),
1077 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street]'),
1078 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street].prop'),
1079 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street'),
1080 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street.prop'),
1081 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street]'),
1082 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street].prop'),
1083 array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street'),
1084 array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street.prop'),
1085 array(self::LEVEL_2, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street]'),
1086 array(self::LEVEL_2, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street].prop'),
1087 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street'),
1088 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street.prop'),
1089 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street]'),
1090 array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street].prop'),
1091
1092 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street'),
1093 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street.prop'),
1094 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street]'),
1095 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street].prop'),
1096 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street'),
1097 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street.prop'),
1098 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street]'),
1099 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street].prop'),
1100 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street'),
1101 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street.prop'),
1102 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street]'),
1103 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street].prop'),
1104 array(self::LEVEL_2, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street'),
1105 array(self::LEVEL_2, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street.prop'),
1106 array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street]'),
1107 array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street].prop'),
1108
1109 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street'),
1110 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street.prop'),
1111 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street]'),
1112 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street].prop'),
1113 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street'),
1114 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street.prop'),
1115 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street]'),
1116 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street].prop'),
1117 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street'),
1118 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street.prop'),
1119 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street]'),
1120 array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street].prop'),
1121 array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street'),
1122 array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street.prop'),
1123 array(self::LEVEL_2, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street]'),
1124 array(self::LEVEL_2, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street].prop'),
1125
1126 array(self::LEVEL_2, 'foo', 'address.street', 'address', 'address', 'street', 'street', 'data.foo'),
1127 array(self::LEVEL_2, 'foo', 'address.street', 'address', 'address', 'street', 'street', 'data.foo.prop'),
1128 array(self::LEVEL_2, '[foo]', 'address.street', 'address', 'address', 'street', 'street', 'data[foo]'),
1129 array(self::LEVEL_2, '[foo]', 'address.street', 'address', 'address', 'street', 'street', 'data[foo].prop'),
1130
1131 array(self::LEVEL_2, 'foo', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo'),
1132 array(self::LEVEL_2, 'foo', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo.prop'),
1133 array(self::LEVEL_2, '[foo]', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo]'),
1134 array(self::LEVEL_2, '[foo]', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo].prop'),
1135
1136 array(self::LEVEL_2, 'foo', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo'),
1137 array(self::LEVEL_2, 'foo', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo.prop'),
1138 array(self::LEVEL_2, '[foo]', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo]'),
1139 array(self::LEVEL_2, '[foo]', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo].prop'),
1140
1141 array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', 'address', 'street', 'street', 'data.foo.bar'),
1142 array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
1143 array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
1144 array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
1145 array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', 'address', 'street', 'street', 'data[foo].bar'),
1146 array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
1147 array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
1148 array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
1149
1150 array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo.bar'),
1151 array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo.bar.prop'),
1152 array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo[bar]'),
1153 array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo[bar].prop'),
1154 array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo].bar'),
1155 array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo].bar.prop'),
1156 array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo][bar]'),
1157 array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo][bar].prop'),
1158
1159 array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo.bar'),
1160 array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo.bar.prop'),
1161 array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo[bar]'),
1162 array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo[bar].prop'),
1163 array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo].bar'),
1164 array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo].bar.prop'),
1165 array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo][bar]'),
1166 array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo][bar].prop'),
1167
1168 // Edge cases
1169 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street'),
1170 array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street.prop'),
1171 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street]'),
1172 array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street].prop'),
1173 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street'),
1174 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street.prop'),
1175 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street]'),
1176 array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street].prop'),
1177
1178 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.street'),
1179 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.street.prop'),
1180 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo[street]'),
1181 array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo[street].prop'),
1182 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].street'),
1183 array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].street.prop'),
1184 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo][street]'),
1185 array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo][street].prop'),
1186 );
1187 }
1188
1189 /**
1190 * @dataProvider provideCustomDataErrorTests
1191 */
1192 public function testCustomDataErrorMapping($target, $mapFrom, $mapTo, $childName, $childPath, $grandChildName, $grandChildPath, $violationPath)
1193 {
1194 $violation = $this->getConstraintViolation($violationPath);
1195 $parent = $this->getForm('parent', null, null, array($mapFrom => $mapTo));
1196 $child = $this->getForm($childName, $childPath);
1197 $grandChild = $this->getForm($grandChildName, $grandChildPath);
1198
1199 $parent->add($child);
1200 $child->add($grandChild);
1201
1202 // Add a field mapped to the first element of $mapFrom
1203 // to try to distract the algorithm
1204 // Only add it if we expect the error to come up on a different
1205 // level than LEVEL_0, because in this case the error would
1206 // (correctly) be mapped to the distraction field
1207 if ($target !== self::LEVEL_0) {
1208 $mapFromPath = new PropertyPath($mapFrom);
1209 $mapFromPrefix = $mapFromPath->isIndex(0)
1210 ? '['.$mapFromPath->getElement(0).']'
1211 : $mapFromPath->getElement(0);
1212 $distraction = $this->getForm('distraction', $mapFromPrefix);
1213
1214 $parent->add($distraction);
1215 }
1216
1217 $this->mapper->mapViolation($violation, $parent);
1218
1219 if ($target !== self::LEVEL_0) {
1220 $this->assertCount(0, $distraction->getErrors(), 'distraction should not have an error, but has one');
1221 }
1222
1223 if (self::LEVEL_0 === $target) {
1224 $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
1225 $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
1226 $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
1227 } elseif (self::LEVEL_1 === $target) {
1228 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
1229 $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
1230 $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
1231 } else {
1232 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
1233 $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
1234 $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
1235 }
1236 }
1237
1238 public function provideCustomFormErrorTests()
1239 {
1240 // This case is different than the data errors, because here the
1241 // left side of the mapping refers to the property path of the actual
1242 // children. In other words, a child error only works if
1243 // 1) the error actually maps to an existing child and
1244 // 2) the property path of that child (relative to the form providing
1245 // the mapping) matches the left side of the mapping
1246 return array(
1247 // mapping target, map from, map to, child name, its property path, grand child name, its property path, violation path
1248 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].children[street].data'),
1249 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].children[street].data.prop'),
1250 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data.street'),
1251 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data.street.prop'),
1252 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data[street]'),
1253 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data[street].prop'),
1254
1255 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street].data'),
1256 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street].data.prop'),
1257 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
1258 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street.prop'),
1259 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
1260 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street].prop'),
1261
1262 // Property path of the erroneous field and mapping must match exactly
1263 array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].children[street].data'),
1264 array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].children[street].data.prop'),
1265 array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data.street'),
1266 array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data.street.prop'),
1267 array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data[street]'),
1268 array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data[street].prop'),
1269
1270 array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].children[street].data'),
1271 array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].children[street].data.prop'),
1272 array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data.street'),
1273 array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data.street.prop'),
1274 array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data[street]'),
1275 array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data[street].prop'),
1276
1277 array(self::LEVEL_1, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].children[street].data'),
1278 array(self::LEVEL_1, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].children[street].data.prop'),
1279 array(self::LEVEL_2, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data.street'),
1280 array(self::LEVEL_2, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data.street.prop'),
1281 array(self::LEVEL_1, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data[street]'),
1282 array(self::LEVEL_1, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data[street].prop'),
1283
1284 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].children[street].data'),
1285 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].children[street].data.prop'),
1286 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].data.street'),
1287 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].data.street.prop'),
1288 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].data[street]'),
1289 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].data[street].prop'),
1290
1291 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street].data'),
1292 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street].data.prop'),
1293 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
1294 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street.prop'),
1295 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
1296 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street].prop'),
1297
1298 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].children[street].data'),
1299 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].children[street].data.prop'),
1300 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].data.street'),
1301 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].data.street.prop'),
1302 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].data[street]'),
1303 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].data[street].prop'),
1304
1305 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street].data'),
1306 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street].data.prop'),
1307 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
1308 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street.prop'),
1309 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
1310 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street].prop'),
1311
1312 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].children[street].data'),
1313 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].children[street].data.prop'),
1314 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].data.street'),
1315 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].data.street.prop'),
1316 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].data[street]'),
1317 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].data[street].prop'),
1318
1319 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street].data'),
1320 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street].data.prop'),
1321 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
1322 array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street.prop'),
1323 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
1324 array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street].prop'),
1325
1326 // Map to a nested child
1327 array(self::LEVEL_2, 'foo', 'address.street', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo]'),
1328 array(self::LEVEL_2, 'foo', 'address.street', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo]'),
1329 array(self::LEVEL_2, 'foo', 'address.street', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo]'),
1330 array(self::LEVEL_2, 'foo', 'address.street', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo]'),
1331
1332 // Map from a nested child
1333 array(self::LEVEL_1B, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street]'),
1334 array(self::LEVEL_1B, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
1335 array(self::LEVEL_1, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
1336 array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street]'),
1337 array(self::LEVEL_1B, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
1338 array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
1339 array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street]'),
1340 array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
1341 array(self::LEVEL_1, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
1342 array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street]'),
1343 array(self::LEVEL_1, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
1344 array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
1345
1346 array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street]'),
1347 array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
1348 array(self::LEVEL_1B, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
1349 array(self::LEVEL_1B, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street]'),
1350 array(self::LEVEL_1, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
1351 array(self::LEVEL_1B, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
1352 array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street]'),
1353 array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
1354 array(self::LEVEL_1, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
1355 array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street]'),
1356 array(self::LEVEL_1, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
1357 array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
1358
1359 array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street]'),
1360 array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
1361 array(self::LEVEL_1, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
1362 array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street]'),
1363 array(self::LEVEL_1, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
1364 array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
1365 array(self::LEVEL_1B, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street]'),
1366 array(self::LEVEL_1B, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
1367 array(self::LEVEL_1, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
1368 array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street]'),
1369 array(self::LEVEL_1B, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
1370 array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
1371
1372 array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street]'),
1373 array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
1374 array(self::LEVEL_1, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
1375 array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street]'),
1376 array(self::LEVEL_1, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
1377 array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
1378 array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street]'),
1379 array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
1380 array(self::LEVEL_1B, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
1381 array(self::LEVEL_1B, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street]'),
1382 array(self::LEVEL_1, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
1383 array(self::LEVEL_1B, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
1384 );
1385 }
1386
1387 /**
1388 * @dataProvider provideCustomFormErrorTests
1389 */
1390 public function testCustomFormErrorMapping($target, $mapFrom, $mapTo, $errorName, $errorPath, $childName, $childPath, $grandChildName, $grandChildPath, $violationPath)
1391 {
1392 $violation = $this->getConstraintViolation($violationPath);
1393 $parent = $this->getForm('parent', null, null, array($mapFrom => $mapTo));
1394 $child = $this->getForm($childName, $childPath);
1395 $grandChild = $this->getForm($grandChildName, $grandChildPath);
1396 $errorChild = $this->getForm($errorName, $errorPath);
1397
1398 $parent->add($child);
1399 $parent->add($errorChild);
1400 $child->add($grandChild);
1401
1402 $this->mapper->mapViolation($violation, $parent);
1403
1404 if (self::LEVEL_0 === $target) {
1405 $this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one');
1406 $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
1407 $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
1408 $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
1409 } elseif (self::LEVEL_1 === $target) {
1410 $this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one');
1411 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
1412 $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
1413 $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
1414 } elseif (self::LEVEL_1B === $target) {
1415 $this->assertEquals(array($this->getFormError()), $errorChild->getErrors(), $errorName.' should have an error, but has none');
1416 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
1417 $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
1418 $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
1419 } else {
1420 $this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one');
1421 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
1422 $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
1423 $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
1424 }
1425 }
1426
1427 public function provideErrorTestsForFormInheritingParentData()
1428 {
1429 return array(
1430 // mapping target, child name, its property path, grand child name, its property path, violation path
1431 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].children[street].data'),
1432 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].children[street].data.prop'),
1433 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].data.street'),
1434 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].data.street.prop'),
1435 array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data[street]'),
1436 array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data[street].prop'),
1437 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'data.street'),
1438 array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'data.street.prop'),
1439 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[street]'),
1440 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[street].prop'),
1441 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data.address.street'),
1442 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data.address.street.prop'),
1443 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data.address[street]'),
1444 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data.address[street].prop'),
1445 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address].street'),
1446 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address].street.prop'),
1447 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address][street]'),
1448 array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address][street].prop'),
1449 );
1450 }
1451
1452 /**
1453 * @dataProvider provideErrorTestsForFormInheritingParentData
1454 */
1455 public function testErrorMappingForFormInheritingParentData($target, $childName, $childPath, $grandChildName, $grandChildPath, $violationPath)
1456 {
1457 $violation = $this->getConstraintViolation($violationPath);
1458 $parent = $this->getForm('parent');
1459 $child = $this->getForm($childName, $childPath, null, array(), true);
1460 $grandChild = $this->getForm($grandChildName, $grandChildPath);
1461
1462 $parent->add($child);
1463 $child->add($grandChild);
1464
1465 $this->mapper->mapViolation($violation, $parent);
1466
1467 if (self::LEVEL_0 === $target) {
1468 $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
1469 $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
1470 $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
1471 } elseif (self::LEVEL_1 === $target) {
1472 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
1473 $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
1474 $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
1475 } else {
1476 $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
1477 $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
1478 $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
1479 }
1480 }
1481}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationPathTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationPathTest.php
new file mode 100644
index 00000000..02df8f43
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationPathTest.php
@@ -0,0 +1,245 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper;
13
14use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationPath;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class ViolationPathTest extends \PHPUnit_Framework_TestCase
20{
21 public function providePaths()
22 {
23 return array(
24 array('children[address]', array(
25 array('address', true, true),
26 )),
27 array('children[address].children[street]', array(
28 array('address', true, true),
29 array('street', true, true),
30 )),
31 array('children[address][street]', array(
32 array('address', true, true),
33 ), 'children[address]'),
34 array('children[address].data', array(
35 array('address', true, true),
36 ), 'children[address]'),
37 array('children[address].data.street', array(
38 array('address', true, true),
39 array('street', false, false),
40 )),
41 array('children[address].data[street]', array(
42 array('address', true, true),
43 array('street', false, true),
44 )),
45 array('children[address].children[street].data.name', array(
46 array('address', true, true),
47 array('street', true, true),
48 array('name', false, false),
49 )),
50 array('children[address].children[street].data[name]', array(
51 array('address', true, true),
52 array('street', true, true),
53 array('name', false, true),
54 )),
55 array('data.address', array(
56 array('address', false, false),
57 )),
58 array('data[address]', array(
59 array('address', false, true),
60 )),
61 array('data.address.street', array(
62 array('address', false, false),
63 array('street', false, false),
64 )),
65 array('data[address].street', array(
66 array('address', false, true),
67 array('street', false, false),
68 )),
69 array('data.address[street]', array(
70 array('address', false, false),
71 array('street', false, true),
72 )),
73 array('data[address][street]', array(
74 array('address', false, true),
75 array('street', false, true),
76 )),
77 // A few invalid examples
78 array('data', array(), ''),
79 array('children', array(), ''),
80 array('children.address', array(), ''),
81 array('children.address[street]', array(), ''),
82 );
83 }
84
85 /**
86 * @dataProvider providePaths
87 */
88 public function testCreatePath($string, $entries, $slicedPath = null)
89 {
90 if (null === $slicedPath) {
91 $slicedPath = $string;
92 }
93
94 $path = new ViolationPath($string);
95
96 $this->assertSame($slicedPath, $path->__toString());
97 $this->assertSame(count($entries), count($path->getElements()));
98 $this->assertSame(count($entries), $path->getLength());
99
100 foreach ($entries as $index => $entry) {
101 $this->assertEquals($entry[0], $path->getElement($index));
102 $this->assertSame($entry[1], $path->mapsForm($index));
103 $this->assertSame($entry[2], $path->isIndex($index));
104 $this->assertSame(!$entry[2], $path->isProperty($index));
105 }
106 }
107
108 public function provideParents()
109 {
110 return array(
111 array('children[address]', null),
112 array('children[address].children[street]', 'children[address]'),
113 array('children[address].data.street', 'children[address]'),
114 array('children[address].data[street]', 'children[address]'),
115 array('data.address', null),
116 array('data.address.street', 'data.address'),
117 array('data.address[street]', 'data.address'),
118 array('data[address].street', 'data[address]'),
119 array('data[address][street]', 'data[address]'),
120 );
121 }
122
123 /**
124 * @dataProvider provideParents
125 */
126 public function testGetParent($violationPath, $parentPath)
127 {
128 $path = new ViolationPath($violationPath);
129 $parent = $parentPath === null ? null : new ViolationPath($parentPath);
130
131 $this->assertEquals($parent, $path->getParent());
132 }
133
134 public function testGetElement()
135 {
136 $path = new ViolationPath('children[address].data[street].name');
137
138 $this->assertEquals('street', $path->getElement(1));
139 }
140
141 /**
142 * @expectedException \OutOfBoundsException
143 */
144 public function testGetElementDoesNotAcceptInvalidIndices()
145 {
146 $path = new ViolationPath('children[address].data[street].name');
147
148 $path->getElement(3);
149 }
150
151 /**
152 * @expectedException \OutOfBoundsException
153 */
154 public function testGetElementDoesNotAcceptNegativeIndices()
155 {
156 $path = new ViolationPath('children[address].data[street].name');
157
158 $path->getElement(-1);
159 }
160
161 public function testIsProperty()
162 {
163 $path = new ViolationPath('children[address].data[street].name');
164
165 $this->assertFalse($path->isProperty(1));
166 $this->assertTrue($path->isProperty(2));
167 }
168
169 /**
170 * @expectedException \OutOfBoundsException
171 */
172 public function testIsPropertyDoesNotAcceptInvalidIndices()
173 {
174 $path = new ViolationPath('children[address].data[street].name');
175
176 $path->isProperty(3);
177 }
178
179 /**
180 * @expectedException \OutOfBoundsException
181 */
182 public function testIsPropertyDoesNotAcceptNegativeIndices()
183 {
184 $path = new ViolationPath('children[address].data[street].name');
185
186 $path->isProperty(-1);
187 }
188
189 public function testIsIndex()
190 {
191 $path = new ViolationPath('children[address].data[street].name');
192
193 $this->assertTrue($path->isIndex(1));
194 $this->assertFalse($path->isIndex(2));
195 }
196
197 /**
198 * @expectedException \OutOfBoundsException
199 */
200 public function testIsIndexDoesNotAcceptInvalidIndices()
201 {
202 $path = new ViolationPath('children[address].data[street].name');
203
204 $path->isIndex(3);
205 }
206
207 /**
208 * @expectedException \OutOfBoundsException
209 */
210 public function testIsIndexDoesNotAcceptNegativeIndices()
211 {
212 $path = new ViolationPath('children[address].data[street].name');
213
214 $path->isIndex(-1);
215 }
216
217 public function testMapsForm()
218 {
219 $path = new ViolationPath('children[address].data[street].name');
220
221 $this->assertTrue($path->mapsForm(0));
222 $this->assertFalse($path->mapsForm(1));
223 $this->assertFalse($path->mapsForm(2));
224 }
225
226 /**
227 * @expectedException \OutOfBoundsException
228 */
229 public function testMapsFormDoesNotAcceptInvalidIndices()
230 {
231 $path = new ViolationPath('children[address].data[street].name');
232
233 $path->mapsForm(3);
234 }
235
236 /**
237 * @expectedException \OutOfBoundsException
238 */
239 public function testMapsFormDoesNotAcceptNegativeIndices()
240 {
241 $path = new ViolationPath('children[address].data[street].name');
242
243 $path->mapsForm(-1);
244 }
245}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/AlternatingRowType.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/AlternatingRowType.php
new file mode 100644
index 00000000..ee7d1353
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/AlternatingRowType.php
@@ -0,0 +1,27 @@
1<?php
2
3namespace Symfony\Component\Form\Tests\Fixtures;
4
5use Symfony\Component\Form\AbstractType;
6use Symfony\Component\Form\FormEvents;
7use Symfony\Component\Form\FormEvent;
8use Symfony\Component\Form\FormBuilderInterface;
9
10class AlternatingRowType extends AbstractType
11{
12 public function buildForm(FormBuilderInterface $builder, array $options)
13 {
14 $formFactory = $builder->getFormFactory();
15
16 $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formFactory) {
17 $form = $event->getForm();
18 $type = $form->getName() % 2 === 0 ? 'text' : 'textarea';
19 $form->add('title', $type);
20 });
21 }
22
23 public function getName()
24 {
25 return 'alternating_row';
26 }
27}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/Author.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/Author.php
new file mode 100644
index 00000000..11204894
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/Author.php
@@ -0,0 +1,71 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14class Author
15{
16 public $firstName;
17 private $lastName;
18 private $australian;
19 public $child;
20 private $readPermissions;
21
22 private $privateProperty;
23
24 public function setLastName($lastName)
25 {
26 $this->lastName = $lastName;
27 }
28
29 public function getLastName()
30 {
31 return $this->lastName;
32 }
33
34 private function getPrivateGetter()
35 {
36 return 'foobar';
37 }
38
39 public function setAustralian($australian)
40 {
41 $this->australian = $australian;
42 }
43
44 public function isAustralian()
45 {
46 return $this->australian;
47 }
48
49 public function setReadPermissions($bool)
50 {
51 $this->readPermissions = $bool;
52 }
53
54 public function hasReadPermissions()
55 {
56 return $this->readPermissions;
57 }
58
59 private function isPrivateIsser()
60 {
61 return true;
62 }
63
64 public function getPrivateSetter()
65 {
66 }
67
68 private function setPrivateSetter($data)
69 {
70 }
71}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/AuthorType.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/AuthorType.php
new file mode 100644
index 00000000..147f6e48
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/AuthorType.php
@@ -0,0 +1,30 @@
1<?php
2
3namespace Symfony\Component\Form\Tests\Fixtures;
4
5use Symfony\Component\Form\AbstractType;
6use Symfony\Component\Form\FormBuilderInterface;
7use Symfony\Component\OptionsResolver\OptionsResolverInterface;
8
9class AuthorType extends AbstractType
10{
11 public function buildForm(FormBuilderInterface $builder, array $options)
12 {
13 $builder
14 ->add('firstName')
15 ->add('lastName')
16 ;
17 }
18
19 public function getName()
20 {
21 return 'author';
22 }
23
24 public function setDefaultOptions(OptionsResolverInterface $resolver)
25 {
26 $resolver->setDefaults(array(
27 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
28 ));
29 }
30}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php
new file mode 100644
index 00000000..950f677f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php
@@ -0,0 +1,70 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14/**
15 * This class is a hand written simplified version of PHP native `ArrayObject`
16 * class, to show that it behaves differently than the PHP native implementation.
17 */
18class CustomArrayObject implements \ArrayAccess, \IteratorAggregate, \Countable, \Serializable
19{
20 private $array;
21
22 public function __construct(array $array = null)
23 {
24 $this->array = $array ?: array();
25 }
26
27 public function offsetExists($offset)
28 {
29 return array_key_exists($offset, $this->array);
30 }
31
32 public function offsetGet($offset)
33 {
34 return $this->array[$offset];
35 }
36
37 public function offsetSet($offset, $value)
38 {
39 if (null === $offset) {
40 $this->array[] = $value;
41 } else {
42 $this->array[$offset] = $value;
43 }
44 }
45
46 public function offsetUnset($offset)
47 {
48 unset($this->array[$offset]);
49 }
50
51 public function getIterator()
52 {
53 return new \ArrayIterator($this->array);
54 }
55
56 public function count()
57 {
58 return count($this->array);
59 }
60
61 public function serialize()
62 {
63 return serialize($this->array);
64 }
65
66 public function unserialize($serialized)
67 {
68 $this->array = (array) unserialize((string) $serialized);
69 }
70}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FixedDataTransformer.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FixedDataTransformer.php
new file mode 100644
index 00000000..a5a31248
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FixedDataTransformer.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14use Symfony\Component\Form\DataTransformerInterface;
15use Symfony\Component\Form\Exception\RuntimeException;
16
17class FixedDataTransformer implements DataTransformerInterface
18{
19 private $mapping;
20
21 public function __construct(array $mapping)
22 {
23 $this->mapping = $mapping;
24 }
25
26 public function transform($value)
27 {
28 if (!array_key_exists($value, $this->mapping)) {
29 throw new RuntimeException(sprintf('No mapping for value "%s"', $value));
30 }
31
32 return $this->mapping[$value];
33 }
34
35 public function reverseTransform($value)
36 {
37 $result = array_search($value, $this->mapping, true);
38
39 if ($result === false) {
40 throw new RuntimeException(sprintf('No reverse mapping for value "%s"', $value));
41 }
42
43 return $result;
44 }
45}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FixedFilterListener.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FixedFilterListener.php
new file mode 100644
index 00000000..762a10b8
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FixedFilterListener.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14use Symfony\Component\Form\FormEvents;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
18class FixedFilterListener implements EventSubscriberInterface
19{
20 private $mapping;
21
22 public function __construct(array $mapping)
23 {
24 $this->mapping = array_merge(array(
25 'preSubmit' => array(),
26 'onSubmit' => array(),
27 'preSetData' => array(),
28 ), $mapping);
29 }
30
31 public function preSubmit(FormEvent $event)
32 {
33 $data = $event->getData();
34
35 if (isset($this->mapping['preSubmit'][$data])) {
36 $event->setData($this->mapping['preSubmit'][$data]);
37 }
38 }
39
40 public function onSubmit(FormEvent $event)
41 {
42 $data = $event->getData();
43
44 if (isset($this->mapping['onSubmit'][$data])) {
45 $event->setData($this->mapping['onSubmit'][$data]);
46 }
47 }
48
49 public function preSetData(FormEvent $event)
50 {
51 $data = $event->getData();
52
53 if (isset($this->mapping['preSetData'][$data])) {
54 $event->setData($this->mapping['preSetData'][$data]);
55 }
56 }
57
58 public static function getSubscribedEvents()
59 {
60 return array(
61 FormEvents::PRE_SUBMIT => 'preSubmit',
62 FormEvents::SUBMIT => 'onSubmit',
63 FormEvents::PRE_SET_DATA => 'preSetData',
64 );
65 }
66}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooSubType.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooSubType.php
new file mode 100644
index 00000000..4f7ba6d4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooSubType.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilder;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\FormFactoryInterface;
18use Symfony\Component\EventDispatcher\EventDispatcher;
19use Symfony\Component\OptionsResolver\OptionsResolverInterface;
20
21class FooSubType extends AbstractType
22{
23 public function getName()
24 {
25 return 'foo_sub_type';
26 }
27
28 public function getParent()
29 {
30 return 'foo';
31 }
32}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooSubTypeWithParentInstance.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooSubTypeWithParentInstance.php
new file mode 100644
index 00000000..468b5a32
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooSubTypeWithParentInstance.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilder;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\FormFactoryInterface;
18use Symfony\Component\EventDispatcher\EventDispatcher;
19use Symfony\Component\OptionsResolver\OptionsResolverInterface;
20
21class FooSubTypeWithParentInstance extends AbstractType
22{
23 public function getName()
24 {
25 return 'foo_sub_type_parent_instance';
26 }
27
28 public function getParent()
29 {
30 return new FooType();
31 }
32}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooType.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooType.php
new file mode 100644
index 00000000..d26d3f76
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooType.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14use Symfony\Component\Form\AbstractType;
15use Symfony\Component\Form\FormBuilder;
16use Symfony\Component\Form\FormBuilderInterface;
17use Symfony\Component\Form\FormFactoryInterface;
18use Symfony\Component\EventDispatcher\EventDispatcher;
19use Symfony\Component\OptionsResolver\OptionsResolverInterface;
20
21class FooType extends AbstractType
22{
23 public function getName()
24 {
25 return 'foo';
26 }
27
28 public function getParent()
29 {
30 return null;
31 }
32}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooTypeBarExtension.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooTypeBarExtension.php
new file mode 100644
index 00000000..c5f92e11
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooTypeBarExtension.php
@@ -0,0 +1,35 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\Form\FormBuilderInterface;
16
17class FooTypeBarExtension extends AbstractTypeExtension
18{
19 public function buildForm(FormBuilderInterface $builder, array $options)
20 {
21 $builder->setAttribute('bar', 'x');
22 }
23
24 public function getAllowedOptionValues()
25 {
26 return array(
27 'a_or_b' => array('c'),
28 );
29 }
30
31 public function getExtendedType()
32 {
33 return 'foo';
34 }
35}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooTypeBazExtension.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooTypeBazExtension.php
new file mode 100644
index 00000000..2e364754
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/FooTypeBazExtension.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14use Symfony\Component\Form\AbstractTypeExtension;
15use Symfony\Component\Form\FormBuilderInterface;
16
17class FooTypeBazExtension extends AbstractTypeExtension
18{
19 public function buildForm(FormBuilderInterface $builder, array $options)
20 {
21 $builder->setAttribute('baz', 'x');
22 }
23
24 public function getExtendedType()
25 {
26 return 'foo';
27 }
28}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/TestExtension.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/TestExtension.php
new file mode 100644
index 00000000..f9de560f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/TestExtension.php
@@ -0,0 +1,72 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Fixtures;
13
14use Symfony\Component\Form\FormTypeInterface;
15use Symfony\Component\Form\FormTypeExtensionInterface;
16use Symfony\Component\Form\FormTypeGuesserInterface;
17use Symfony\Component\Form\FormExtensionInterface;
18
19class TestExtension implements FormExtensionInterface
20{
21 private $types = array();
22
23 private $extensions = array();
24
25 private $guesser;
26
27 public function __construct(FormTypeGuesserInterface $guesser)
28 {
29 $this->guesser = $guesser;
30 }
31
32 public function addType(FormTypeInterface $type)
33 {
34 $this->types[$type->getName()] = $type;
35 }
36
37 public function getType($name)
38 {
39 return isset($this->types[$name]) ? $this->types[$name] : null;
40 }
41
42 public function hasType($name)
43 {
44 return isset($this->types[$name]);
45 }
46
47 public function addTypeExtension(FormTypeExtensionInterface $extension)
48 {
49 $type = $extension->getExtendedType();
50
51 if (!isset($this->extensions[$type])) {
52 $this->extensions[$type] = array();
53 }
54
55 $this->extensions[$type][] = $extension;
56 }
57
58 public function getTypeExtensions($name)
59 {
60 return isset($this->extensions[$name]) ? $this->extensions[$name] : array();
61 }
62
63 public function hasTypeExtensions($name)
64 {
65 return isset($this->extensions[$name]);
66 }
67
68 public function getTypeGuesser()
69 {
70 return $this->guesser;
71 }
72}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/foo b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/foo
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Fixtures/foo
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/FormBuilderTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/FormBuilderTest.php
new file mode 100644
index 00000000..e076c97e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/FormBuilderTest.php
@@ -0,0 +1,232 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\FormBuilder;
15
16class FormBuilderTest extends \PHPUnit_Framework_TestCase
17{
18 private $dispatcher;
19
20 private $factory;
21
22 private $builder;
23
24 protected function setUp()
25 {
26 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
27 $this->markTestSkipped('The "EventDispatcher" component is not available');
28 }
29
30 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
31 $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
32 $this->builder = new FormBuilder('name', null, $this->dispatcher, $this->factory);
33 }
34
35 protected function tearDown()
36 {
37 $this->dispatcher = null;
38 $this->factory = null;
39 $this->builder = null;
40 }
41
42 /**
43 * Changing the name is not allowed, otherwise the name and property path
44 * are not synchronized anymore
45 *
46 * @see FormType::buildForm
47 */
48 public function testNoSetName()
49 {
50 $this->assertFalse(method_exists($this->builder, 'setName'));
51 }
52
53 public function testAddNameNoStringAndNoInteger()
54 {
55 $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
56 $this->builder->add(true);
57 }
58
59 public function testAddTypeNoString()
60 {
61 $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
62 $this->builder->add('foo', 1234);
63 }
64
65 public function testAddWithGuessFluent()
66 {
67 $this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory);
68 $builder = $this->builder->add('foo');
69 $this->assertSame($builder, $this->builder);
70 }
71
72 public function testAddIsFluent()
73 {
74 $builder = $this->builder->add('foo', 'text', array('bar' => 'baz'));
75 $this->assertSame($builder, $this->builder);
76 }
77
78 public function testAdd()
79 {
80 $this->assertFalse($this->builder->has('foo'));
81 $this->builder->add('foo', 'text');
82 $this->assertTrue($this->builder->has('foo'));
83 }
84
85 public function testAddIntegerName()
86 {
87 $this->assertFalse($this->builder->has(0));
88 $this->builder->add(0, 'text');
89 $this->assertTrue($this->builder->has(0));
90 }
91
92 public function testAll()
93 {
94 $this->factory->expects($this->once())
95 ->method('createNamedBuilder')
96 ->with('foo', 'text')
97 ->will($this->returnValue(new FormBuilder('foo', null, $this->dispatcher, $this->factory)));
98
99 $this->assertCount(0, $this->builder->all());
100 $this->assertFalse($this->builder->has('foo'));
101
102 $this->builder->add('foo', 'text');
103 $children = $this->builder->all();
104
105 $this->assertTrue($this->builder->has('foo'));
106 $this->assertCount(1, $children);
107 $this->assertArrayHasKey('foo', $children);
108 }
109
110 /*
111 * https://github.com/symfony/symfony/issues/4693
112 */
113 public function testMaintainOrderOfLazyAndExplicitChildren()
114 {
115 $this->builder->add('foo', 'text');
116 $this->builder->add($this->getFormBuilder('bar'));
117 $this->builder->add('baz', 'text');
118
119 $children = $this->builder->all();
120
121 $this->assertSame(array('foo', 'bar', 'baz'), array_keys($children));
122 }
123
124 public function testAddFormType()
125 {
126 $this->assertFalse($this->builder->has('foo'));
127 $this->builder->add('foo', $this->getMock('Symfony\Component\Form\FormTypeInterface'));
128 $this->assertTrue($this->builder->has('foo'));
129 }
130
131 public function testRemove()
132 {
133 $this->builder->add('foo', 'text');
134 $this->builder->remove('foo');
135 $this->assertFalse($this->builder->has('foo'));
136 }
137
138 public function testRemoveUnknown()
139 {
140 $this->builder->remove('foo');
141 $this->assertFalse($this->builder->has('foo'));
142 }
143
144 // https://github.com/symfony/symfony/pull/4826
145 public function testRemoveAndGetForm()
146 {
147 $this->builder->add('foo', 'text');
148 $this->builder->remove('foo');
149 $form = $this->builder->getForm();
150 $this->assertInstanceOf('Symfony\Component\Form\Form', $form);
151 }
152
153 public function testCreateNoTypeNo()
154 {
155 $this->factory->expects($this->once())
156 ->method('createNamedBuilder')
157 ->with('foo', 'text', null, array())
158 ;
159
160 $this->builder->create('foo');
161 }
162
163 public function testGetUnknown()
164 {
165 $this->setExpectedException('Symfony\Component\Form\Exception\InvalidArgumentException', 'The child with the name "foo" does not exist.');
166 $this->builder->get('foo');
167 }
168
169 public function testGetExplicitType()
170 {
171 $expectedType = 'text';
172 $expectedName = 'foo';
173 $expectedOptions = array('bar' => 'baz');
174
175 $this->factory->expects($this->once())
176 ->method('createNamedBuilder')
177 ->with($expectedName, $expectedType, null, $expectedOptions)
178 ->will($this->returnValue($this->getFormBuilder()));
179
180 $this->builder->add($expectedName, $expectedType, $expectedOptions);
181 $builder = $this->builder->get($expectedName);
182
183 $this->assertNotSame($builder, $this->builder);
184 }
185
186 public function testGetGuessedType()
187 {
188 $expectedName = 'foo';
189 $expectedOptions = array('bar' => 'baz');
190
191 $this->factory->expects($this->once())
192 ->method('createBuilderForProperty')
193 ->with('stdClass', $expectedName, null, $expectedOptions)
194 ->will($this->returnValue($this->getFormBuilder()));
195
196 $this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory);
197 $this->builder->add($expectedName, null, $expectedOptions);
198 $builder = $this->builder->get($expectedName);
199
200 $this->assertNotSame($builder, $this->builder);
201 }
202
203 public function testGetFormConfigErasesReferences()
204 {
205 $builder = new FormBuilder('name', null, $this->dispatcher, $this->factory);
206 $builder->add(new FormBuilder('child', null, $this->dispatcher, $this->factory));
207
208 $config = $builder->getFormConfig();
209 $reflClass = new \ReflectionClass($config);
210 $children = $reflClass->getProperty('children');
211 $unresolvedChildren = $reflClass->getProperty('unresolvedChildren');
212
213 $children->setAccessible(true);
214 $unresolvedChildren->setAccessible(true);
215
216 $this->assertEmpty($children->getValue($config));
217 $this->assertEmpty($unresolvedChildren->getValue($config));
218 }
219
220 private function getFormBuilder($name = 'name')
221 {
222 $mock = $this->getMockBuilder('Symfony\Component\Form\FormBuilder')
223 ->disableOriginalConstructor()
224 ->getMock();
225
226 $mock->expects($this->any())
227 ->method('getName')
228 ->will($this->returnValue($name));
229
230 return $mock;
231 }
232}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/FormConfigTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/FormConfigTest.php
new file mode 100644
index 00000000..961dfd33
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/FormConfigTest.php
@@ -0,0 +1,148 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\Exception\UnexpectedTypeException;
15use Symfony\Component\Form\FormConfigBuilder;
16use Symfony\Component\Form\Exception\InvalidArgumentException;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class FormConfigTest extends \PHPUnit_Framework_TestCase
22{
23 public function getHtml4Ids()
24 {
25 return array(
26 array('z0', true),
27 array('A0', true),
28 array('A9', true),
29 array('Z0', true),
30 array('#', false),
31 array('a#', false),
32 array('a$', false),
33 array('a%', false),
34 array('a ', false),
35 array("a\t", false),
36 array("a\n", false),
37 array('a-', true),
38 array('a_', true),
39 array('a:', true),
40 // Periods are allowed by the HTML4 spec, but disallowed by us
41 // because they break the generated property paths
42 array('a.', false),
43 // Contrary to the HTML4 spec, we allow names starting with a
44 // number, otherwise naming fields by collection indices is not
45 // possible.
46 // For root forms, leading digits will be stripped from the
47 // "id" attribute to produce valid HTML4.
48 array('0', true),
49 array('9', true),
50 // Contrary to the HTML4 spec, we allow names starting with an
51 // underscore, since this is already a widely used practice in
52 // Symfony2.
53 // For root forms, leading underscores will be stripped from the
54 // "id" attribute to produce valid HTML4.
55 array('_', true),
56 // Integers are allowed
57 array(0, true),
58 array(123, true),
59 // NULL is allowed
60 array(null, true),
61 // Other types are not
62 array(1.23, false),
63 array(5., false),
64 array(true, false),
65 array(new \stdClass(), false),
66 );
67 }
68
69 /**
70 * @dataProvider getHtml4Ids
71 */
72 public function testNameAcceptsOnlyNamesValidAsIdsInHtml4($name, $accepted)
73 {
74 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
75
76 try {
77 new FormConfigBuilder($name, null, $dispatcher);
78 if (!$accepted) {
79 $this->fail(sprintf('The value "%s" should not be accepted', $name));
80 }
81 } catch (UnexpectedTypeException $e) {
82 // if the value was not accepted, but should be, rethrow exception
83 if ($accepted) {
84 throw $e;
85 }
86 } catch (InvalidArgumentException $e) {
87 // if the value was not accepted, but should be, rethrow exception
88 if ($accepted) {
89 throw $e;
90 }
91 }
92 }
93
94 public function testGetRequestHandlerCreatesNativeRequestHandlerIfNotSet()
95 {
96 $config = $this->getConfigBuilder()->getFormConfig();
97
98 $this->assertInstanceOf('Symfony\Component\Form\NativeRequestHandler', $config->getRequestHandler());
99 }
100
101 public function testGetRequestHandlerReusesNativeRequestHandlerInstance()
102 {
103 $config1 = $this->getConfigBuilder()->getFormConfig();
104 $config2 = $this->getConfigBuilder()->getFormConfig();
105
106 $this->assertSame($config1->getRequestHandler(), $config2->getRequestHandler());
107 }
108
109 public function testSetMethodAllowsGet()
110 {
111 $this->getConfigBuilder()->setMethod('GET');
112 }
113
114 public function testSetMethodAllowsPost()
115 {
116 $this->getConfigBuilder()->setMethod('POST');
117 }
118
119 public function testSetMethodAllowsPut()
120 {
121 $this->getConfigBuilder()->setMethod('PUT');
122 }
123
124 public function testSetMethodAllowsDelete()
125 {
126 $this->getConfigBuilder()->setMethod('DELETE');
127 }
128
129 public function testSetMethodAllowsPatch()
130 {
131 $this->getConfigBuilder()->setMethod('PATCH');
132 }
133
134 /**
135 * @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
136 */
137 public function testSetMethodDoesNotAllowOtherValues()
138 {
139 $this->getConfigBuilder()->setMethod('foo');
140 }
141
142 private function getConfigBuilder($name = 'name')
143 {
144 $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
145
146 return new FormConfigBuilder($name, null, $dispatcher);
147 }
148}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/FormFactoryBuilderTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/FormFactoryBuilderTest.php
new file mode 100644
index 00000000..a1292dbe
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/FormFactoryBuilderTest.php
@@ -0,0 +1,59 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\FormFactoryBuilder;
15use Symfony\Component\Form\Tests\Fixtures\FooType;
16
17class FormFactoryBuilderTest extends \PHPUnit_Framework_TestCase
18{
19 private $registry;
20 private $guesser;
21 private $type;
22
23 protected function setUp()
24 {
25 $factory = new \ReflectionClass('Symfony\Component\Form\FormFactory');
26 $this->registry = $factory->getProperty('registry');
27 $this->registry->setAccessible(true);
28
29 $this->guesser = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
30 $this->type = new FooType;
31 }
32
33 public function testAddType()
34 {
35 $factoryBuilder = new FormFactoryBuilder;
36 $factoryBuilder->addType($this->type);
37
38 $factory = $factoryBuilder->getFormFactory();
39 $registry = $this->registry->getValue($factory);
40 $extensions = $registry->getExtensions();
41
42 $this->assertCount(1, $extensions);
43 $this->assertTrue($extensions[0]->hasType($this->type->getName()));
44 $this->assertNull($extensions[0]->getTypeGuesser());
45 }
46
47 public function testAddTypeGuesser()
48 {
49 $factoryBuilder = new FormFactoryBuilder;
50 $factoryBuilder->addTypeGuesser($this->guesser);
51
52 $factory = $factoryBuilder->getFormFactory();
53 $registry = $this->registry->getValue($factory);
54 $extensions = $registry->getExtensions();
55
56 $this->assertCount(1, $extensions);
57 $this->assertNotNull($extensions[0]->getTypeGuesser());
58 }
59}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/FormFactoryTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/FormFactoryTest.php
new file mode 100644
index 00000000..ea872b01
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/FormFactoryTest.php
@@ -0,0 +1,506 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\FormTypeGuesserChain;
15use Symfony\Component\Form\FormFactory;
16use Symfony\Component\Form\Guess\Guess;
17use Symfony\Component\Form\Guess\ValueGuess;
18use Symfony\Component\Form\Guess\TypeGuess;
19use Symfony\Component\Form\Tests\Fixtures\Author;
20use Symfony\Component\Form\Tests\Fixtures\FooType;
21use Symfony\Component\Form\Tests\Fixtures\FooSubType;
22use Symfony\Component\Form\Tests\Fixtures\FooSubTypeWithParentInstance;
23
24/**
25 * @author Bernhard Schussek <bschussek@gmail.com>
26 */
27class FormFactoryTest extends \PHPUnit_Framework_TestCase
28{
29 /**
30 * @var \PHPUnit_Framework_MockObject_MockObject
31 */
32 private $guesser1;
33
34 /**
35 * @var \PHPUnit_Framework_MockObject_MockObject
36 */
37 private $guesser2;
38
39 /**
40 * @var \PHPUnit_Framework_MockObject_MockObject
41 */
42 private $registry;
43
44 /**
45 * @var \PHPUnit_Framework_MockObject_MockObject
46 */
47 private $resolvedTypeFactory;
48
49 /**
50 * @var FormFactory
51 */
52 private $factory;
53
54 protected function setUp()
55 {
56 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
57 $this->markTestSkipped('The "EventDispatcher" component is not available');
58 }
59
60 $this->resolvedTypeFactory = $this->getMock('Symfony\Component\Form\ResolvedFormTypeFactoryInterface');
61 $this->guesser1 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
62 $this->guesser2 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
63 $this->registry = $this->getMock('Symfony\Component\Form\FormRegistryInterface');
64 $this->factory = new FormFactory($this->registry, $this->resolvedTypeFactory);
65
66 $this->registry->expects($this->any())
67 ->method('getTypeGuesser')
68 ->will($this->returnValue(new FormTypeGuesserChain(array(
69 $this->guesser1,
70 $this->guesser2,
71 ))));
72 }
73
74 public function testCreateNamedBuilderWithTypeName()
75 {
76 $options = array('a' => '1', 'b' => '2');
77 $resolvedType = $this->getMockResolvedType();
78
79 $this->registry->expects($this->once())
80 ->method('getType')
81 ->with('type')
82 ->will($this->returnValue($resolvedType));
83
84 $resolvedType->expects($this->once())
85 ->method('createBuilder')
86 ->with($this->factory, 'name', $options)
87 ->will($this->returnValue('BUILDER'));
88
89 $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', null, $options));
90 }
91
92 public function testCreateNamedBuilderWithTypeInstance()
93 {
94 $options = array('a' => '1', 'b' => '2');
95 $type = new FooType();
96 $resolvedType = $this->getMockResolvedType();
97
98 $this->resolvedTypeFactory->expects($this->once())
99 ->method('createResolvedType')
100 ->with($type)
101 ->will($this->returnValue($resolvedType));
102
103 $resolvedType->expects($this->once())
104 ->method('createBuilder')
105 ->with($this->factory, 'name', $options)
106 ->will($this->returnValue('BUILDER'));
107
108 $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
109 }
110
111 public function testCreateNamedBuilderWithTypeInstanceWithParentType()
112 {
113 $options = array('a' => '1', 'b' => '2');
114 $type = new FooSubType();
115 $resolvedType = $this->getMockResolvedType();
116 $parentResolvedType = $this->getMockResolvedType();
117
118 $this->registry->expects($this->once())
119 ->method('getType')
120 ->with('foo')
121 ->will($this->returnValue($parentResolvedType));
122
123 $this->resolvedTypeFactory->expects($this->once())
124 ->method('createResolvedType')
125 ->with($type, array(), $parentResolvedType)
126 ->will($this->returnValue($resolvedType));
127
128 $resolvedType->expects($this->once())
129 ->method('createBuilder')
130 ->with($this->factory, 'name', $options)
131 ->will($this->returnValue('BUILDER'));
132
133 $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
134 }
135
136 public function testCreateNamedBuilderWithTypeInstanceWithParentTypeInstance()
137 {
138 $options = array('a' => '1', 'b' => '2');
139 $type = new FooSubTypeWithParentInstance();
140 $resolvedType = $this->getMockResolvedType();
141 $parentResolvedType = $this->getMockResolvedType();
142
143 $this->resolvedTypeFactory->expects($this->at(0))
144 ->method('createResolvedType')
145 ->with($type->getParent())
146 ->will($this->returnValue($parentResolvedType));
147
148 $this->resolvedTypeFactory->expects($this->at(1))
149 ->method('createResolvedType')
150 ->with($type, array(), $parentResolvedType)
151 ->will($this->returnValue($resolvedType));
152
153 $resolvedType->expects($this->once())
154 ->method('createBuilder')
155 ->with($this->factory, 'name', $options)
156 ->will($this->returnValue('BUILDER'));
157
158 $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
159 }
160
161 public function testCreateNamedBuilderWithResolvedTypeInstance()
162 {
163 $options = array('a' => '1', 'b' => '2');
164 $resolvedType = $this->getMockResolvedType();
165
166 $resolvedType->expects($this->once())
167 ->method('createBuilder')
168 ->with($this->factory, 'name', $options)
169 ->will($this->returnValue('BUILDER'));
170
171 $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $resolvedType, null, $options));
172 }
173
174 public function testCreateNamedBuilderFillsDataOption()
175 {
176 $givenOptions = array('a' => '1', 'b' => '2');
177 $expectedOptions = array_merge($givenOptions, array('data' => 'DATA'));
178 $resolvedType = $this->getMockResolvedType();
179
180 $this->registry->expects($this->once())
181 ->method('getType')
182 ->with('type')
183 ->will($this->returnValue($resolvedType));
184
185 $resolvedType->expects($this->once())
186 ->method('createBuilder')
187 ->with($this->factory, 'name', $expectedOptions)
188 ->will($this->returnValue('BUILDER'));
189
190 $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', 'DATA', $givenOptions));
191 }
192
193 public function testCreateNamedBuilderDoesNotOverrideExistingDataOption()
194 {
195 $options = array('a' => '1', 'b' => '2', 'data' => 'CUSTOM');
196 $resolvedType = $this->getMockResolvedType();
197
198 $this->registry->expects($this->once())
199 ->method('getType')
200 ->with('type')
201 ->will($this->returnValue($resolvedType));
202
203 $resolvedType->expects($this->once())
204 ->method('createBuilder')
205 ->with($this->factory, 'name', $options)
206 ->will($this->returnValue('BUILDER'));
207
208 $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', 'DATA', $options));
209 }
210
211 /**
212 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
213 * @expectedExceptionMessage Expected argument of type "string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface", "stdClass" given
214 */
215 public function testCreateNamedBuilderThrowsUnderstandableException()
216 {
217 $this->factory->createNamedBuilder('name', new \stdClass());
218 }
219
220 public function testCreateUsesTypeNameIfTypeGivenAsString()
221 {
222 $options = array('a' => '1', 'b' => '2');
223 $resolvedType = $this->getMockResolvedType();
224 $builder = $this->getMockFormBuilder();
225
226 $this->registry->expects($this->once())
227 ->method('getType')
228 ->with('TYPE')
229 ->will($this->returnValue($resolvedType));
230
231 $resolvedType->expects($this->once())
232 ->method('createBuilder')
233 ->with($this->factory, 'TYPE', $options)
234 ->will($this->returnValue($builder));
235
236 $builder->expects($this->once())
237 ->method('getForm')
238 ->will($this->returnValue('FORM'));
239
240 $this->assertSame('FORM', $this->factory->create('TYPE', null, $options));
241 }
242
243 public function testCreateUsesTypeNameIfTypeGivenAsObject()
244 {
245 $options = array('a' => '1', 'b' => '2');
246 $resolvedType = $this->getMockResolvedType();
247 $builder = $this->getMockFormBuilder();
248
249 $resolvedType->expects($this->once())
250 ->method('getName')
251 ->will($this->returnValue('TYPE'));
252
253 $resolvedType->expects($this->once())
254 ->method('createBuilder')
255 ->with($this->factory, 'TYPE', $options)
256 ->will($this->returnValue($builder));
257
258 $builder->expects($this->once())
259 ->method('getForm')
260 ->will($this->returnValue('FORM'));
261
262 $this->assertSame('FORM', $this->factory->create($resolvedType, null, $options));
263 }
264
265 public function testCreateNamed()
266 {
267 $options = array('a' => '1', 'b' => '2');
268 $resolvedType = $this->getMockResolvedType();
269 $builder = $this->getMockFormBuilder();
270
271 $this->registry->expects($this->once())
272 ->method('getType')
273 ->with('type')
274 ->will($this->returnValue($resolvedType));
275
276 $resolvedType->expects($this->once())
277 ->method('createBuilder')
278 ->with($this->factory, 'name', $options)
279 ->will($this->returnValue($builder));
280
281 $builder->expects($this->once())
282 ->method('getForm')
283 ->will($this->returnValue('FORM'));
284
285 $this->assertSame('FORM', $this->factory->createNamed('name', 'type', null, $options));
286 }
287
288 public function testCreateBuilderForPropertyWithoutTypeGuesser()
289 {
290 $registry = $this->getMock('Symfony\Component\Form\FormRegistryInterface');
291 $factory = $this->getMockBuilder('Symfony\Component\Form\FormFactory')
292 ->setMethods(array('createNamedBuilder'))
293 ->setConstructorArgs(array($registry, $this->resolvedTypeFactory))
294 ->getMock();
295
296 $factory->expects($this->once())
297 ->method('createNamedBuilder')
298 ->with('firstName', 'text', null, array())
299 ->will($this->returnValue('builderInstance'));
300
301 $builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
302
303 $this->assertEquals('builderInstance', $builder);
304 }
305
306 public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence()
307 {
308 $this->guesser1->expects($this->once())
309 ->method('guessType')
310 ->with('Application\Author', 'firstName')
311 ->will($this->returnValue(new TypeGuess(
312 'text',
313 array('max_length' => 10),
314 Guess::MEDIUM_CONFIDENCE
315 )));
316
317 $this->guesser2->expects($this->once())
318 ->method('guessType')
319 ->with('Application\Author', 'firstName')
320 ->will($this->returnValue(new TypeGuess(
321 'password',
322 array('max_length' => 7),
323 Guess::HIGH_CONFIDENCE
324 )));
325
326 $factory = $this->getMockFactory(array('createNamedBuilder'));
327
328 $factory->expects($this->once())
329 ->method('createNamedBuilder')
330 ->with('firstName', 'password', null, array('max_length' => 7))
331 ->will($this->returnValue('builderInstance'));
332
333 $builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
334
335 $this->assertEquals('builderInstance', $builder);
336 }
337
338 public function testCreateBuilderCreatesTextFormIfNoGuess()
339 {
340 $this->guesser1->expects($this->once())
341 ->method('guessType')
342 ->with('Application\Author', 'firstName')
343 ->will($this->returnValue(null));
344
345 $factory = $this->getMockFactory(array('createNamedBuilder'));
346
347 $factory->expects($this->once())
348 ->method('createNamedBuilder')
349 ->with('firstName', 'text')
350 ->will($this->returnValue('builderInstance'));
351
352 $builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
353
354 $this->assertEquals('builderInstance', $builder);
355 }
356
357 public function testOptionsCanBeOverridden()
358 {
359 $this->guesser1->expects($this->once())
360 ->method('guessType')
361 ->with('Application\Author', 'firstName')
362 ->will($this->returnValue(new TypeGuess(
363 'text',
364 array('max_length' => 10),
365 Guess::MEDIUM_CONFIDENCE
366 )));
367
368 $factory = $this->getMockFactory(array('createNamedBuilder'));
369
370 $factory->expects($this->once())
371 ->method('createNamedBuilder')
372 ->with('firstName', 'text', null, array('max_length' => 11))
373 ->will($this->returnValue('builderInstance'));
374
375 $builder = $factory->createBuilderForProperty(
376 'Application\Author',
377 'firstName',
378 null,
379 array('max_length' => 11)
380 );
381
382 $this->assertEquals('builderInstance', $builder);
383 }
384
385 public function testCreateBuilderUsesMaxLengthIfFound()
386 {
387 $this->guesser1->expects($this->once())
388 ->method('guessMaxLength')
389 ->with('Application\Author', 'firstName')
390 ->will($this->returnValue(new ValueGuess(
391 15,
392 Guess::MEDIUM_CONFIDENCE
393 )));
394
395 $this->guesser2->expects($this->once())
396 ->method('guessMaxLength')
397 ->with('Application\Author', 'firstName')
398 ->will($this->returnValue(new ValueGuess(
399 20,
400 Guess::HIGH_CONFIDENCE
401 )));
402
403 $factory = $this->getMockFactory(array('createNamedBuilder'));
404
405 $factory->expects($this->once())
406 ->method('createNamedBuilder')
407 ->with('firstName', 'text', null, array('max_length' => 20))
408 ->will($this->returnValue('builderInstance'));
409
410 $builder = $factory->createBuilderForProperty(
411 'Application\Author',
412 'firstName'
413 );
414
415 $this->assertEquals('builderInstance', $builder);
416 }
417
418 public function testCreateBuilderUsesRequiredSettingWithHighestConfidence()
419 {
420 $this->guesser1->expects($this->once())
421 ->method('guessRequired')
422 ->with('Application\Author', 'firstName')
423 ->will($this->returnValue(new ValueGuess(
424 true,
425 Guess::MEDIUM_CONFIDENCE
426 )));
427
428 $this->guesser2->expects($this->once())
429 ->method('guessRequired')
430 ->with('Application\Author', 'firstName')
431 ->will($this->returnValue(new ValueGuess(
432 false,
433 Guess::HIGH_CONFIDENCE
434 )));
435
436 $factory = $this->getMockFactory(array('createNamedBuilder'));
437
438 $factory->expects($this->once())
439 ->method('createNamedBuilder')
440 ->with('firstName', 'text', null, array('required' => false))
441 ->will($this->returnValue('builderInstance'));
442
443 $builder = $factory->createBuilderForProperty(
444 'Application\Author',
445 'firstName'
446 );
447
448 $this->assertEquals('builderInstance', $builder);
449 }
450
451 public function testCreateBuilderUsesPatternIfFound()
452 {
453 $this->guesser1->expects($this->once())
454 ->method('guessPattern')
455 ->with('Application\Author', 'firstName')
456 ->will($this->returnValue(new ValueGuess(
457 '[a-z]',
458 Guess::MEDIUM_CONFIDENCE
459 )));
460
461 $this->guesser2->expects($this->once())
462 ->method('guessPattern')
463 ->with('Application\Author', 'firstName')
464 ->will($this->returnValue(new ValueGuess(
465 '[a-zA-Z]',
466 Guess::HIGH_CONFIDENCE
467 )));
468
469 $factory = $this->getMockFactory(array('createNamedBuilder'));
470
471 $factory->expects($this->once())
472 ->method('createNamedBuilder')
473 ->with('firstName', 'text', null, array('pattern' => '[a-zA-Z]'))
474 ->will($this->returnValue('builderInstance'));
475
476 $builder = $factory->createBuilderForProperty(
477 'Application\Author',
478 'firstName'
479 );
480
481 $this->assertEquals('builderInstance', $builder);
482 }
483
484 private function getMockFactory(array $methods = array())
485 {
486 return $this->getMockBuilder('Symfony\Component\Form\FormFactory')
487 ->setMethods($methods)
488 ->setConstructorArgs(array($this->registry, $this->resolvedTypeFactory))
489 ->getMock();
490 }
491
492 private function getMockResolvedType()
493 {
494 return $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
495 }
496
497 private function getMockType()
498 {
499 return $this->getMock('Symfony\Component\Form\FormTypeInterface');
500 }
501
502 private function getMockFormBuilder()
503 {
504 return $this->getMock('Symfony\Component\Form\Test\FormBuilderInterface');
505 }
506}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/FormIntegrationTestCase.php b/vendor/symfony/form/Symfony/Component/Form/Tests/FormIntegrationTestCase.php
new file mode 100644
index 00000000..763286c2
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/FormIntegrationTestCase.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\Test\FormIntegrationTestCase as BaseFormIntegrationTestCase;
15
16/**
17 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use Symfony\Component\Form\Test\FormIntegrationTestCase instead.
18 */
19abstract class FormIntegrationTestCase extends BaseFormIntegrationTestCase
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/FormPerformanceTestCase.php b/vendor/symfony/form/Symfony/Component/Form/Tests/FormPerformanceTestCase.php
new file mode 100644
index 00000000..39882e85
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/FormPerformanceTestCase.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\Test\FormPerformanceTestCase as BaseFormPerformanceTestCase;
15
16/**
17 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use Symfony\Component\Form\Test\FormPerformanceTestCase instead.
18 */
19abstract class FormPerformanceTestCase extends BaseFormPerformanceTestCase
20{
21}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/FormRegistryTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/FormRegistryTest.php
new file mode 100644
index 00000000..0c8bb6b4
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/FormRegistryTest.php
@@ -0,0 +1,243 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\FormRegistry;
15use Symfony\Component\Form\FormTypeGuesserChain;
16use Symfony\Component\Form\Tests\Fixtures\TestExtension;
17use Symfony\Component\Form\Tests\Fixtures\FooSubTypeWithParentInstance;
18use Symfony\Component\Form\Tests\Fixtures\FooSubType;
19use Symfony\Component\Form\Tests\Fixtures\FooTypeBazExtension;
20use Symfony\Component\Form\Tests\Fixtures\FooTypeBarExtension;
21use Symfony\Component\Form\Tests\Fixtures\FooType;
22
23/**
24 * @author Bernhard Schussek <bschussek@gmail.com>
25 */
26class FormRegistryTest extends \PHPUnit_Framework_TestCase
27{
28 /**
29 * @var FormRegistry
30 */
31 private $registry;
32
33 /**
34 * @var \PHPUnit_Framework_MockObject_MockObject
35 */
36 private $resolvedTypeFactory;
37
38 /**
39 * @var \PHPUnit_Framework_MockObject_MockObject
40 */
41 private $guesser1;
42
43 /**
44 * @var \PHPUnit_Framework_MockObject_MockObject
45 */
46 private $guesser2;
47
48 /**
49 * @var TestExtension
50 */
51 private $extension1;
52
53 /**
54 * @var TestExtension
55 */
56 private $extension2;
57
58 protected function setUp()
59 {
60 $this->resolvedTypeFactory = $this->getMock('Symfony\Component\Form\ResolvedFormTypeFactory');
61 $this->guesser1 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
62 $this->guesser2 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
63 $this->extension1 = new TestExtension($this->guesser1);
64 $this->extension2 = new TestExtension($this->guesser2);
65 $this->registry = new FormRegistry(array(
66 $this->extension1,
67 $this->extension2,
68 ), $this->resolvedTypeFactory);
69 }
70
71 public function testGetTypeFromExtension()
72 {
73 $type = new FooType();
74 $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
75
76 $this->extension2->addType($type);
77
78 $this->resolvedTypeFactory->expects($this->once())
79 ->method('createResolvedType')
80 ->with($type)
81 ->will($this->returnValue($resolvedType));
82
83 $resolvedType->expects($this->any())
84 ->method('getName')
85 ->will($this->returnValue('foo'));
86
87 $resolvedType = $this->registry->getType('foo');
88
89 $this->assertSame($resolvedType, $this->registry->getType('foo'));
90 }
91
92 public function testGetTypeWithTypeExtensions()
93 {
94 $type = new FooType();
95 $ext1 = new FooTypeBarExtension();
96 $ext2 = new FooTypeBazExtension();
97 $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
98
99 $this->extension2->addType($type);
100 $this->extension1->addTypeExtension($ext1);
101 $this->extension2->addTypeExtension($ext2);
102
103 $this->resolvedTypeFactory->expects($this->once())
104 ->method('createResolvedType')
105 ->with($type, array($ext1, $ext2))
106 ->will($this->returnValue($resolvedType));
107
108 $resolvedType->expects($this->any())
109 ->method('getName')
110 ->will($this->returnValue('foo'));
111
112 $this->assertSame($resolvedType, $this->registry->getType('foo'));
113 }
114
115 public function testGetTypeConnectsParent()
116 {
117 $parentType = new FooType();
118 $type = new FooSubType();
119 $parentResolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
120 $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
121
122 $this->extension1->addType($parentType);
123 $this->extension2->addType($type);
124
125 $this->resolvedTypeFactory->expects($this->at(0))
126 ->method('createResolvedType')
127 ->with($parentType)
128 ->will($this->returnValue($parentResolvedType));
129
130 $this->resolvedTypeFactory->expects($this->at(1))
131 ->method('createResolvedType')
132 ->with($type, array(), $parentResolvedType)
133 ->will($this->returnValue($resolvedType));
134
135 $parentResolvedType->expects($this->any())
136 ->method('getName')
137 ->will($this->returnValue('foo'));
138
139 $resolvedType->expects($this->any())
140 ->method('getName')
141 ->will($this->returnValue('foo_sub_type'));
142
143 $this->assertSame($resolvedType, $this->registry->getType('foo_sub_type'));
144 }
145
146 public function testGetTypeConnectsParentIfGetParentReturnsInstance()
147 {
148 $type = new FooSubTypeWithParentInstance();
149 $parentResolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
150 $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
151
152 $this->extension1->addType($type);
153
154 $this->resolvedTypeFactory->expects($this->at(0))
155 ->method('createResolvedType')
156 ->with($this->isInstanceOf('Symfony\Component\Form\Tests\Fixtures\FooType'))
157 ->will($this->returnValue($parentResolvedType));
158
159 $this->resolvedTypeFactory->expects($this->at(1))
160 ->method('createResolvedType')
161 ->with($type, array(), $parentResolvedType)
162 ->will($this->returnValue($resolvedType));
163
164 $parentResolvedType->expects($this->any())
165 ->method('getName')
166 ->will($this->returnValue('foo'));
167
168 $resolvedType->expects($this->any())
169 ->method('getName')
170 ->will($this->returnValue('foo_sub_type_parent_instance'));
171
172 $this->assertSame($resolvedType, $this->registry->getType('foo_sub_type_parent_instance'));
173 }
174
175 /**
176 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
177 */
178 public function testGetTypeThrowsExceptionIfParentNotFound()
179 {
180 $type = new FooSubType();
181
182 $this->extension1->addType($type);
183
184 $this->registry->getType($type);
185 }
186
187 /**
188 * @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
189 */
190 public function testGetTypeThrowsExceptionIfTypeNotFound()
191 {
192 $this->registry->getType('bar');
193 }
194
195 /**
196 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
197 */
198 public function testGetTypeThrowsExceptionIfNoString()
199 {
200 $this->registry->getType(array());
201 }
202
203 public function testHasTypeAfterLoadingFromExtension()
204 {
205 $type = new FooType();
206 $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
207
208 $this->resolvedTypeFactory->expects($this->once())
209 ->method('createResolvedType')
210 ->with($type)
211 ->will($this->returnValue($resolvedType));
212
213 $resolvedType->expects($this->any())
214 ->method('getName')
215 ->will($this->returnValue('foo'));
216
217 $this->assertFalse($this->registry->hasType('foo'));
218
219 $this->extension2->addType($type);
220
221 $this->assertTrue($this->registry->hasType('foo'));
222 }
223
224 public function testGetTypeGuesser()
225 {
226 $expectedGuesser = new FormTypeGuesserChain(array($this->guesser1, $this->guesser2));
227
228 $this->assertEquals($expectedGuesser, $this->registry->getTypeGuesser());
229
230 $registry = new FormRegistry(
231 array($this->getMock('Symfony\Component\Form\FormExtensionInterface')),
232 $this->resolvedTypeFactory);
233
234 $this->assertNull($registry->getTypeGuesser());
235 }
236
237 public function testGetExtensions()
238 {
239 $expectedExtensions = array($this->extension1, $this->extension2);
240
241 $this->assertEquals($expectedExtensions, $this->registry->getExtensions());
242 }
243}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/FormRendererTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/FormRendererTest.php
new file mode 100644
index 00000000..69b048f7
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/FormRendererTest.php
@@ -0,0 +1,27 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Test;
13
14class FormRendererTest extends \PHPUnit_Framework_TestCase
15{
16 public function testHumanize()
17 {
18 $renderer = $this->getMockBuilder('Symfony\Component\Form\FormRenderer')
19 ->setMethods(null)
20 ->disableOriginalConstructor()
21 ->getMock()
22 ;
23
24 $this->assertEquals('Is active', $renderer->humanize('is_active'));
25 $this->assertEquals('Is active', $renderer->humanize('isActive'));
26 }
27}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/Guess/GuessTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/Guess/GuessTest.php
new file mode 100644
index 00000000..235eb6ed
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/Guess/GuessTest.php
@@ -0,0 +1,36 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Guess;
13
14use Symfony\Component\Form\Guess\Guess;
15
16class TestGuess extends Guess {}
17
18class GuessTest extends \PHPUnit_Framework_TestCase
19{
20 public function testGetBestGuessReturnsGuessWithHighestConfidence()
21 {
22 $guess1 = new TestGuess(Guess::MEDIUM_CONFIDENCE);
23 $guess2 = new TestGuess(Guess::LOW_CONFIDENCE);
24 $guess3 = new TestGuess(Guess::HIGH_CONFIDENCE);
25
26 $this->assertSame($guess3, Guess::getBestGuess(array($guess1, $guess2, $guess3)));
27 }
28
29 /**
30 * @expectedException \InvalidArgumentException
31 */
32 public function testGuessExpectsValidConfidence()
33 {
34 new TestGuess(5);
35 }
36}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php
new file mode 100644
index 00000000..9d3a997f
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php
@@ -0,0 +1,219 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\NativeRequestHandler;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class NativeRequestHandlerTest extends AbstractRequestHandlerTest
20{
21 private static $serverBackup;
22
23 public static function setUpBeforeClass()
24 {
25 self::$serverBackup = $_SERVER;
26 }
27
28 protected function setUp()
29 {
30 parent::setUp();
31
32 $_GET = array();
33 $_POST = array();
34 $_FILES = array();
35 $_SERVER = array(
36 // PHPUnit needs this entry
37 'SCRIPT_NAME' => self::$serverBackup['SCRIPT_NAME'],
38 );
39 }
40
41 protected function tearDown()
42 {
43 parent::tearDown();
44
45 $_GET = array();
46 $_POST = array();
47 $_FILES = array();
48 $_SERVER = self::$serverBackup;
49 }
50
51 /**
52 * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
53 */
54 public function testRequestShouldBeNull()
55 {
56 $this->requestHandler->handleRequest($this->getMockForm('name', 'GET'), 'request');
57 }
58
59 public function testMethodOverrideHeaderTakesPrecedenceIfPost()
60 {
61 $form = $this->getMockForm('param1', 'PUT');
62
63 $this->setRequestData('POST', array(
64 'param1' => 'DATA',
65 ));
66
67 $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT';
68
69 $form->expects($this->once())
70 ->method('submit')
71 ->with('DATA');
72
73 $this->requestHandler->handleRequest($form, $this->request);
74 }
75
76 public function testConvertEmptyUploadedFilesToNull()
77 {
78 $form = $this->getMockForm('param1', 'POST', false);
79
80 $this->setRequestData('POST', array(), array('param1' => array(
81 'name' => '',
82 'type' => '',
83 'tmp_name' => '',
84 'error' => UPLOAD_ERR_NO_FILE,
85 'size' => 0
86 )));
87
88 $form->expects($this->once())
89 ->method('submit')
90 ->with($this->identicalTo(null));
91
92 $this->requestHandler->handleRequest($form, $this->request);
93 }
94
95 public function testFixBuggyFilesArray()
96 {
97 $form = $this->getMockForm('param1', 'POST', false);
98
99 $this->setRequestData('POST', array(), array('param1' => array(
100 'name' => array(
101 'field' => 'upload.txt',
102 ),
103 'type' => array(
104 'field' => 'text/plain',
105 ),
106 'tmp_name' => array(
107 'field' => 'owfdskjasdfsa',
108 ),
109 'error' => array(
110 'field' => UPLOAD_ERR_OK,
111 ),
112 'size' => array(
113 'field' => 100,
114 ),
115 )));
116
117 $form->expects($this->once())
118 ->method('submit')
119 ->with(array(
120 'field' => array(
121 'name' => 'upload.txt',
122 'type' => 'text/plain',
123 'tmp_name' => 'owfdskjasdfsa',
124 'error' => UPLOAD_ERR_OK,
125 'size' => 100,
126 ),
127 ));
128
129 $this->requestHandler->handleRequest($form, $this->request);
130 }
131
132 public function testFixBuggyNestedFilesArray()
133 {
134 $form = $this->getMockForm('param1', 'POST');
135
136 $this->setRequestData('POST', array(), array('param1' => array(
137 'name' => array(
138 'field' => array('subfield' => 'upload.txt'),
139 ),
140 'type' => array(
141 'field' => array('subfield' => 'text/plain'),
142 ),
143 'tmp_name' => array(
144 'field' => array('subfield' => 'owfdskjasdfsa'),
145 ),
146 'error' => array(
147 'field' => array('subfield' => UPLOAD_ERR_OK),
148 ),
149 'size' => array(
150 'field' => array('subfield' => 100),
151 ),
152 )));
153
154 $form->expects($this->once())
155 ->method('submit')
156 ->with(array(
157 'field' => array(
158 'subfield' => array(
159 'name' => 'upload.txt',
160 'type' => 'text/plain',
161 'tmp_name' => 'owfdskjasdfsa',
162 'error' => UPLOAD_ERR_OK,
163 'size' => 100,
164 ),
165 ),
166 ));
167
168 $this->requestHandler->handleRequest($form, $this->request);
169 }
170
171 public function testMethodOverrideHeaderIgnoredIfNotPost()
172 {
173 $form = $this->getMockForm('param1', 'POST');
174
175 $this->setRequestData('GET', array(
176 'param1' => 'DATA',
177 ));
178
179 $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT';
180
181 $form->expects($this->never())
182 ->method('submit');
183
184 $this->requestHandler->handleRequest($form, $this->request);
185 }
186
187 protected function setRequestData($method, $data, $files = array())
188 {
189 if ('GET' === $method) {
190 $_GET = $data;
191 $_FILES = array();
192 } else {
193 $_POST = $data;
194 $_FILES = $files;
195 }
196
197 $_SERVER = array(
198 'REQUEST_METHOD' => $method,
199 // PHPUnit needs this entry
200 'SCRIPT_NAME' => self::$serverBackup['SCRIPT_NAME'],
201 );
202 }
203
204 protected function getRequestHandler()
205 {
206 return new NativeRequestHandler();
207 }
208
209 protected function getMockFile()
210 {
211 return array(
212 'name' => 'upload.txt',
213 'type' => 'text/plain',
214 'tmp_name' => 'owfdskjasdfsa',
215 'error' => UPLOAD_ERR_OK,
216 'size' => 100,
217 );
218 }
219}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php
new file mode 100644
index 00000000..bb32a241
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php
@@ -0,0 +1,280 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\ResolvedFormType;
15use Symfony\Component\Form\FormView;
16use Symfony\Component\Form\FormBuilder;
17use Symfony\Component\Form\Form;
18use Symfony\Component\OptionsResolver\OptionsResolverInterface;
19
20/**
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class ResolvedFormTypeTest extends \PHPUnit_Framework_TestCase
24{
25 /**
26 * @var \PHPUnit_Framework_MockObject_MockObject
27 */
28 private $dispatcher;
29
30 /**
31 * @var \PHPUnit_Framework_MockObject_MockObject
32 */
33 private $factory;
34
35 /**
36 * @var \PHPUnit_Framework_MockObject_MockObject
37 */
38 private $dataMapper;
39
40 protected function setUp()
41 {
42 if (!class_exists('Symfony\Component\OptionsResolver\OptionsResolver')) {
43 $this->markTestSkipped('The "OptionsResolver" component is not available');
44 }
45
46 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
47 $this->markTestSkipped('The "EventDispatcher" component is not available');
48 }
49
50 $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
51 $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
52 $this->dataMapper = $this->getMock('Symfony\Component\Form\DataMapperInterface');
53 }
54
55 public function testCreateBuilder()
56 {
57 if (version_compare(\PHPUnit_Runner_Version::id(), '3.7', '<')) {
58 $this->markTestSkipped('This test requires PHPUnit 3.7.');
59 }
60
61 $parentType = $this->getMockFormType();
62 $type = $this->getMockFormType();
63 $extension1 = $this->getMockFormTypeExtension();
64 $extension2 = $this->getMockFormTypeExtension();
65
66 $parentResolvedType = new ResolvedFormType($parentType);
67 $resolvedType = new ResolvedFormType($type, array($extension1, $extension2), $parentResolvedType);
68
69 $test = $this;
70 $i = 0;
71
72 $assertIndex = function ($index) use (&$i, $test) {
73 return function () use (&$i, $test, $index) {
74 /* @var \PHPUnit_Framework_TestCase $test */
75 $test->assertEquals($index, $i, 'Executed at index '.$index);
76
77 ++$i;
78 };
79 };
80
81 $assertIndexAndAddOption = function ($index, $option, $default) use ($assertIndex) {
82 $assertIndex = $assertIndex($index);
83
84 return function (OptionsResolverInterface $resolver) use ($assertIndex, $index, $option, $default) {
85 $assertIndex();
86
87 $resolver->setDefaults(array($option => $default));
88 };
89 };
90
91 // First the default options are generated for the super type
92 $parentType->expects($this->once())
93 ->method('setDefaultOptions')
94 ->will($this->returnCallback($assertIndexAndAddOption(0, 'a', 'a_default')));
95
96 // The form type itself
97 $type->expects($this->once())
98 ->method('setDefaultOptions')
99 ->will($this->returnCallback($assertIndexAndAddOption(1, 'b', 'b_default')));
100
101 // And its extensions
102 $extension1->expects($this->once())
103 ->method('setDefaultOptions')
104 ->will($this->returnCallback($assertIndexAndAddOption(2, 'c', 'c_default')));
105
106 $extension2->expects($this->once())
107 ->method('setDefaultOptions')
108 ->will($this->returnCallback($assertIndexAndAddOption(3, 'd', 'd_default')));
109
110 $givenOptions = array('a' => 'a_custom', 'c' => 'c_custom');
111 $resolvedOptions = array('a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default');
112
113 // Then the form is built for the super type
114 $parentType->expects($this->once())
115 ->method('buildForm')
116 ->with($this->anything(), $resolvedOptions)
117 ->will($this->returnCallback($assertIndex(4)));
118
119 // Then the type itself
120 $type->expects($this->once())
121 ->method('buildForm')
122 ->with($this->anything(), $resolvedOptions)
123 ->will($this->returnCallback($assertIndex(5)));
124
125 // Then its extensions
126 $extension1->expects($this->once())
127 ->method('buildForm')
128 ->with($this->anything(), $resolvedOptions)
129 ->will($this->returnCallback($assertIndex(6)));
130
131 $extension2->expects($this->once())
132 ->method('buildForm')
133 ->with($this->anything(), $resolvedOptions)
134 ->will($this->returnCallback($assertIndex(7)));
135
136 $factory = $this->getMockFormFactory();
137 $builder = $resolvedType->createBuilder($factory, 'name', $givenOptions);
138
139 $this->assertSame($resolvedType, $builder->getType());
140 }
141
142 public function testCreateView()
143 {
144 $parentType = $this->getMockFormType();
145 $type = $this->getMockFormType();
146 $field1Type = $this->getMockFormType();
147 $field2Type = $this->getMockFormType();
148 $extension1 = $this->getMockFormTypeExtension();
149 $extension2 = $this->getMockFormTypeExtension();
150
151 $parentResolvedType = new ResolvedFormType($parentType);
152 $resolvedType = new ResolvedFormType($type, array($extension1, $extension2), $parentResolvedType);
153 $field1ResolvedType = new ResolvedFormType($field1Type);
154 $field2ResolvedType = new ResolvedFormType($field2Type);
155
156 $options = array('a' => '1', 'b' => '2');
157 $form = $this->getBuilder('name', $options)
158 ->setCompound(true)
159 ->setDataMapper($this->dataMapper)
160 ->setType($resolvedType)
161 ->add($this->getBuilder('foo')->setType($field1ResolvedType))
162 ->add($this->getBuilder('bar')->setType($field2ResolvedType))
163 ->getForm();
164
165 $test = $this;
166 $i = 0;
167
168 $assertIndexAndNbOfChildViews = function ($index, $nbOfChildViews) use (&$i, $test) {
169 return function (FormView $view) use (&$i, $test, $index, $nbOfChildViews) {
170 /* @var \PHPUnit_Framework_TestCase $test */
171 $test->assertEquals($index, $i, 'Executed at index '.$index);
172 $test->assertCount($nbOfChildViews, $view);
173
174 ++$i;
175 };
176 };
177
178 // First the super type
179 $parentType->expects($this->once())
180 ->method('buildView')
181 ->with($this->anything(), $form, $options)
182 ->will($this->returnCallback($assertIndexAndNbOfChildViews(0, 0)));
183
184 // Then the type itself
185 $type->expects($this->once())
186 ->method('buildView')
187 ->with($this->anything(), $form, $options)
188 ->will($this->returnCallback($assertIndexAndNbOfChildViews(1, 0)));
189
190 // Then its extensions
191 $extension1->expects($this->once())
192 ->method('buildView')
193 ->with($this->anything(), $form, $options)
194 ->will($this->returnCallback($assertIndexAndNbOfChildViews(2, 0)));
195
196 $extension2->expects($this->once())
197 ->method('buildView')
198 ->with($this->anything(), $form, $options)
199 ->will($this->returnCallback($assertIndexAndNbOfChildViews(3, 0)));
200
201 // Now the first child form
202 $field1Type->expects($this->once())
203 ->method('buildView')
204 ->will($this->returnCallback($assertIndexAndNbOfChildViews(4, 0)));
205 $field1Type->expects($this->once())
206 ->method('finishView')
207 ->will($this->returnCallback($assertIndexAndNbOfChildViews(5, 0)));
208
209 // And the second child form
210 $field2Type->expects($this->once())
211 ->method('buildView')
212 ->will($this->returnCallback($assertIndexAndNbOfChildViews(6, 0)));
213 $field2Type->expects($this->once())
214 ->method('finishView')
215 ->will($this->returnCallback($assertIndexAndNbOfChildViews(7, 0)));
216
217 // Again first the parent
218 $parentType->expects($this->once())
219 ->method('finishView')
220 ->with($this->anything(), $form, $options)
221 ->will($this->returnCallback($assertIndexAndNbOfChildViews(8, 2)));
222
223 // Then the type itself
224 $type->expects($this->once())
225 ->method('finishView')
226 ->with($this->anything(), $form, $options)
227 ->will($this->returnCallback($assertIndexAndNbOfChildViews(9, 2)));
228
229 // Then its extensions
230 $extension1->expects($this->once())
231 ->method('finishView')
232 ->with($this->anything(), $form, $options)
233 ->will($this->returnCallback($assertIndexAndNbOfChildViews(10, 2)));
234
235 $extension2->expects($this->once())
236 ->method('finishView')
237 ->with($this->anything(), $form, $options)
238 ->will($this->returnCallback($assertIndexAndNbOfChildViews(11, 2)));
239
240 $parentView = new FormView();
241 $view = $resolvedType->createView($form, $parentView);
242
243 $this->assertSame($parentView, $view->parent);
244 }
245
246 /**
247 * @return \PHPUnit_Framework_MockObject_MockObject
248 */
249 private function getMockFormType()
250 {
251 return $this->getMock('Symfony\Component\Form\FormTypeInterface');
252 }
253
254 /**
255 * @return \PHPUnit_Framework_MockObject_MockObject
256 */
257 private function getMockFormTypeExtension()
258 {
259 return $this->getMock('Symfony\Component\Form\FormTypeExtensionInterface');
260 }
261
262 /**
263 * @return \PHPUnit_Framework_MockObject_MockObject
264 */
265 private function getMockFormFactory()
266 {
267 return $this->getMock('Symfony\Component\Form\FormFactoryInterface');
268 }
269
270 /**
271 * @param string $name
272 * @param array $options
273 *
274 * @return FormBuilder
275 */
276 protected function getBuilder($name = 'name', array $options = array())
277 {
278 return new FormBuilder($name, null, $this->dispatcher, $this->factory, $options);
279 }
280}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Tests/SimpleFormTest.php b/vendor/symfony/form/Symfony/Component/Form/Tests/SimpleFormTest.php
new file mode 100644
index 00000000..bedad676
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Tests/SimpleFormTest.php
@@ -0,0 +1,1045 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests;
13
14use Symfony\Component\Form\Form;
15use Symfony\Component\Form\FormEvent;
16use Symfony\Component\Form\FormEvents;
17use Symfony\Component\PropertyAccess\PropertyPath;
18use Symfony\Component\Form\FormConfigBuilder;
19use Symfony\Component\Form\FormError;
20use Symfony\Component\Form\Exception\TransformationFailedException;
21use Symfony\Component\EventDispatcher\EventDispatcher;
22use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
23use Symfony\Component\Form\Tests\Fixtures\FixedFilterListener;
24
25class SimpleFormTest_Countable implements \Countable
26{
27 private $count;
28
29 public function __construct($count)
30 {
31 $this->count = $count;
32 }
33
34 public function count()
35 {
36 return $this->count;
37 }
38}
39
40class SimpleFormTest_Traversable implements \IteratorAggregate
41{
42 private $iterator;
43
44 public function __construct($count)
45 {
46 $this->iterator = new \ArrayIterator($count > 0 ? array_fill(0, $count, 'Foo') : array());
47 }
48
49 public function getIterator()
50 {
51 return $this->iterator;
52 }
53}
54
55class SimpleFormTest extends AbstractFormTest
56{
57 public function testDataIsInitializedToConfiguredValue()
58 {
59 $model = new FixedDataTransformer(array(
60 'default' => 'foo',
61 ));
62 $view = new FixedDataTransformer(array(
63 'foo' => 'bar',
64 ));
65
66 $config = new FormConfigBuilder('name', null, $this->dispatcher);
67 $config->addViewTransformer($view);
68 $config->addModelTransformer($model);
69 $config->setData('default');
70 $form = new Form($config);
71
72 $this->assertSame('default', $form->getData());
73 $this->assertSame('foo', $form->getNormData());
74 $this->assertSame('bar', $form->getViewData());
75 }
76
77 // https://github.com/symfony/symfony/commit/d4f4038f6daf7cf88ca7c7ab089473cce5ebf7d8#commitcomment-1632879
78 public function testDataIsInitializedFromSubmit()
79 {
80 $mock = $this->getMockBuilder('\stdClass')
81 ->setMethods(array('preSetData', 'preSubmit'))
82 ->getMock();
83 $mock->expects($this->at(0))
84 ->method('preSetData');
85 $mock->expects($this->at(1))
86 ->method('preSubmit');
87
88 $config = new FormConfigBuilder('name', null, $this->dispatcher);
89 $config->addEventListener(FormEvents::PRE_SET_DATA, array($mock, 'preSetData'));
90 $config->addEventListener(FormEvents::PRE_SUBMIT, array($mock, 'preSubmit'));
91 $form = new Form($config);
92
93 // no call to setData() or similar where the object would be
94 // initialized otherwise
95
96 $form->submit('foobar');
97 }
98
99 // https://github.com/symfony/symfony/pull/7789
100 public function testFalseIsConvertedToNull()
101 {
102 $mock = $this->getMockBuilder('\stdClass')
103 ->setMethods(array('preBind'))
104 ->getMock();
105 $mock->expects($this->once())
106 ->method('preBind')
107 ->with($this->callback(function ($event) {
108 return null === $event->getData();
109 }));
110
111 $config = new FormConfigBuilder('name', null, $this->dispatcher);
112 $config->addEventListener(FormEvents::PRE_BIND, array($mock, 'preBind'));
113 $form = new Form($config);
114
115 $form->bind(false);
116
117 $this->assertTrue($form->isValid());
118 $this->assertNull($form->getData());
119 }
120
121 /**
122 * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
123 */
124 public function testSubmitThrowsExceptionIfAlreadySubmitted()
125 {
126 $this->form->submit(array());
127 $this->form->submit(array());
128 }
129
130 public function testSubmitIsIgnoredIfDisabled()
131 {
132 $form = $this->getBuilder()
133 ->setDisabled(true)
134 ->setData('initial')
135 ->getForm();
136
137 $form->submit('new');
138
139 $this->assertEquals('initial', $form->getData());
140 $this->assertTrue($form->isSubmitted());
141 }
142
143 public function testNeverRequiredIfParentNotRequired()
144 {
145 $parent = $this->getBuilder()->setRequired(false)->getForm();
146 $child = $this->getBuilder()->setRequired(true)->getForm();
147
148 $child->setParent($parent);
149
150 $this->assertFalse($child->isRequired());
151 }
152
153 public function testRequired()
154 {
155 $parent = $this->getBuilder()->setRequired(true)->getForm();
156 $child = $this->getBuilder()->setRequired(true)->getForm();
157
158 $child->setParent($parent);
159
160 $this->assertTrue($child->isRequired());
161 }
162
163 public function testNotRequired()
164 {
165 $parent = $this->getBuilder()->setRequired(true)->getForm();
166 $child = $this->getBuilder()->setRequired(false)->getForm();
167
168 $child->setParent($parent);
169
170 $this->assertFalse($child->isRequired());
171 }
172
173 public function testAlwaysDisabledIfParentDisabled()
174 {
175 $parent = $this->getBuilder()->setDisabled(true)->getForm();
176 $child = $this->getBuilder()->setDisabled(false)->getForm();
177
178 $child->setParent($parent);
179
180 $this->assertTrue($child->isDisabled());
181 }
182
183 public function testDisabled()
184 {
185 $parent = $this->getBuilder()->setDisabled(false)->getForm();
186 $child = $this->getBuilder()->setDisabled(true)->getForm();
187
188 $child->setParent($parent);
189
190 $this->assertTrue($child->isDisabled());
191 }
192
193 public function testNotDisabled()
194 {
195 $parent = $this->getBuilder()->setDisabled(false)->getForm();
196 $child = $this->getBuilder()->setDisabled(false)->getForm();
197
198 $child->setParent($parent);
199
200 $this->assertFalse($child->isDisabled());
201 }
202
203 public function testGetRootReturnsRootOfParent()
204 {
205 $parent = $this->getMockForm();
206 $parent->expects($this->once())
207 ->method('getRoot')
208 ->will($this->returnValue('ROOT'));
209
210 $this->form->setParent($parent);
211
212 $this->assertEquals('ROOT', $this->form->getRoot());
213 }
214
215 public function testGetRootReturnsSelfIfNoParent()
216 {
217 $this->assertSame($this->form, $this->form->getRoot());
218 }
219
220 public function testEmptyIfEmptyArray()
221 {
222 $this->form->setData(array());
223
224 $this->assertTrue($this->form->isEmpty());
225 }
226
227 public function testEmptyIfEmptyCountable()
228 {
229 $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Countable', $this->dispatcher));
230
231 $this->form->setData(new SimpleFormTest_Countable(0));
232
233 $this->assertTrue($this->form->isEmpty());
234 }
235
236 public function testNotEmptyIfFilledCountable()
237 {
238 $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Countable', $this->dispatcher));
239
240 $this->form->setData(new SimpleFormTest_Countable(1));
241
242 $this->assertFalse($this->form->isEmpty());
243 }
244
245 public function testEmptyIfEmptyTraversable()
246 {
247 $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Traversable', $this->dispatcher));
248
249 $this->form->setData(new SimpleFormTest_Traversable(0));
250
251 $this->assertTrue($this->form->isEmpty());
252 }
253
254 public function testNotEmptyIfFilledTraversable()
255 {
256 $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Traversable', $this->dispatcher));
257
258 $this->form->setData(new SimpleFormTest_Traversable(1));
259
260 $this->assertFalse($this->form->isEmpty());
261 }
262
263 public function testEmptyIfNull()
264 {
265 $this->form->setData(null);
266
267 $this->assertTrue($this->form->isEmpty());
268 }
269
270 public function testEmptyIfEmptyString()
271 {
272 $this->form->setData('');
273
274 $this->assertTrue($this->form->isEmpty());
275 }
276
277 public function testNotEmptyIfText()
278 {
279 $this->form->setData('foobar');
280
281 $this->assertFalse($this->form->isEmpty());
282 }
283
284 public function testValidIfSubmitted()
285 {
286 $form = $this->getBuilder()->getForm();
287 $form->submit('foobar');
288
289 $this->assertTrue($form->isValid());
290 }
291
292 public function testValidIfSubmittedAndDisabled()
293 {
294 $form = $this->getBuilder()->setDisabled(true)->getForm();
295 $form->submit('foobar');
296
297 $this->assertTrue($form->isValid());
298 }
299
300 public function testNotValidIfNotSubmitted()
301 {
302 $this->assertFalse($this->form->isValid());
303 }
304
305 public function testNotValidIfErrors()
306 {
307 $form = $this->getBuilder()->getForm();
308 $form->submit('foobar');
309 $form->addError(new FormError('Error!'));
310
311 $this->assertFalse($form->isValid());
312 }
313
314 public function testHasErrors()
315 {
316 $this->form->addError(new FormError('Error!'));
317
318 $this->assertCount(1, $this->form->getErrors());
319 }
320
321 public function testHasNoErrors()
322 {
323 $this->assertCount(0, $this->form->getErrors());
324 }
325
326 /**
327 * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
328 */
329 public function testSetParentThrowsExceptionIfAlreadySubmitted()
330 {
331 $this->form->submit(array());
332 $this->form->setParent($this->getBuilder('parent')->getForm());
333 }
334
335 public function testSubmitted()
336 {
337 $form = $this->getBuilder()->getForm();
338 $form->submit('foobar');
339
340 $this->assertTrue($form->isSubmitted());
341 }
342
343 public function testNotSubmitted()
344 {
345 $this->assertFalse($this->form->isSubmitted());
346 }
347
348 /**
349 * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
350 */
351 public function testSetDataThrowsExceptionIfAlreadySubmitted()
352 {
353 $this->form->submit(array());
354 $this->form->setData(null);
355 }
356
357 public function testSetDataClonesObjectIfNotByReference()
358 {
359 $data = new \stdClass();
360 $form = $this->getBuilder('name', null, '\stdClass')->setByReference(false)->getForm();
361 $form->setData($data);
362
363 $this->assertNotSame($data, $form->getData());
364 $this->assertEquals($data, $form->getData());
365 }
366
367 public function testSetDataDoesNotCloneObjectIfByReference()
368 {
369 $data = new \stdClass();
370 $form = $this->getBuilder('name', null, '\stdClass')->setByReference(true)->getForm();
371 $form->setData($data);
372
373 $this->assertSame($data, $form->getData());
374 }
375
376 public function testSetDataExecutesTransformationChain()
377 {
378 // use real event dispatcher now
379 $form = $this->getBuilder('name', new EventDispatcher())
380 ->addEventSubscriber(new FixedFilterListener(array(
381 'preSetData' => array(
382 'app' => 'filtered',
383 ),
384 )))
385 ->addModelTransformer(new FixedDataTransformer(array(
386 '' => '',
387 'filtered' => 'norm',
388 )))
389 ->addViewTransformer(new FixedDataTransformer(array(
390 '' => '',
391 'norm' => 'client',
392 )))
393 ->getForm();
394
395 $form->setData('app');
396
397 $this->assertEquals('filtered', $form->getData());
398 $this->assertEquals('norm', $form->getNormData());
399 $this->assertEquals('client', $form->getViewData());
400 }
401
402 public function testSetDataExecutesViewTransformersInOrder()
403 {
404 $form = $this->getBuilder()
405 ->addViewTransformer(new FixedDataTransformer(array(
406 '' => '',
407 'first' => 'second',
408 )))
409 ->addViewTransformer(new FixedDataTransformer(array(
410 '' => '',
411 'second' => 'third',
412 )))
413 ->getForm();
414
415 $form->setData('first');
416
417 $this->assertEquals('third', $form->getViewData());
418 }
419
420 public function testSetDataExecutesModelTransformersInReverseOrder()
421 {
422 $form = $this->getBuilder()
423 ->addModelTransformer(new FixedDataTransformer(array(
424 '' => '',
425 'second' => 'third',
426 )))
427 ->addModelTransformer(new FixedDataTransformer(array(
428 '' => '',
429 'first' => 'second',
430 )))
431 ->getForm();
432
433 $form->setData('first');
434
435 $this->assertEquals('third', $form->getNormData());
436 }
437
438 /*
439 * When there is no data transformer, the data must have the same format
440 * in all three representations
441 */
442 public function testSetDataConvertsScalarToStringIfNoTransformer()
443 {
444 $form = $this->getBuilder()->getForm();
445
446 $form->setData(1);
447
448 $this->assertSame('1', $form->getData());
449 $this->assertSame('1', $form->getNormData());
450 $this->assertSame('1', $form->getViewData());
451 }
452
453 /*
454 * Data in client format should, if possible, always be a string to
455 * facilitate differentiation between '0' and ''
456 */
457 public function testSetDataConvertsScalarToStringIfOnlyModelTransformer()
458 {
459 $form = $this->getBuilder()
460 ->addModelTransformer(new FixedDataTransformer(array(
461 '' => '',
462 1 => 23,
463 )))
464 ->getForm();
465
466 $form->setData(1);
467
468 $this->assertSame(1, $form->getData());
469 $this->assertSame(23, $form->getNormData());
470 $this->assertSame('23', $form->getViewData());
471 }
472
473 /*
474 * NULL remains NULL in app and norm format to remove the need to treat
475 * empty values and NULL explicitly in the application
476 */
477 public function testSetDataConvertsNullToStringIfNoTransformer()
478 {
479 $form = $this->getBuilder()->getForm();
480
481 $form->setData(null);
482
483 $this->assertNull($form->getData());
484 $this->assertNull($form->getNormData());
485 $this->assertSame('', $form->getViewData());
486 }
487
488 public function testSetDataIsIgnoredIfDataIsLocked()
489 {
490 $form = $this->getBuilder()
491 ->setData('default')
492 ->setDataLocked(true)
493 ->getForm();
494
495 $form->setData('foobar');
496
497 $this->assertSame('default', $form->getData());
498 }
499
500 public function testSubmitConvertsEmptyToNullIfNoTransformer()
501 {
502 $form = $this->getBuilder()->getForm();
503
504 $form->submit('');
505
506 $this->assertNull($form->getData());
507 $this->assertNull($form->getNormData());
508 $this->assertSame('', $form->getViewData());
509 }
510
511 public function testSubmitExecutesTransformationChain()
512 {
513 // use real event dispatcher now
514 $form = $this->getBuilder('name', new EventDispatcher())
515 ->addEventSubscriber(new FixedFilterListener(array(
516 'preSubmit' => array(
517 'client' => 'filteredclient',
518 ),
519 'onSubmit' => array(
520 'norm' => 'filterednorm',
521 ),
522 )))
523 ->addViewTransformer(new FixedDataTransformer(array(
524 '' => '',
525 // direction is reversed!
526 'norm' => 'filteredclient',
527 'filterednorm' => 'cleanedclient'
528 )))
529 ->addModelTransformer(new FixedDataTransformer(array(
530 '' => '',
531 // direction is reversed!
532 'app' => 'filterednorm',
533 )))
534 ->getForm();
535
536 $form->submit('client');
537
538 $this->assertEquals('app', $form->getData());
539 $this->assertEquals('filterednorm', $form->getNormData());
540 $this->assertEquals('cleanedclient', $form->getViewData());
541 }
542
543 public function testSubmitExecutesViewTransformersInReverseOrder()
544 {
545 $form = $this->getBuilder()
546 ->addViewTransformer(new FixedDataTransformer(array(
547 '' => '',
548 'third' => 'second',
549 )))
550 ->addViewTransformer(new FixedDataTransformer(array(
551 '' => '',
552 'second' => 'first',
553 )))
554 ->getForm();
555
556 $form->submit('first');
557
558 $this->assertEquals('third', $form->getNormData());
559 }
560
561 public function testSubmitExecutesModelTransformersInOrder()
562 {
563 $form = $this->getBuilder()
564 ->addModelTransformer(new FixedDataTransformer(array(
565 '' => '',
566 'second' => 'first',
567 )))
568 ->addModelTransformer(new FixedDataTransformer(array(
569 '' => '',
570 'third' => 'second',
571 )))
572 ->getForm();
573
574 $form->submit('first');
575
576 $this->assertEquals('third', $form->getData());
577 }
578
579 public function testSynchronizedByDefault()
580 {
581 $this->assertTrue($this->form->isSynchronized());
582 }
583
584 public function testSynchronizedAfterSubmission()
585 {
586 $this->form->submit('foobar');
587
588 $this->assertTrue($this->form->isSynchronized());
589 }
590
591 public function testNotSynchronizedIfViewReverseTransformationFailed()
592 {
593 $transformer = $this->getDataTransformer();
594 $transformer->expects($this->once())
595 ->method('reverseTransform')
596 ->will($this->throwException(new TransformationFailedException()));
597
598 $form = $this->getBuilder()
599 ->addViewTransformer($transformer)
600 ->getForm();
601
602 $form->submit('foobar');
603
604 $this->assertFalse($form->isSynchronized());
605 }
606
607 public function testNotSynchronizedIfModelReverseTransformationFailed()
608 {
609 $transformer = $this->getDataTransformer();
610 $transformer->expects($this->once())
611 ->method('reverseTransform')
612 ->will($this->throwException(new TransformationFailedException()));
613
614 $form = $this->getBuilder()
615 ->addModelTransformer($transformer)
616 ->getForm();
617
618 $form->submit('foobar');
619
620 $this->assertFalse($form->isSynchronized());
621 }
622
623 public function testEmptyDataCreatedBeforeTransforming()
624 {
625 $form = $this->getBuilder()
626 ->setEmptyData('foo')
627 ->addViewTransformer(new FixedDataTransformer(array(
628 '' => '',
629 // direction is reversed!
630 'bar' => 'foo',
631 )))
632 ->getForm();
633
634 $form->submit('');
635
636 $this->assertEquals('bar', $form->getData());
637 }
638
639 public function testEmptyDataFromClosure()
640 {
641 $test = $this;
642 $form = $this->getBuilder()
643 ->setEmptyData(function ($form) use ($test) {
644 // the form instance is passed to the closure to allow use
645 // of form data when creating the empty value
646 $test->assertInstanceOf('Symfony\Component\Form\FormInterface', $form);
647
648 return 'foo';
649 })
650 ->addViewTransformer(new FixedDataTransformer(array(
651 '' => '',
652 // direction is reversed!
653 'bar' => 'foo',
654 )))
655 ->getForm();
656
657 $form->submit('');
658
659 $this->assertEquals('bar', $form->getData());
660 }
661
662 public function testSubmitResetsErrors()
663 {
664 $this->form->addError(new FormError('Error!'));
665 $this->form->submit('foobar');
666
667 $this->assertSame(array(), $this->form->getErrors());
668 }
669
670 public function testCreateView()
671 {
672 $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
673 $view = $this->getMock('Symfony\Component\Form\FormView');
674 $form = $this->getBuilder()->setType($type)->getForm();
675
676 $type->expects($this->once())
677 ->method('createView')
678 ->with($form)
679 ->will($this->returnValue($view));
680
681 $this->assertSame($view, $form->createView());
682 }
683
684 public function testCreateViewWithParent()
685 {
686 $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
687 $view = $this->getMock('Symfony\Component\Form\FormView');
688 $parentForm = $this->getMock('Symfony\Component\Form\Test\FormInterface');
689 $parentView = $this->getMock('Symfony\Component\Form\FormView');
690 $form = $this->getBuilder()->setType($type)->getForm();
691 $form->setParent($parentForm);
692
693 $parentForm->expects($this->once())
694 ->method('createView')
695 ->will($this->returnValue($parentView));
696
697 $type->expects($this->once())
698 ->method('createView')
699 ->with($form, $parentView)
700 ->will($this->returnValue($view));
701
702 $this->assertSame($view, $form->createView());
703 }
704
705 public function testCreateViewWithExplicitParent()
706 {
707 $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
708 $view = $this->getMock('Symfony\Component\Form\FormView');
709 $parentView = $this->getMock('Symfony\Component\Form\FormView');
710 $form = $this->getBuilder()->setType($type)->getForm();
711
712 $type->expects($this->once())
713 ->method('createView')
714 ->with($form, $parentView)
715 ->will($this->returnValue($view));
716
717 $this->assertSame($view, $form->createView($parentView));
718 }
719
720 public function testGetErrorsAsString()
721 {
722 $this->form->addError(new FormError('Error!'));
723
724 $this->assertEquals("ERROR: Error!\n", $this->form->getErrorsAsString());
725 }
726
727 public function testFormCanHaveEmptyName()
728 {
729 $form = $this->getBuilder('')->getForm();
730
731 $this->assertEquals('', $form->getName());
732 }
733
734 public function testSetNullParentWorksWithEmptyName()
735 {
736 $form = $this->getBuilder('')->getForm();
737 $form->setParent(null);
738
739 $this->assertNull($form->getParent());
740 }
741
742 /**
743 * @expectedException \Symfony\Component\Form\Exception\LogicException
744 * @expectedExceptionMessage A form with an empty name cannot have a parent form.
745 */
746 public function testFormCannotHaveEmptyNameNotInRootLevel()
747 {
748 $this->getBuilder()
749 ->setCompound(true)
750 ->setDataMapper($this->getDataMapper())
751 ->add($this->getBuilder(''))
752 ->getForm();
753 }
754
755 public function testGetPropertyPathReturnsConfiguredPath()
756 {
757 $form = $this->getBuilder()->setPropertyPath('address.street')->getForm();
758
759 $this->assertEquals(new PropertyPath('address.street'), $form->getPropertyPath());
760 }
761
762 // see https://github.com/symfony/symfony/issues/3903
763 public function testGetPropertyPathDefaultsToNameIfParentHasDataClass()
764 {
765 $parent = $this->getBuilder(null, null, 'stdClass')
766 ->setCompound(true)
767 ->setDataMapper($this->getDataMapper())
768 ->getForm();
769 $form = $this->getBuilder('name')->getForm();
770 $parent->add($form);
771
772 $this->assertEquals(new PropertyPath('name'), $form->getPropertyPath());
773 }
774
775 // see https://github.com/symfony/symfony/issues/3903
776 public function testGetPropertyPathDefaultsToIndexedNameIfParentDataClassIsNull()
777 {
778 $parent = $this->getBuilder()
779 ->setCompound(true)
780 ->setDataMapper($this->getDataMapper())
781 ->getForm();
782 $form = $this->getBuilder('name')->getForm();
783 $parent->add($form);
784
785 $this->assertEquals(new PropertyPath('[name]'), $form->getPropertyPath());
786 }
787
788 public function testGetPropertyPathDefaultsToNameIfFirstParentWithoutInheritDataHasDataClass()
789 {
790 $grandParent = $this->getBuilder(null, null, 'stdClass')
791 ->setCompound(true)
792 ->setDataMapper($this->getDataMapper())
793 ->getForm();
794 $parent = $this->getBuilder()
795 ->setCompound(true)
796 ->setDataMapper($this->getDataMapper())
797 ->setInheritData(true)
798 ->getForm();
799 $form = $this->getBuilder('name')->getForm();
800 $grandParent->add($parent);
801 $parent->add($form);
802
803 $this->assertEquals(new PropertyPath('name'), $form->getPropertyPath());
804 }
805
806 public function testGetPropertyPathDefaultsToIndexedNameIfDataClassOfFirstParentWithoutInheritDataIsNull()
807 {
808 $grandParent = $this->getBuilder()
809 ->setCompound(true)
810 ->setDataMapper($this->getDataMapper())
811 ->getForm();
812 $parent = $this->getBuilder()
813 ->setCompound(true)
814 ->setDataMapper($this->getDataMapper())
815 ->setInheritData(true)
816 ->getForm();
817 $form = $this->getBuilder('name')->getForm();
818 $grandParent->add($parent);
819 $parent->add($form);
820
821 $this->assertEquals(new PropertyPath('[name]'), $form->getPropertyPath());
822 }
823
824 /**
825 * @expectedException \Symfony\Component\Form\Exception\LogicException
826 */
827 public function testViewDataMustNotBeObjectIfDataClassIsNull()
828 {
829 $config = new FormConfigBuilder('name', null, $this->dispatcher);
830 $config->addViewTransformer(new FixedDataTransformer(array(
831 '' => '',
832 'foo' => new \stdClass(),
833 )));
834 $form = new Form($config);
835
836 $form->setData('foo');
837 }
838
839 public function testViewDataMayBeArrayAccessIfDataClassIsNull()
840 {
841 $arrayAccess = $this->getMock('\ArrayAccess');
842 $config = new FormConfigBuilder('name', null, $this->dispatcher);
843 $config->addViewTransformer(new FixedDataTransformer(array(
844 '' => '',
845 'foo' => $arrayAccess,
846 )));
847 $form = new Form($config);
848
849 $form->setData('foo');
850
851 $this->assertSame($arrayAccess, $form->getViewData());
852 }
853
854 /**
855 * @expectedException \Symfony\Component\Form\Exception\LogicException
856 */
857 public function testViewDataMustBeObjectIfDataClassIsSet()
858 {
859 $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher);
860 $config->addViewTransformer(new FixedDataTransformer(array(
861 '' => '',
862 'foo' => array('bar' => 'baz'),
863 )));
864 $form = new Form($config);
865
866 $form->setData('foo');
867 }
868
869 /**
870 * @expectedException \Symfony\Component\Form\Exception\RuntimeException
871 */
872 public function testSetDataCannotInvokeItself()
873 {
874 // Cycle detection to prevent endless loops
875 $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher);
876 $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
877 $event->getForm()->setData('bar');
878 });
879 $form = new Form($config);
880
881 $form->setData('foo');
882 }
883
884 public function testSubmittingWrongDataIsIgnored()
885 {
886 $test = $this;
887
888 $child = $this->getBuilder('child', $this->dispatcher);
889 $child->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($test) {
890 // child form doesn't receive the wrong data that is submitted on parent
891 $test->assertNull($event->getData());
892 });
893
894 $parent = $this->getBuilder('parent', new EventDispatcher())
895 ->setCompound(true)
896 ->setDataMapper($this->getDataMapper())
897 ->add($child)
898 ->getForm();
899
900 $parent->submit('not-an-array');
901 }
902
903 public function testHandleRequestForwardsToRequestHandler()
904 {
905 $handler = $this->getMock('Symfony\Component\Form\RequestHandlerInterface');
906
907 $form = $this->getBuilder()
908 ->setRequestHandler($handler)
909 ->getForm();
910
911 $handler->expects($this->once())
912 ->method('handleRequest')
913 ->with($this->identicalTo($form), 'REQUEST');
914
915 $this->assertSame($form, $form->handleRequest('REQUEST'));
916 }
917
918 public function testFormInheritsParentData()
919 {
920 $child = $this->getBuilder('child')
921 ->setInheritData(true);
922
923 $parent = $this->getBuilder('parent')
924 ->setCompound(true)
925 ->setDataMapper($this->getDataMapper())
926 ->setData('foo')
927 ->addModelTransformer(new FixedDataTransformer(array(
928 'foo' => 'norm[foo]',
929 )))
930 ->addViewTransformer(new FixedDataTransformer(array(
931 'norm[foo]' => 'view[foo]',
932 )))
933 ->add($child)
934 ->getForm();
935
936 $this->assertSame('foo', $parent->get('child')->getData());
937 $this->assertSame('norm[foo]', $parent->get('child')->getNormData());
938 $this->assertSame('view[foo]', $parent->get('child')->getViewData());
939 }
940
941 /**
942 * @expectedException \Symfony\Component\Form\Exception\RuntimeException
943 */
944 public function testInheritDataDisallowsSetData()
945 {
946 $form = $this->getBuilder()
947 ->setInheritData(true)
948 ->getForm();
949
950 $form->setData('foo');
951 }
952
953 /**
954 * @expectedException \Symfony\Component\Form\Exception\RuntimeException
955 */
956 public function testGetDataRequiresParentToBeSetIfInheritData()
957 {
958 $form = $this->getBuilder()
959 ->setInheritData(true)
960 ->getForm();
961
962 $form->getData();
963 }
964
965 /**
966 * @expectedException \Symfony\Component\Form\Exception\RuntimeException
967 */
968 public function testGetNormDataRequiresParentToBeSetIfInheritData()
969 {
970 $form = $this->getBuilder()
971 ->setInheritData(true)
972 ->getForm();
973
974 $form->getNormData();
975 }
976
977 /**
978 * @expectedException \Symfony\Component\Form\Exception\RuntimeException
979 */
980 public function testGetViewDataRequiresParentToBeSetIfInheritData()
981 {
982 $form = $this->getBuilder()
983 ->setInheritData(true)
984 ->getForm();
985
986 $form->getViewData();
987 }
988
989 public function testPostSubmitDataIsNullIfInheritData()
990 {
991 $test = $this;
992 $form = $this->getBuilder()
993 ->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($test) {
994 $test->assertNull($event->getData());
995 })
996 ->setInheritData(true)
997 ->getForm();
998
999 $form->submit('foo');
1000 }
1001
1002 public function testSubmitIsNeverFiredIfInheritData()
1003 {
1004 $test = $this;
1005 $form = $this->getBuilder()
1006 ->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) use ($test) {
1007 $test->fail('The SUBMIT event should not be fired');
1008 })
1009 ->setInheritData(true)
1010 ->getForm();
1011
1012 $form->submit('foo');
1013 }
1014
1015 public function testInitializeSetsDefaultData()
1016 {
1017 $config = $this->getBuilder()->setData('DEFAULT')->getFormConfig();
1018 $form = $this->getMock('Symfony\Component\Form\Form', array('setData'), array($config));
1019
1020 $form->expects($this->once())
1021 ->method('setData')
1022 ->with($this->identicalTo('DEFAULT'));
1023
1024 /* @var Form $form */
1025 $form->initialize();
1026 }
1027
1028 /**
1029 * @expectedException \Symfony\Component\Form\Exception\RuntimeException
1030 */
1031 public function testInitializeFailsIfParent()
1032 {
1033 $parent = $this->getBuilder()->setRequired(false)->getForm();
1034 $child = $this->getBuilder()->setRequired(true)->getForm();
1035
1036 $child->setParent($parent);
1037
1038 $child->initialize();
1039 }
1040
1041 protected function createForm()
1042 {
1043 return $this->getBuilder()->getForm();
1044 }
1045}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Util/FormUtil.php b/vendor/symfony/form/Symfony/Component/Form/Util/FormUtil.php
new file mode 100644
index 00000000..7647691e
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Util/FormUtil.php
@@ -0,0 +1,42 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Util;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class FormUtil
18{
19 /**
20 * This class should not be instantiated
21 */
22 private function __construct() {}
23
24 /**
25 * Returns whether the given data is empty.
26 *
27 * This logic is reused multiple times throughout the processing of
28 * a form and needs to be consistent. PHP's keyword `empty` cannot
29 * be used as it also considers 0 and "0" to be empty.
30 *
31 * @param mixed $data
32 *
33 * @return Boolean
34 */
35 public static function isEmpty($data)
36 {
37 // Should not do a check for array() === $data!!!
38 // This method is used in occurrences where arrays are
39 // not considered to be empty, ever.
40 return null === $data || '' === $data;
41 }
42}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Util/InheritDataAwareIterator.php b/vendor/symfony/form/Symfony/Component/Form/Util/InheritDataAwareIterator.php
new file mode 100644
index 00000000..5c2c5fad
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Util/InheritDataAwareIterator.php
@@ -0,0 +1,35 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Util;
13
14/**
15 * Iterator that returns only forms from a form tree that do not inherit their
16 * parent data.
17 *
18 * If the iterator encounters a form that inherits its parent data, it enters
19 * the form and traverses its children as well.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class InheritDataAwareIterator extends VirtualFormAwareIterator
24{
25 /**
26 * Creates a new iterator.
27 *
28 * @param \Symfony\Component\Form\FormInterface[] $forms An array
29 */
30 public function __construct(array $forms)
31 {
32 // Skip the deprecation error
33 \ArrayIterator::__construct($forms);
34 }
35}
diff --git a/vendor/symfony/form/Symfony/Component/Form/Util/VirtualFormAwareIterator.php b/vendor/symfony/form/Symfony/Component/Form/Util/VirtualFormAwareIterator.php
new file mode 100644
index 00000000..24fdc8bb
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/Util/VirtualFormAwareIterator.php
@@ -0,0 +1,50 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Util;
13
14/**
15 * Iterator that returns only forms from a form tree that do not inherit their
16 * parent data.
17 *
18 * If the iterator encounters a form that inherits its parent data, it enters
19 * the form and traverses its children as well.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 *
23 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
24 * {@link InheritDataAwareIterator} instead.
25 */
26class VirtualFormAwareIterator extends \ArrayIterator implements \RecursiveIterator
27{
28 /**
29 * Creates a new iterator.
30 *
31 * @param \Symfony\Component\Form\FormInterface[] $forms An array
32 */
33 public function __construct(array $forms)
34 {
35 // Uncomment this as soon as the deprecation note should be shown
36 // trigger_error('VirtualFormAwareIterator is deprecated since version 2.3 and will be removed in 3.0. Use InheritDataAwareIterator instead.', E_USER_DEPRECATED);
37
38 parent::__construct($forms);
39 }
40
41 public function getChildren()
42 {
43 return new static($this->current()->all());
44 }
45
46 public function hasChildren()
47 {
48 return $this->current()->getConfig()->getInheritData();
49 }
50}
diff --git a/vendor/symfony/form/Symfony/Component/Form/composer.json b/vendor/symfony/form/Symfony/Component/Form/composer.json
new file mode 100644
index 00000000..73415011
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/composer.json
@@ -0,0 +1,43 @@
1{
2 "name": "symfony/form",
3 "type": "library",
4 "description": "Symfony Form Component",
5 "keywords": [],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3",
20 "symfony/event-dispatcher": "~2.1",
21 "symfony/intl": "~2.3",
22 "symfony/options-resolver": "~2.1",
23 "symfony/property-access": "~2.2"
24 },
25 "require-dev": {
26 "symfony/validator": "~2.2",
27 "symfony/http-foundation": "~2.2"
28 },
29 "suggest": {
30 "symfony/validator": "",
31 "symfony/http-foundation": ""
32 },
33 "autoload": {
34 "psr-0": { "Symfony\\Component\\Form\\": "" }
35 },
36 "target-dir": "Symfony/Component/Form",
37 "minimum-stability": "dev",
38 "extra": {
39 "branch-alias": {
40 "dev-master": "2.3-dev"
41 }
42 }
43}
diff --git a/vendor/symfony/form/Symfony/Component/Form/phpunit.xml.dist b/vendor/symfony/form/Symfony/Component/Form/phpunit.xml.dist
new file mode 100644
index 00000000..d0d261f1
--- /dev/null
+++ b/vendor/symfony/form/Symfony/Component/Form/phpunit.xml.dist
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony Form Component Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./Tests</directory>
25 <directory>./vendor</directory>
26 </exclude>
27 </whitelist>
28 </filter>
29</phpunit>
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/.gitignore b/vendor/symfony/icu/Symfony/Component/Icu/.gitignore
new file mode 100644
index 00000000..c49a5d8d
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/.gitignore
@@ -0,0 +1,3 @@
1vendor/
2composer.lock
3phpunit.xml
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/IcuCurrencyBundle.php b/vendor/symfony/icu/Symfony/Component/Icu/IcuCurrencyBundle.php
new file mode 100644
index 00000000..7c47e4e3
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/IcuCurrencyBundle.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Icu;
13
14use Symfony\Component\Intl\ResourceBundle\CurrencyBundle;
15use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
16
17/**
18 * A stub implementation of {@link \Symfony\Component\Intl\ResourceBundle\CurrencyBundleInterface}.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class IcuCurrencyBundle extends CurrencyBundle
23{
24 public function __construct(StructuredBundleReaderInterface $reader)
25 {
26 parent::__construct(realpath(IcuData::getResourceDirectory() . '/curr'), $reader);
27 }
28}
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/IcuData.php b/vendor/symfony/icu/Symfony/Component/Icu/IcuData.php
new file mode 100644
index 00000000..478a2f0e
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/IcuData.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Icu;
13
14use Symfony\Component\Intl\ResourceBundle\Reader\PhpBundleReader;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class IcuData
20{
21 /**
22 * Returns the version of the bundled ICU data.
23 *
24 * @return string The version string.
25 */
26 public static function getVersion()
27 {
28 return trim(file_get_contents(__DIR__ . '/Resources/data/version.txt'));
29 }
30
31 /**
32 * Returns whether the ICU data is stubbed.
33 *
34 * @return Boolean Returns true if the ICU data is stubbed, false if it is
35 * loaded from ICU .res files.
36 */
37 public static function isStubbed()
38 {
39 return true;
40 }
41
42 /**
43 * Returns the path to the directory where the resource bundles are stored.
44 *
45 * @return string The absolute path to the resource directory.
46 */
47 public static function getResourceDirectory()
48 {
49 return realpath(__DIR__ . '/Resources/data');
50 }
51
52 /**
53 * Returns a reader for reading resource bundles in this component.
54 *
55 * @return \Symfony\Component\Intl\ResourceBundle\Reader\BundleReaderInterface
56 */
57 public static function getBundleReader()
58 {
59 return new PhpBundleReader();
60 }
61
62 /**
63 * This class must not be instantiated.
64 */
65 private function __construct() {}
66}
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/IcuLanguageBundle.php b/vendor/symfony/icu/Symfony/Component/Icu/IcuLanguageBundle.php
new file mode 100644
index 00000000..a3de4316
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/IcuLanguageBundle.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Icu;
13
14use Symfony\Component\Intl\ResourceBundle\LanguageBundle;
15use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
16
17/**
18 * A stub implementation of {@link \Symfony\Component\Intl\ResourceBundle\LanguageBundleInterface}.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class IcuLanguageBundle extends LanguageBundle
23{
24 public function __construct(StructuredBundleReaderInterface $reader)
25 {
26 parent::__construct(realpath(IcuData::getResourceDirectory() . '/lang'), $reader);
27 }
28}
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/IcuLocaleBundle.php b/vendor/symfony/icu/Symfony/Component/Icu/IcuLocaleBundle.php
new file mode 100644
index 00000000..a9a54384
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/IcuLocaleBundle.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Icu;
13
14use Symfony\Component\Intl\ResourceBundle\LocaleBundle;
15use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
16
17/**
18 * A stub implementation of {@link \Symfony\Component\Intl\ResourceBundle\LocaleBundleInterface}.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class IcuLocaleBundle extends LocaleBundle
23{
24 public function __construct(StructuredBundleReaderInterface $reader)
25 {
26 parent::__construct(realpath(IcuData::getResourceDirectory() . '/locales'), $reader);
27 }
28}
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/IcuRegionBundle.php b/vendor/symfony/icu/Symfony/Component/Icu/IcuRegionBundle.php
new file mode 100644
index 00000000..639a4339
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/IcuRegionBundle.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Icu;
13
14use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
15use Symfony\Component\Intl\ResourceBundle\RegionBundle;
16
17/**
18 * A stub implementation of {@link \Symfony\Component\Intl\ResourceBundle\RegionBundleInterface}.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class IcuRegionBundle extends RegionBundle
23{
24 public function __construct(StructuredBundleReaderInterface $reader)
25 {
26 parent::__construct(realpath(IcuData::getResourceDirectory() . '/region'), $reader);
27 }
28}
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/LICENSE b/vendor/symfony/icu/Symfony/Component/Icu/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/README.md b/vendor/symfony/icu/Symfony/Component/Icu/README.md
new file mode 100644
index 00000000..b0a16edd
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/README.md
@@ -0,0 +1,18 @@
1Icu Component
2=============
3
4Contains data of the ICU library in a specific version.
5
6You should not directly use this component. Use it through the API of the
7[Intl component] [1] instead.
8
9Resources
10---------
11
12You can run the unit tests with the following command:
13
14 $ cd path/to/Symfony/Component/Icu/
15 $ composer.phar install --dev
16 $ phpunit
17
18[1]: https://github.com/symfony/Intl
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/curr/en.php b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/curr/en.php
new file mode 100644
index 00000000..3b38213c
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/curr/en.php
@@ -0,0 +1,1791 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12return array(
13 'Currencies' => array(
14 'XUA' => array(
15 0 => 'ADB Unit of Account',
16 1 => 'XUA',
17 2 => 2,
18 3 => 0,
19 ),
20 'AFN' => array(
21 0 => 'Afghan Afghani',
22 1 => 'AFN',
23 2 => 0,
24 3 => 0,
25 ),
26 'AFA' => array(
27 0 => 'Afghan Afghani (1927-2002)',
28 1 => 'AFA',
29 2 => 2,
30 3 => 0,
31 ),
32 'ALL' => array(
33 0 => 'Albanian Lek',
34 1 => 'ALL',
35 2 => 0,
36 3 => 0,
37 ),
38 'ALK' => array(
39 0 => 'Albanian Lek (1946-1965)',
40 1 => 'ALK',
41 2 => 2,
42 3 => 0,
43 ),
44 'DZD' => array(
45 0 => 'Algerian Dinar',
46 1 => 'DZD',
47 2 => 2,
48 3 => 0,
49 ),
50 'ADP' => array(
51 0 => 'Andorran Peseta',
52 1 => 'ADP',
53 2 => 0,
54 3 => 0,
55 ),
56 'AOA' => array(
57 0 => 'Angolan Kwanza',
58 1 => 'AOA',
59 2 => 2,
60 3 => 0,
61 ),
62 'AOK' => array(
63 0 => 'Angolan Kwanza (1977-1991)',
64 1 => 'AOK',
65 2 => 2,
66 3 => 0,
67 ),
68 'AON' => array(
69 0 => 'Angolan New Kwanza (1990-2000)',
70 1 => 'AON',
71 2 => 2,
72 3 => 0,
73 ),
74 'AOR' => array(
75 0 => 'Angolan Readjusted Kwanza (1995-1999)',
76 1 => 'AOR',
77 2 => 2,
78 3 => 0,
79 ),
80 'ARA' => array(
81 0 => 'Argentine Austral',
82 1 => 'ARA',
83 2 => 2,
84 3 => 0,
85 ),
86 'ARS' => array(
87 0 => 'Argentine Peso',
88 1 => 'ARS',
89 2 => 2,
90 3 => 0,
91 ),
92 'ARM' => array(
93 0 => 'Argentine Peso (1881-1970)',
94 1 => 'ARM',
95 2 => 2,
96 3 => 0,
97 ),
98 'ARP' => array(
99 0 => 'Argentine Peso (1983-1985)',
100 1 => 'ARP',
101 2 => 2,
102 3 => 0,
103 ),
104 'ARL' => array(
105 0 => 'Argentine Peso Ley (1970-1983)',
106 1 => 'ARL',
107 2 => 2,
108 3 => 0,
109 ),
110 'AMD' => array(
111 0 => 'Armenian Dram',
112 1 => 'AMD',
113 2 => 0,
114 3 => 0,
115 ),
116 'AWG' => array(
117 0 => 'Aruban Florin',
118 1 => 'AWG',
119 2 => 2,
120 3 => 0,
121 ),
122 'AUD' => array(
123 0 => 'Australian Dollar',
124 1 => 'A$',
125 2 => 2,
126 3 => 0,
127 ),
128 'ATS' => array(
129 0 => 'Austrian Schilling',
130 1 => 'ATS',
131 2 => 2,
132 3 => 0,
133 ),
134 'AZN' => array(
135 0 => 'Azerbaijani Manat',
136 1 => 'AZN',
137 2 => 2,
138 3 => 0,
139 ),
140 'AZM' => array(
141 0 => 'Azerbaijani Manat (1993-2006)',
142 1 => 'AZM',
143 2 => 2,
144 3 => 0,
145 ),
146 'BSD' => array(
147 0 => 'Bahamian Dollar',
148 1 => 'BSD',
149 2 => 2,
150 3 => 0,
151 ),
152 'BHD' => array(
153 0 => 'Bahraini Dinar',
154 1 => 'BHD',
155 2 => 3,
156 3 => 0,
157 ),
158 'BDT' => array(
159 0 => 'Bangladeshi Taka',
160 1 => 'BDT',
161 2 => 2,
162 3 => 0,
163 ),
164 'BBD' => array(
165 0 => 'Barbadian Dollar',
166 1 => 'BBD',
167 2 => 2,
168 3 => 0,
169 ),
170 'BYB' => array(
171 0 => 'Belarusian New Ruble (1994-1999)',
172 1 => 'BYB',
173 2 => 2,
174 3 => 0,
175 ),
176 'BYR' => array(
177 0 => 'Belarusian Ruble',
178 1 => 'BYR',
179 2 => 0,
180 3 => 0,
181 ),
182 'BEF' => array(
183 0 => 'Belgian Franc',
184 1 => 'BEF',
185 2 => 2,
186 3 => 0,
187 ),
188 'BEC' => array(
189 0 => 'Belgian Franc (convertible)',
190 1 => 'BEC',
191 2 => 2,
192 3 => 0,
193 ),
194 'BEL' => array(
195 0 => 'Belgian Franc (financial)',
196 1 => 'BEL',
197 2 => 2,
198 3 => 0,
199 ),
200 'BZD' => array(
201 0 => 'Belize Dollar',
202 1 => 'BZD',
203 2 => 2,
204 3 => 0,
205 ),
206 'BMD' => array(
207 0 => 'Bermudan Dollar',
208 1 => 'BMD',
209 2 => 2,
210 3 => 0,
211 ),
212 'BTN' => array(
213 0 => 'Bhutanese Ngultrum',
214 1 => 'BTN',
215 2 => 2,
216 3 => 0,
217 ),
218 'BOB' => array(
219 0 => 'Bolivian Boliviano',
220 1 => 'BOB',
221 2 => 2,
222 3 => 0,
223 ),
224 'BOL' => array(
225 0 => 'Bolivian Boliviano (1863-1963)',
226 1 => 'BOL',
227 2 => 2,
228 3 => 0,
229 ),
230 'BOV' => array(
231 0 => 'Bolivian Mvdol',
232 1 => 'BOV',
233 2 => 2,
234 3 => 0,
235 ),
236 'BOP' => array(
237 0 => 'Bolivian Peso',
238 1 => 'BOP',
239 2 => 2,
240 3 => 0,
241 ),
242 'BAM' => array(
243 0 => 'Bosnia-Herzegovina Convertible Mark',
244 1 => 'BAM',
245 2 => 2,
246 3 => 0,
247 ),
248 'BAD' => array(
249 0 => 'Bosnia-Herzegovina Dinar (1992-1994)',
250 1 => 'BAD',
251 2 => 2,
252 3 => 0,
253 ),
254 'BAN' => array(
255 0 => 'Bosnia-Herzegovina New Dinar (1994-1997)',
256 1 => 'BAN',
257 2 => 2,
258 3 => 0,
259 ),
260 'BWP' => array(
261 0 => 'Botswanan Pula',
262 1 => 'BWP',
263 2 => 2,
264 3 => 0,
265 ),
266 'BRC' => array(
267 0 => 'Brazilian Cruzado (1986-1989)',
268 1 => 'BRC',
269 2 => 2,
270 3 => 0,
271 ),
272 'BRZ' => array(
273 0 => 'Brazilian Cruzeiro (1942-1967)',
274 1 => 'BRZ',
275 2 => 2,
276 3 => 0,
277 ),
278 'BRE' => array(
279 0 => 'Brazilian Cruzeiro (1990-1993)',
280 1 => 'BRE',
281 2 => 2,
282 3 => 0,
283 ),
284 'BRR' => array(
285 0 => 'Brazilian Cruzeiro (1993-1994)',
286 1 => 'BRR',
287 2 => 2,
288 3 => 0,
289 ),
290 'BRN' => array(
291 0 => 'Brazilian New Cruzado (1989-1990)',
292 1 => 'BRN',
293 2 => 2,
294 3 => 0,
295 ),
296 'BRB' => array(
297 0 => 'Brazilian New Cruzeiro (1967-1986)',
298 1 => 'BRB',
299 2 => 2,
300 3 => 0,
301 ),
302 'BRL' => array(
303 0 => 'Brazilian Real',
304 1 => 'R$',
305 2 => 2,
306 3 => 0,
307 ),
308 'GBP' => array(
309 0 => 'British Pound Sterling',
310 1 => '£',
311 2 => 2,
312 3 => 0,
313 ),
314 'BND' => array(
315 0 => 'Brunei Dollar',
316 1 => 'BND',
317 2 => 2,
318 3 => 0,
319 ),
320 'BGL' => array(
321 0 => 'Bulgarian Hard Lev',
322 1 => 'BGL',
323 2 => 2,
324 3 => 0,
325 ),
326 'BGN' => array(
327 0 => 'Bulgarian Lev',
328 1 => 'BGN',
329 2 => 2,
330 3 => 0,
331 ),
332 'BGO' => array(
333 0 => 'Bulgarian Lev (1879-1952)',
334 1 => 'BGO',
335 2 => 2,
336 3 => 0,
337 ),
338 'BGM' => array(
339 0 => 'Bulgarian Socialist Lev',
340 1 => 'BGM',
341 2 => 2,
342 3 => 0,
343 ),
344 'BUK' => array(
345 0 => 'Burmese Kyat',
346 1 => 'BUK',
347 2 => 2,
348 3 => 0,
349 ),
350 'BIF' => array(
351 0 => 'Burundian Franc',
352 1 => 'BIF',
353 2 => 0,
354 3 => 0,
355 ),
356 'KHR' => array(
357 0 => 'Cambodian Riel',
358 1 => 'KHR',
359 2 => 2,
360 3 => 0,
361 ),
362 'CAD' => array(
363 0 => 'Canadian Dollar',
364 1 => 'CA$',
365 2 => 2,
366 3 => 0,
367 ),
368 'CVE' => array(
369 0 => 'Cape Verdean Escudo',
370 1 => 'CVE',
371 2 => 2,
372 3 => 0,
373 ),
374 'KYD' => array(
375 0 => 'Cayman Islands Dollar',
376 1 => 'KYD',
377 2 => 2,
378 3 => 0,
379 ),
380 'XOF' => array(
381 0 => 'CFA Franc BCEAO',
382 1 => 'CFA',
383 2 => 0,
384 3 => 0,
385 ),
386 'XAF' => array(
387 0 => 'CFA Franc BEAC',
388 1 => 'FCFA',
389 2 => 0,
390 3 => 0,
391 ),
392 'XPF' => array(
393 0 => 'CFP Franc',
394 1 => 'CFPF',
395 2 => 0,
396 3 => 0,
397 ),
398 'CLE' => array(
399 0 => 'Chilean Escudo',
400 1 => 'CLE',
401 2 => 2,
402 3 => 0,
403 ),
404 'CLP' => array(
405 0 => 'Chilean Peso',
406 1 => 'CLP',
407 2 => 0,
408 3 => 0,
409 ),
410 'CLF' => array(
411 0 => 'Chilean Unit of Account (UF)',
412 1 => 'CLF',
413 2 => 0,
414 3 => 0,
415 ),
416 'CNX' => array(
417 0 => 'Chinese People’s Bank Dollar',
418 1 => 'CNX',
419 2 => 2,
420 3 => 0,
421 ),
422 'CNY' => array(
423 0 => 'Chinese Yuan',
424 1 => 'CNÂ¥',
425 2 => 2,
426 3 => 0,
427 ),
428 'COP' => array(
429 0 => 'Colombian Peso',
430 1 => 'COP',
431 2 => 0,
432 3 => 0,
433 ),
434 'COU' => array(
435 0 => 'Colombian Real Value Unit',
436 1 => 'COU',
437 2 => 2,
438 3 => 0,
439 ),
440 'KMF' => array(
441 0 => 'Comorian Franc',
442 1 => 'KMF',
443 2 => 0,
444 3 => 0,
445 ),
446 'CDF' => array(
447 0 => 'Congolese Franc',
448 1 => 'CDF',
449 2 => 2,
450 3 => 0,
451 ),
452 'CRC' => array(
453 0 => 'Costa Rican Colón',
454 1 => 'CRC',
455 2 => 0,
456 3 => 0,
457 ),
458 'HRD' => array(
459 0 => 'Croatian Dinar',
460 1 => 'HRD',
461 2 => 2,
462 3 => 0,
463 ),
464 'HRK' => array(
465 0 => 'Croatian Kuna',
466 1 => 'HRK',
467 2 => 2,
468 3 => 0,
469 ),
470 'CUC' => array(
471 0 => 'Cuban Convertible Peso',
472 1 => 'CUC',
473 2 => 2,
474 3 => 0,
475 ),
476 'CUP' => array(
477 0 => 'Cuban Peso',
478 1 => 'CUP',
479 2 => 2,
480 3 => 0,
481 ),
482 'CYP' => array(
483 0 => 'Cypriot Pound',
484 1 => 'CYP',
485 2 => 2,
486 3 => 0,
487 ),
488 'CZK' => array(
489 0 => 'Czech Republic Koruna',
490 1 => 'CZK',
491 2 => 2,
492 3 => 0,
493 ),
494 'CSK' => array(
495 0 => 'Czechoslovak Hard Koruna',
496 1 => 'CSK',
497 2 => 2,
498 3 => 0,
499 ),
500 'DKK' => array(
501 0 => 'Danish Krone',
502 1 => 'DKK',
503 2 => 2,
504 3 => 0,
505 ),
506 'DJF' => array(
507 0 => 'Djiboutian Franc',
508 1 => 'DJF',
509 2 => 0,
510 3 => 0,
511 ),
512 'DOP' => array(
513 0 => 'Dominican Peso',
514 1 => 'DOP',
515 2 => 2,
516 3 => 0,
517 ),
518 'NLG' => array(
519 0 => 'Dutch Guilder',
520 1 => 'NLG',
521 2 => 2,
522 3 => 0,
523 ),
524 'XCD' => array(
525 0 => 'East Caribbean Dollar',
526 1 => 'EC$',
527 2 => 2,
528 3 => 0,
529 ),
530 'DDM' => array(
531 0 => 'East German Mark',
532 1 => 'DDM',
533 2 => 2,
534 3 => 0,
535 ),
536 'ECS' => array(
537 0 => 'Ecuadorian Sucre',
538 1 => 'ECS',
539 2 => 2,
540 3 => 0,
541 ),
542 'ECV' => array(
543 0 => 'Ecuadorian Unit of Constant Value',
544 1 => 'ECV',
545 2 => 2,
546 3 => 0,
547 ),
548 'EGP' => array(
549 0 => 'Egyptian Pound',
550 1 => 'EGP',
551 2 => 2,
552 3 => 0,
553 ),
554 'GQE' => array(
555 0 => 'Equatorial Guinean Ekwele',
556 1 => 'GQE',
557 2 => 2,
558 3 => 0,
559 ),
560 'ERN' => array(
561 0 => 'Eritrean Nakfa',
562 1 => 'ERN',
563 2 => 2,
564 3 => 0,
565 ),
566 'EEK' => array(
567 0 => 'Estonian Kroon',
568 1 => 'EEK',
569 2 => 2,
570 3 => 0,
571 ),
572 'ETB' => array(
573 0 => 'Ethiopian Birr',
574 1 => 'ETB',
575 2 => 2,
576 3 => 0,
577 ),
578 'EUR' => array(
579 0 => 'Euro',
580 1 => '€',
581 2 => 2,
582 3 => 0,
583 ),
584 'XBA' => array(
585 0 => 'European Composite Unit',
586 1 => 'XBA',
587 2 => 2,
588 3 => 0,
589 ),
590 'XEU' => array(
591 0 => 'European Currency Unit',
592 1 => 'XEU',
593 2 => 2,
594 3 => 0,
595 ),
596 'XBB' => array(
597 0 => 'European Monetary Unit',
598 1 => 'XBB',
599 2 => 2,
600 3 => 0,
601 ),
602 'XBC' => array(
603 0 => 'European Unit of Account (XBC)',
604 1 => 'XBC',
605 2 => 2,
606 3 => 0,
607 ),
608 'XBD' => array(
609 0 => 'European Unit of Account (XBD)',
610 1 => 'XBD',
611 2 => 2,
612 3 => 0,
613 ),
614 'FKP' => array(
615 0 => 'Falkland Islands Pound',
616 1 => 'FKP',
617 2 => 2,
618 3 => 0,
619 ),
620 'FJD' => array(
621 0 => 'Fijian Dollar',
622 1 => 'FJD',
623 2 => 2,
624 3 => 0,
625 ),
626 'FIM' => array(
627 0 => 'Finnish Markka',
628 1 => 'FIM',
629 2 => 2,
630 3 => 0,
631 ),
632 'FRF' => array(
633 0 => 'French Franc',
634 1 => 'FRF',
635 2 => 2,
636 3 => 0,
637 ),
638 'XFO' => array(
639 0 => 'French Gold Franc',
640 1 => 'XFO',
641 2 => 2,
642 3 => 0,
643 ),
644 'XFU' => array(
645 0 => 'French UIC-Franc',
646 1 => 'XFU',
647 2 => 2,
648 3 => 0,
649 ),
650 'GMD' => array(
651 0 => 'Gambian Dalasi',
652 1 => 'GMD',
653 2 => 2,
654 3 => 0,
655 ),
656 'GEK' => array(
657 0 => 'Georgian Kupon Larit',
658 1 => 'GEK',
659 2 => 2,
660 3 => 0,
661 ),
662 'GEL' => array(
663 0 => 'Georgian Lari',
664 1 => 'GEL',
665 2 => 2,
666 3 => 0,
667 ),
668 'DEM' => array(
669 0 => 'German Mark',
670 1 => 'DEM',
671 2 => 2,
672 3 => 0,
673 ),
674 'GHS' => array(
675 0 => 'Ghanaian Cedi',
676 1 => 'GHS',
677 2 => 2,
678 3 => 0,
679 ),
680 'GHC' => array(
681 0 => 'Ghanaian Cedi (1979-2007)',
682 1 => 'GHC',
683 2 => 2,
684 3 => 0,
685 ),
686 'GIP' => array(
687 0 => 'Gibraltar Pound',
688 1 => 'GIP',
689 2 => 2,
690 3 => 0,
691 ),
692 'XAU' => array(
693 0 => 'Gold',
694 1 => 'XAU',
695 2 => 2,
696 3 => 0,
697 ),
698 'GRD' => array(
699 0 => 'Greek Drachma',
700 1 => 'GRD',
701 2 => 2,
702 3 => 0,
703 ),
704 'GTQ' => array(
705 0 => 'Guatemalan Quetzal',
706 1 => 'GTQ',
707 2 => 2,
708 3 => 0,
709 ),
710 'GWP' => array(
711 0 => 'Guinea-Bissau Peso',
712 1 => 'GWP',
713 2 => 2,
714 3 => 0,
715 ),
716 'GNF' => array(
717 0 => 'Guinean Franc',
718 1 => 'GNF',
719 2 => 0,
720 3 => 0,
721 ),
722 'GNS' => array(
723 0 => 'Guinean Syli',
724 1 => 'GNS',
725 2 => 2,
726 3 => 0,
727 ),
728 'GYD' => array(
729 0 => 'Guyanaese Dollar',
730 1 => 'GYD',
731 2 => 0,
732 3 => 0,
733 ),
734 'HTG' => array(
735 0 => 'Haitian Gourde',
736 1 => 'HTG',
737 2 => 2,
738 3 => 0,
739 ),
740 'HNL' => array(
741 0 => 'Honduran Lempira',
742 1 => 'HNL',
743 2 => 2,
744 3 => 0,
745 ),
746 'HKD' => array(
747 0 => 'Hong Kong Dollar',
748 1 => 'HK$',
749 2 => 2,
750 3 => 0,
751 ),
752 'HUF' => array(
753 0 => 'Hungarian Forint',
754 1 => 'HUF',
755 2 => 0,
756 3 => 0,
757 ),
758 'ISK' => array(
759 0 => 'Icelandic Króna',
760 1 => 'ISK',
761 2 => 0,
762 3 => 0,
763 ),
764 'ISJ' => array(
765 0 => 'Icelandic Króna (1918-1981)',
766 1 => 'ISJ',
767 2 => 2,
768 3 => 0,
769 ),
770 'INR' => array(
771 0 => 'Indian Rupee',
772 1 => '₹',
773 2 => 2,
774 3 => 0,
775 ),
776 'IDR' => array(
777 0 => 'Indonesian Rupiah',
778 1 => 'IDR',
779 2 => 0,
780 3 => 0,
781 ),
782 'IRR' => array(
783 0 => 'Iranian Rial',
784 1 => 'IRR',
785 2 => 0,
786 3 => 0,
787 ),
788 'IQD' => array(
789 0 => 'Iraqi Dinar',
790 1 => 'IQD',
791 2 => 0,
792 3 => 0,
793 ),
794 'IEP' => array(
795 0 => 'Irish Pound',
796 1 => 'IEP',
797 2 => 2,
798 3 => 0,
799 ),
800 'ILS' => array(
801 0 => 'Israeli New Sheqel',
802 1 => '₪',
803 2 => 2,
804 3 => 0,
805 ),
806 'ILP' => array(
807 0 => 'Israeli Pound',
808 1 => 'ILP',
809 2 => 2,
810 3 => 0,
811 ),
812 'ILR' => array(
813 0 => 'Israeli Sheqel (1980-1985)',
814 1 => 'ILR',
815 2 => 2,
816 3 => 0,
817 ),
818 'ITL' => array(
819 0 => 'Italian Lira',
820 1 => 'ITL',
821 2 => 0,
822 3 => 0,
823 ),
824 'JMD' => array(
825 0 => 'Jamaican Dollar',
826 1 => 'JMD',
827 2 => 2,
828 3 => 0,
829 ),
830 'JPY' => array(
831 0 => 'Japanese Yen',
832 1 => 'Â¥',
833 2 => 0,
834 3 => 0,
835 ),
836 'JOD' => array(
837 0 => 'Jordanian Dinar',
838 1 => 'JOD',
839 2 => 3,
840 3 => 0,
841 ),
842 'KZT' => array(
843 0 => 'Kazakhstani Tenge',
844 1 => 'KZT',
845 2 => 2,
846 3 => 0,
847 ),
848 'KES' => array(
849 0 => 'Kenyan Shilling',
850 1 => 'KES',
851 2 => 2,
852 3 => 0,
853 ),
854 'KWD' => array(
855 0 => 'Kuwaiti Dinar',
856 1 => 'KWD',
857 2 => 3,
858 3 => 0,
859 ),
860 'KGS' => array(
861 0 => 'Kyrgystani Som',
862 1 => 'KGS',
863 2 => 2,
864 3 => 0,
865 ),
866 'LAK' => array(
867 0 => 'Laotian Kip',
868 1 => 'LAK',
869 2 => 0,
870 3 => 0,
871 ),
872 'LVL' => array(
873 0 => 'Latvian Lats',
874 1 => 'LVL',
875 2 => 2,
876 3 => 0,
877 ),
878 'LVR' => array(
879 0 => 'Latvian Ruble',
880 1 => 'LVR',
881 2 => 2,
882 3 => 0,
883 ),
884 'LBP' => array(
885 0 => 'Lebanese Pound',
886 1 => 'LBP',
887 2 => 0,
888 3 => 0,
889 ),
890 'LSL' => array(
891 0 => 'Lesotho Loti',
892 1 => 'LSL',
893 2 => 2,
894 3 => 0,
895 ),
896 'LRD' => array(
897 0 => 'Liberian Dollar',
898 1 => 'LRD',
899 2 => 2,
900 3 => 0,
901 ),
902 'LYD' => array(
903 0 => 'Libyan Dinar',
904 1 => 'LYD',
905 2 => 3,
906 3 => 0,
907 ),
908 'LTL' => array(
909 0 => 'Lithuanian Litas',
910 1 => 'LTL',
911 2 => 2,
912 3 => 0,
913 ),
914 'LTT' => array(
915 0 => 'Lithuanian Talonas',
916 1 => 'LTT',
917 2 => 2,
918 3 => 0,
919 ),
920 'LUL' => array(
921 0 => 'Luxembourg Financial Franc',
922 1 => 'LUL',
923 2 => 2,
924 3 => 0,
925 ),
926 'LUC' => array(
927 0 => 'Luxembourgian Convertible Franc',
928 1 => 'LUC',
929 2 => 2,
930 3 => 0,
931 ),
932 'LUF' => array(
933 0 => 'Luxembourgian Franc',
934 1 => 'LUF',
935 2 => 0,
936 3 => 0,
937 ),
938 'MOP' => array(
939 0 => 'Macanese Pataca',
940 1 => 'MOP',
941 2 => 2,
942 3 => 0,
943 ),
944 'MKD' => array(
945 0 => 'Macedonian Denar',
946 1 => 'MKD',
947 2 => 2,
948 3 => 0,
949 ),
950 'MKN' => array(
951 0 => 'Macedonian Denar (1992-1993)',
952 1 => 'MKN',
953 2 => 2,
954 3 => 0,
955 ),
956 'MGA' => array(
957 0 => 'Malagasy Ariary',
958 1 => 'MGA',
959 2 => 0,
960 3 => 0,
961 ),
962 'MGF' => array(
963 0 => 'Malagasy Franc',
964 1 => 'MGF',
965 2 => 0,
966 3 => 0,
967 ),
968 'MWK' => array(
969 0 => 'Malawian Kwacha',
970 1 => 'MWK',
971 2 => 2,
972 3 => 0,
973 ),
974 'MYR' => array(
975 0 => 'Malaysian Ringgit',
976 1 => 'MYR',
977 2 => 2,
978 3 => 0,
979 ),
980 'MVR' => array(
981 0 => 'Maldivian Rufiyaa',
982 1 => 'MVR',
983 2 => 2,
984 3 => 0,
985 ),
986 'MVP' => array(
987 0 => 'Maldivian Rupee',
988 1 => 'MVP',
989 2 => 2,
990 3 => 0,
991 ),
992 'MLF' => array(
993 0 => 'Malian Franc',
994 1 => 'MLF',
995 2 => 2,
996 3 => 0,
997 ),
998 'MTL' => array(
999 0 => 'Maltese Lira',
1000 1 => 'MTL',
1001 2 => 2,
1002 3 => 0,
1003 ),
1004 'MTP' => array(
1005 0 => 'Maltese Pound',
1006 1 => 'MTP',
1007 2 => 2,
1008 3 => 0,
1009 ),
1010 'MRO' => array(
1011 0 => 'Mauritanian Ouguiya',
1012 1 => 'MRO',
1013 2 => 0,
1014 3 => 0,
1015 ),
1016 'MUR' => array(
1017 0 => 'Mauritian Rupee',
1018 1 => 'MUR',
1019 2 => 0,
1020 3 => 0,
1021 ),
1022 'MXV' => array(
1023 0 => 'Mexican Investment Unit',
1024 1 => 'MXV',
1025 2 => 2,
1026 3 => 0,
1027 ),
1028 'MXN' => array(
1029 0 => 'Mexican Peso',
1030 1 => 'MX$',
1031 2 => 2,
1032 3 => 0,
1033 ),
1034 'MXP' => array(
1035 0 => 'Mexican Silver Peso (1861-1992)',
1036 1 => 'MXP',
1037 2 => 2,
1038 3 => 0,
1039 ),
1040 'MDC' => array(
1041 0 => 'Moldovan Cupon',
1042 1 => 'MDC',
1043 2 => 2,
1044 3 => 0,
1045 ),
1046 'MDL' => array(
1047 0 => 'Moldovan Leu',
1048 1 => 'MDL',
1049 2 => 2,
1050 3 => 0,
1051 ),
1052 'MCF' => array(
1053 0 => 'Monegasque Franc',
1054 1 => 'MCF',
1055 2 => 2,
1056 3 => 0,
1057 ),
1058 'MNT' => array(
1059 0 => 'Mongolian Tugrik',
1060 1 => 'MNT',
1061 2 => 0,
1062 3 => 0,
1063 ),
1064 'MAD' => array(
1065 0 => 'Moroccan Dirham',
1066 1 => 'MAD',
1067 2 => 2,
1068 3 => 0,
1069 ),
1070 'MAF' => array(
1071 0 => 'Moroccan Franc',
1072 1 => 'MAF',
1073 2 => 2,
1074 3 => 0,
1075 ),
1076 'MZE' => array(
1077 0 => 'Mozambican Escudo',
1078 1 => 'MZE',
1079 2 => 2,
1080 3 => 0,
1081 ),
1082 'MZN' => array(
1083 0 => 'Mozambican Metical',
1084 1 => 'MZN',
1085 2 => 2,
1086 3 => 0,
1087 ),
1088 'MZM' => array(
1089 0 => 'Mozambican Metical (1980-2006)',
1090 1 => 'MZM',
1091 2 => 2,
1092 3 => 0,
1093 ),
1094 'MMK' => array(
1095 0 => 'Myanma Kyat',
1096 1 => 'MMK',
1097 2 => 0,
1098 3 => 0,
1099 ),
1100 'NAD' => array(
1101 0 => 'Namibian Dollar',
1102 1 => 'NAD',
1103 2 => 2,
1104 3 => 0,
1105 ),
1106 'NPR' => array(
1107 0 => 'Nepalese Rupee',
1108 1 => 'NPR',
1109 2 => 2,
1110 3 => 0,
1111 ),
1112 'ANG' => array(
1113 0 => 'Netherlands Antillean Guilder',
1114 1 => 'ANG',
1115 2 => 2,
1116 3 => 0,
1117 ),
1118 'TWD' => array(
1119 0 => 'New Taiwan Dollar',
1120 1 => 'NT$',
1121 2 => 2,
1122 3 => 0,
1123 ),
1124 'NZD' => array(
1125 0 => 'New Zealand Dollar',
1126 1 => 'NZ$',
1127 2 => 2,
1128 3 => 0,
1129 ),
1130 'NIO' => array(
1131 0 => 'Nicaraguan Córdoba',
1132 1 => 'NIO',
1133 2 => 2,
1134 3 => 0,
1135 ),
1136 'NIC' => array(
1137 0 => 'Nicaraguan Córdoba (1988-1991)',
1138 1 => 'NIC',
1139 2 => 2,
1140 3 => 0,
1141 ),
1142 'NGN' => array(
1143 0 => 'Nigerian Naira',
1144 1 => 'NGN',
1145 2 => 2,
1146 3 => 0,
1147 ),
1148 'KPW' => array(
1149 0 => 'North Korean Won',
1150 1 => 'KPW',
1151 2 => 0,
1152 3 => 0,
1153 ),
1154 'NOK' => array(
1155 0 => 'Norwegian Krone',
1156 1 => 'NOK',
1157 2 => 2,
1158 3 => 0,
1159 ),
1160 'OMR' => array(
1161 0 => 'Omani Rial',
1162 1 => 'OMR',
1163 2 => 3,
1164 3 => 0,
1165 ),
1166 'PKR' => array(
1167 0 => 'Pakistani Rupee',
1168 1 => 'PKR',
1169 2 => 0,
1170 3 => 0,
1171 ),
1172 'XPD' => array(
1173 0 => 'Palladium',
1174 1 => 'XPD',
1175 2 => 2,
1176 3 => 0,
1177 ),
1178 'PAB' => array(
1179 0 => 'Panamanian Balboa',
1180 1 => 'PAB',
1181 2 => 2,
1182 3 => 0,
1183 ),
1184 'PGK' => array(
1185 0 => 'Papua New Guinean Kina',
1186 1 => 'PGK',
1187 2 => 2,
1188 3 => 0,
1189 ),
1190 'PYG' => array(
1191 0 => 'Paraguayan Guarani',
1192 1 => 'PYG',
1193 2 => 0,
1194 3 => 0,
1195 ),
1196 'PEI' => array(
1197 0 => 'Peruvian Inti',
1198 1 => 'PEI',
1199 2 => 2,
1200 3 => 0,
1201 ),
1202 'PEN' => array(
1203 0 => 'Peruvian Nuevo Sol',
1204 1 => 'PEN',
1205 2 => 2,
1206 3 => 0,
1207 ),
1208 'PES' => array(
1209 0 => 'Peruvian Sol (1863-1965)',
1210 1 => 'PES',
1211 2 => 2,
1212 3 => 0,
1213 ),
1214 'PHP' => array(
1215 0 => 'Philippine Peso',
1216 1 => 'PHP',
1217 2 => 2,
1218 3 => 0,
1219 ),
1220 'XPT' => array(
1221 0 => 'Platinum',
1222 1 => 'XPT',
1223 2 => 2,
1224 3 => 0,
1225 ),
1226 'PLN' => array(
1227 0 => 'Polish Zloty',
1228 1 => 'PLN',
1229 2 => 2,
1230 3 => 0,
1231 ),
1232 'PLZ' => array(
1233 0 => 'Polish Zloty (1950-1995)',
1234 1 => 'PLZ',
1235 2 => 2,
1236 3 => 0,
1237 ),
1238 'PTE' => array(
1239 0 => 'Portuguese Escudo',
1240 1 => 'PTE',
1241 2 => 2,
1242 3 => 0,
1243 ),
1244 'GWE' => array(
1245 0 => 'Portuguese Guinea Escudo',
1246 1 => 'GWE',
1247 2 => 2,
1248 3 => 0,
1249 ),
1250 'QAR' => array(
1251 0 => 'Qatari Rial',
1252 1 => 'QAR',
1253 2 => 2,
1254 3 => 0,
1255 ),
1256 'RHD' => array(
1257 0 => 'Rhodesian Dollar',
1258 1 => 'RHD',
1259 2 => 2,
1260 3 => 0,
1261 ),
1262 'XRE' => array(
1263 0 => 'RINET Funds',
1264 1 => 'XRE',
1265 2 => 2,
1266 3 => 0,
1267 ),
1268 'RON' => array(
1269 0 => 'Romanian Leu',
1270 1 => 'RON',
1271 2 => 2,
1272 3 => 0,
1273 ),
1274 'ROL' => array(
1275 0 => 'Romanian Leu (1952-2006)',
1276 1 => 'ROL',
1277 2 => 2,
1278 3 => 0,
1279 ),
1280 'RUB' => array(
1281 0 => 'Russian Ruble',
1282 1 => 'RUB',
1283 2 => 2,
1284 3 => 0,
1285 ),
1286 'RUR' => array(
1287 0 => 'Russian Ruble (1991-1998)',
1288 1 => 'RUR',
1289 2 => 2,
1290 3 => 0,
1291 ),
1292 'RWF' => array(
1293 0 => 'Rwandan Franc',
1294 1 => 'RWF',
1295 2 => 0,
1296 3 => 0,
1297 ),
1298 'SHP' => array(
1299 0 => 'Saint Helena Pound',
1300 1 => 'SHP',
1301 2 => 2,
1302 3 => 0,
1303 ),
1304 'SVC' => array(
1305 0 => 'Salvadoran Colón',
1306 1 => 'SVC',
1307 2 => 2,
1308 3 => 0,
1309 ),
1310 'WST' => array(
1311 0 => 'Samoan Tala',
1312 1 => 'WST',
1313 2 => 2,
1314 3 => 0,
1315 ),
1316 'STD' => array(
1317 0 => 'São Tomé and Príncipe Dobra',
1318 1 => 'STD',
1319 2 => 0,
1320 3 => 0,
1321 ),
1322 'SAR' => array(
1323 0 => 'Saudi Riyal',
1324 1 => 'SAR',
1325 2 => 2,
1326 3 => 0,
1327 ),
1328 'RSD' => array(
1329 0 => 'Serbian Dinar',
1330 1 => 'RSD',
1331 2 => 0,
1332 3 => 0,
1333 ),
1334 'CSD' => array(
1335 0 => 'Serbian Dinar (2002-2006)',
1336 1 => 'CSD',
1337 2 => 2,
1338 3 => 0,
1339 ),
1340 'SCR' => array(
1341 0 => 'Seychellois Rupee',
1342 1 => 'SCR',
1343 2 => 2,
1344 3 => 0,
1345 ),
1346 'SLL' => array(
1347 0 => 'Sierra Leonean Leone',
1348 1 => 'SLL',
1349 2 => 0,
1350 3 => 0,
1351 ),
1352 'XAG' => array(
1353 0 => 'Silver',
1354 1 => 'XAG',
1355 2 => 2,
1356 3 => 0,
1357 ),
1358 'SGD' => array(
1359 0 => 'Singapore Dollar',
1360 1 => 'SGD',
1361 2 => 2,
1362 3 => 0,
1363 ),
1364 'SKK' => array(
1365 0 => 'Slovak Koruna',
1366 1 => 'SKK',
1367 2 => 2,
1368 3 => 0,
1369 ),
1370 'SIT' => array(
1371 0 => 'Slovenian Tolar',
1372 1 => 'SIT',
1373 2 => 2,
1374 3 => 0,
1375 ),
1376 'SBD' => array(
1377 0 => 'Solomon Islands Dollar',
1378 1 => 'SBD',
1379 2 => 2,
1380 3 => 0,
1381 ),
1382 'SOS' => array(
1383 0 => 'Somali Shilling',
1384 1 => 'SOS',
1385 2 => 0,
1386 3 => 0,
1387 ),
1388 'ZAR' => array(
1389 0 => 'South African Rand',
1390 1 => 'ZAR',
1391 2 => 2,
1392 3 => 0,
1393 ),
1394 'ZAL' => array(
1395 0 => 'South African Rand (financial)',
1396 1 => 'ZAL',
1397 2 => 2,
1398 3 => 0,
1399 ),
1400 'KRH' => array(
1401 0 => 'South Korean Hwan (1953-1962)',
1402 1 => 'KRH',
1403 2 => 2,
1404 3 => 0,
1405 ),
1406 'KRW' => array(
1407 0 => 'South Korean Won',
1408 1 => 'â‚©',
1409 2 => 0,
1410 3 => 0,
1411 ),
1412 'KRO' => array(
1413 0 => 'South Korean Won (1945-1953)',
1414 1 => 'KRO',
1415 2 => 2,
1416 3 => 0,
1417 ),
1418 'SSP' => array(
1419 0 => 'South Sudanese Pound',
1420 1 => 'SSP',
1421 2 => 2,
1422 3 => 0,
1423 ),
1424 'SUR' => array(
1425 0 => 'Soviet Rouble',
1426 1 => 'SUR',
1427 2 => 2,
1428 3 => 0,
1429 ),
1430 'ESP' => array(
1431 0 => 'Spanish Peseta',
1432 1 => 'ESP',
1433 2 => 0,
1434 3 => 0,
1435 ),
1436 'ESA' => array(
1437 0 => 'Spanish Peseta (A account)',
1438 1 => 'ESA',
1439 2 => 2,
1440 3 => 0,
1441 ),
1442 'ESB' => array(
1443 0 => 'Spanish Peseta (convertible account)',
1444 1 => 'ESB',
1445 2 => 2,
1446 3 => 0,
1447 ),
1448 'XDR' => array(
1449 0 => 'Special Drawing Rights',
1450 1 => 'XDR',
1451 2 => 2,
1452 3 => 0,
1453 ),
1454 'LKR' => array(
1455 0 => 'Sri Lankan Rupee',
1456 1 => 'LKR',
1457 2 => 2,
1458 3 => 0,
1459 ),
1460 'XSU' => array(
1461 0 => 'Sucre',
1462 1 => 'XSU',
1463 2 => 2,
1464 3 => 0,
1465 ),
1466 'SDD' => array(
1467 0 => 'Sudanese Dinar (1992-2007)',
1468 1 => 'SDD',
1469 2 => 2,
1470 3 => 0,
1471 ),
1472 'SDG' => array(
1473 0 => 'Sudanese Pound',
1474 1 => 'SDG',
1475 2 => 2,
1476 3 => 0,
1477 ),
1478 'SDP' => array(
1479 0 => 'Sudanese Pound (1957-1998)',
1480 1 => 'SDP',
1481 2 => 2,
1482 3 => 0,
1483 ),
1484 'SRD' => array(
1485 0 => 'Surinamese Dollar',
1486 1 => 'SRD',
1487 2 => 2,
1488 3 => 0,
1489 ),
1490 'SRG' => array(
1491 0 => 'Surinamese Guilder',
1492 1 => 'SRG',
1493 2 => 2,
1494 3 => 0,
1495 ),
1496 'SZL' => array(
1497 0 => 'Swazi Lilangeni',
1498 1 => 'SZL',
1499 2 => 2,
1500 3 => 0,
1501 ),
1502 'SEK' => array(
1503 0 => 'Swedish Krona',
1504 1 => 'SEK',
1505 2 => 2,
1506 3 => 0,
1507 ),
1508 'CHF' => array(
1509 0 => 'Swiss Franc',
1510 1 => 'CHF',
1511 2 => 2,
1512 3 => 5,
1513 ),
1514 'SYP' => array(
1515 0 => 'Syrian Pound',
1516 1 => 'SYP',
1517 2 => 0,
1518 3 => 0,
1519 ),
1520 'TJR' => array(
1521 0 => 'Tajikistani Ruble',
1522 1 => 'TJR',
1523 2 => 2,
1524 3 => 0,
1525 ),
1526 'TJS' => array(
1527 0 => 'Tajikistani Somoni',
1528 1 => 'TJS',
1529 2 => 2,
1530 3 => 0,
1531 ),
1532 'TZS' => array(
1533 0 => 'Tanzanian Shilling',
1534 1 => 'TZS',
1535 2 => 0,
1536 3 => 0,
1537 ),
1538 'XTS' => array(
1539 0 => 'Testing Currency Code',
1540 1 => 'XTS',
1541 2 => 2,
1542 3 => 0,
1543 ),
1544 'THB' => array(
1545 0 => 'Thai Baht',
1546 1 => '฿',
1547 2 => 2,
1548 3 => 0,
1549 ),
1550 'TPE' => array(
1551 0 => 'Timorese Escudo',
1552 1 => 'TPE',
1553 2 => 2,
1554 3 => 0,
1555 ),
1556 'TOP' => array(
1557 0 => 'Tongan Paʻanga',
1558 1 => 'TOP',
1559 2 => 2,
1560 3 => 0,
1561 ),
1562 'TTD' => array(
1563 0 => 'Trinidad and Tobago Dollar',
1564 1 => 'TTD',
1565 2 => 2,
1566 3 => 0,
1567 ),
1568 'TND' => array(
1569 0 => 'Tunisian Dinar',
1570 1 => 'TND',
1571 2 => 3,
1572 3 => 0,
1573 ),
1574 'TRY' => array(
1575 0 => 'Turkish Lira',
1576 1 => 'TRY',
1577 2 => 2,
1578 3 => 0,
1579 ),
1580 'TRL' => array(
1581 0 => 'Turkish Lira (1922-2005)',
1582 1 => 'TRL',
1583 2 => 0,
1584 3 => 0,
1585 ),
1586 'TMT' => array(
1587 0 => 'Turkmenistani Manat',
1588 1 => 'TMT',
1589 2 => 2,
1590 3 => 0,
1591 ),
1592 'TMM' => array(
1593 0 => 'Turkmenistani Manat (1993-2009)',
1594 1 => 'TMM',
1595 2 => 0,
1596 3 => 0,
1597 ),
1598 'UGX' => array(
1599 0 => 'Ugandan Shilling',
1600 1 => 'UGX',
1601 2 => 0,
1602 3 => 0,
1603 ),
1604 'UGS' => array(
1605 0 => 'Ugandan Shilling (1966-1987)',
1606 1 => 'UGS',
1607 2 => 2,
1608 3 => 0,
1609 ),
1610 'UAH' => array(
1611 0 => 'Ukrainian Hryvnia',
1612 1 => 'UAH',
1613 2 => 2,
1614 3 => 0,
1615 ),
1616 'UAK' => array(
1617 0 => 'Ukrainian Karbovanets',
1618 1 => 'UAK',
1619 2 => 2,
1620 3 => 0,
1621 ),
1622 'AED' => array(
1623 0 => 'United Arab Emirates Dirham',
1624 1 => 'AED',
1625 2 => 2,
1626 3 => 0,
1627 ),
1628 'XXX' => array(
1629 0 => 'Unknown Currency',
1630 1 => 'XXX',
1631 2 => 2,
1632 3 => 0,
1633 ),
1634 'UYU' => array(
1635 0 => 'Uruguayan Peso',
1636 1 => 'UYU',
1637 2 => 2,
1638 3 => 0,
1639 ),
1640 'UYP' => array(
1641 0 => 'Uruguayan Peso (1975-1993)',
1642 1 => 'UYP',
1643 2 => 2,
1644 3 => 0,
1645 ),
1646 'UYI' => array(
1647 0 => 'Uruguayan Peso (Indexed Units)',
1648 1 => 'UYI',
1649 2 => 2,
1650 3 => 0,
1651 ),
1652 'USD' => array(
1653 0 => 'US Dollar',
1654 1 => '$',
1655 2 => 2,
1656 3 => 0,
1657 ),
1658 'USN' => array(
1659 0 => 'US Dollar (Next day)',
1660 1 => 'USN',
1661 2 => 2,
1662 3 => 0,
1663 ),
1664 'USS' => array(
1665 0 => 'US Dollar (Same day)',
1666 1 => 'USS',
1667 2 => 2,
1668 3 => 0,
1669 ),
1670 'UZS' => array(
1671 0 => 'Uzbekistan Som',
1672 1 => 'UZS',
1673 2 => 0,
1674 3 => 0,
1675 ),
1676 'VUV' => array(
1677 0 => 'Vanuatu Vatu',
1678 1 => 'VUV',
1679 2 => 0,
1680 3 => 0,
1681 ),
1682 'VEF' => array(
1683 0 => 'Venezuelan Bolívar',
1684 1 => 'VEF',
1685 2 => 2,
1686 3 => 0,
1687 ),
1688 'VEB' => array(
1689 0 => 'Venezuelan Bolívar (1871-2008)',
1690 1 => 'VEB',
1691 2 => 2,
1692 3 => 0,
1693 ),
1694 'VND' => array(
1695 0 => 'Vietnamese Dong',
1696 1 => 'â‚«',
1697 2 => 0,
1698 3 => 0,
1699 ),
1700 'VNN' => array(
1701 0 => 'Vietnamese Dong (1978-1985)',
1702 1 => 'VNN',
1703 2 => 2,
1704 3 => 0,
1705 ),
1706 'CHE' => array(
1707 0 => 'WIR Euro',
1708 1 => 'CHE',
1709 2 => 2,
1710 3 => 0,
1711 ),
1712 'CHW' => array(
1713 0 => 'WIR Franc',
1714 1 => 'CHW',
1715 2 => 2,
1716 3 => 0,
1717 ),
1718 'YDD' => array(
1719 0 => 'Yemeni Dinar',
1720 1 => 'YDD',
1721 2 => 2,
1722 3 => 0,
1723 ),
1724 'YER' => array(
1725 0 => 'Yemeni Rial',
1726 1 => 'YER',
1727 2 => 0,
1728 3 => 0,
1729 ),
1730 'YUN' => array(
1731 0 => 'Yugoslavian Convertible Dinar (1990-1992)',
1732 1 => 'YUN',
1733 2 => 2,
1734 3 => 0,
1735 ),
1736 'YUD' => array(
1737 0 => 'Yugoslavian Hard Dinar (1966-1990)',
1738 1 => 'YUD',
1739 2 => 2,
1740 3 => 0,
1741 ),
1742 'YUM' => array(
1743 0 => 'Yugoslavian New Dinar (1994-2002)',
1744 1 => 'YUM',
1745 2 => 2,
1746 3 => 0,
1747 ),
1748 'YUR' => array(
1749 0 => 'Yugoslavian Reformed Dinar (1992-1993)',
1750 1 => 'YUR',
1751 2 => 2,
1752 3 => 0,
1753 ),
1754 'ZRN' => array(
1755 0 => 'Zairean New Zaire (1993-1998)',
1756 1 => 'ZRN',
1757 2 => 2,
1758 3 => 0,
1759 ),
1760 'ZRZ' => array(
1761 0 => 'Zairean Zaire (1971-1993)',
1762 1 => 'ZRZ',
1763 2 => 2,
1764 3 => 0,
1765 ),
1766 'ZMK' => array(
1767 0 => 'Zambian Kwacha',
1768 1 => 'ZMK',
1769 2 => 0,
1770 3 => 0,
1771 ),
1772 'ZWD' => array(
1773 0 => 'Zimbabwean Dollar (1980-2008)',
1774 1 => 'ZWD',
1775 2 => 0,
1776 3 => 0,
1777 ),
1778 'ZWR' => array(
1779 0 => 'Zimbabwean Dollar (2008)',
1780 1 => 'ZWR',
1781 2 => 2,
1782 3 => 0,
1783 ),
1784 'ZWL' => array(
1785 0 => 'Zimbabwean Dollar (2009)',
1786 1 => 'ZWL',
1787 2 => 2,
1788 3 => 0,
1789 ),
1790 ),
1791);
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/lang/en.php b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/lang/en.php
new file mode 100644
index 00000000..9d2ff140
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/lang/en.php
@@ -0,0 +1,750 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12return array(
13 'Languages' => array(
14 'ab' => 'Abkhazian',
15 'ace' => 'Achinese',
16 'ach' => 'Acoli',
17 'ada' => 'Adangme',
18 'ady' => 'Adyghe',
19 'aa' => 'Afar',
20 'afh' => 'Afrihili',
21 'af' => 'Afrikaans',
22 'afa' => 'Afro-Asiatic Language',
23 'agq' => 'Aghem',
24 'ain' => 'Ainu',
25 'ak' => 'Akan',
26 'akk' => 'Akkadian',
27 'bss' => 'Akoose',
28 'sq' => 'Albanian',
29 'ale' => 'Aleut',
30 'alg' => 'Algonquian Language',
31 'tut' => 'Altaic Language',
32 'am' => 'Amharic',
33 'egy' => 'Ancient Egyptian',
34 'grc' => 'Ancient Greek',
35 'anp' => 'Angika',
36 'apa' => 'Apache Language',
37 'ar' => 'Arabic',
38 'an' => 'Aragonese',
39 'arc' => 'Aramaic',
40 'arp' => 'Arapaho',
41 'arw' => 'Arawak',
42 'hy' => 'Armenian',
43 'rup' => 'Aromanian',
44 'art' => 'Artificial Language',
45 'as' => 'Assamese',
46 'ast' => 'Asturian',
47 'asa' => 'Asu',
48 'ath' => 'Athapascan Language',
49 'cch' => 'Atsam',
50 'en_AU' => 'Australian English',
51 'aus' => 'Australian Language',
52 'de_AT' => 'Austrian German',
53 'map' => 'Austronesian Language',
54 'av' => 'Avaric',
55 'ae' => 'Avestan',
56 'awa' => 'Awadhi',
57 'ay' => 'Aymara',
58 'az' => 'Azerbaijani',
59 'ksf' => 'Bafia',
60 'bfd' => 'Bafut',
61 'ban' => 'Balinese',
62 'bat' => 'Baltic Language',
63 'bal' => 'Baluchi',
64 'bm' => 'Bambara',
65 'bai' => 'Bamileke Language',
66 'bax' => 'Bamun',
67 'bad' => 'Banda',
68 'bnt' => 'Bantu',
69 'bas' => 'Basaa',
70 'ba' => 'Bashkir',
71 'eu' => 'Basque',
72 'btk' => 'Batak',
73 'bej' => 'Beja',
74 'be' => 'Belarusian',
75 'bem' => 'Bemba',
76 'bez' => 'Bena',
77 'bn' => 'Bengali',
78 'ber' => 'Berber',
79 'bho' => 'Bhojpuri',
80 'bh' => 'Bihari',
81 'bik' => 'Bikol',
82 'bin' => 'Bini',
83 'bi' => 'Bislama',
84 'byn' => 'Blin',
85 'zbl' => 'Blissymbols',
86 'brx' => 'Bodo',
87 'bs' => 'Bosnian',
88 'bra' => 'Braj',
89 'pt_BR' => 'Brazilian Portuguese',
90 'br' => 'Breton',
91 'en_GB' => 'British English',
92 'bug' => 'Buginese',
93 'bg' => 'Bulgarian',
94 'bum' => 'Bulu',
95 'bua' => 'Buriat',
96 'my' => 'Burmese',
97 'cad' => 'Caddo',
98 'en_CA' => 'Canadian English',
99 'fr_CA' => 'Canadian French',
100 'yue' => 'Cantonese',
101 'car' => 'Carib',
102 'ca' => 'Catalan',
103 'cau' => 'Caucasian Language',
104 'cay' => 'Cayuga',
105 'ceb' => 'Cebuano',
106 'cel' => 'Celtic Language',
107 'cai' => 'Central American Indian Language',
108 'tzm' => 'Central Atlas Tamazight',
109 'shu' => 'Chadian Arabic',
110 'chg' => 'Chagatai',
111 'cmc' => 'Chamic Language',
112 'ch' => 'Chamorro',
113 'ce' => 'Chechen',
114 'chr' => 'Cherokee',
115 'chy' => 'Cheyenne',
116 'chb' => 'Chibcha',
117 'cgg' => 'Chiga',
118 'zh' => 'Chinese',
119 'chn' => 'Chinook Jargon',
120 'chp' => 'Chipewyan',
121 'cho' => 'Choctaw',
122 'cu' => 'Church Slavic',
123 'chk' => 'Chuukese',
124 'cv' => 'Chuvash',
125 'nwc' => 'Classical Newari',
126 'syc' => 'Classical Syriac',
127 'ksh' => 'Colognian',
128 'swb' => 'Comorian',
129 'swc' => 'Congo Swahili',
130 'cop' => 'Coptic',
131 'kw' => 'Cornish',
132 'co' => 'Corsican',
133 'cr' => 'Cree',
134 'mus' => 'Creek',
135 'crp' => 'Creole or Pidgin',
136 'crh' => 'Crimean Turkish',
137 'hr' => 'Croatian',
138 'cus' => 'Cushitic Language',
139 'cs' => 'Czech',
140 'dak' => 'Dakota',
141 'da' => 'Danish',
142 'dar' => 'Dargwa',
143 'day' => 'Dayak',
144 'dzg' => 'Dazaga',
145 'del' => 'Delaware',
146 'din' => 'Dinka',
147 'dv' => 'Divehi',
148 'doi' => 'Dogri',
149 'dgr' => 'Dogrib',
150 'dra' => 'Dravidian Language',
151 'dua' => 'Duala',
152 'nl' => 'Dutch',
153 'dyu' => 'Dyula',
154 'dz' => 'Dzongkha',
155 'frs' => 'Eastern Frisian',
156 'efi' => 'Efik',
157 'eka' => 'Ekajuk',
158 'elx' => 'Elamite',
159 'ebu' => 'Embu',
160 'en' => 'English',
161 'cpe' => 'English-based Creole or Pidgin',
162 'myv' => 'Erzya',
163 'eo' => 'Esperanto',
164 'et' => 'Estonian',
165 'pt_PT' => 'European Portuguese',
166 'es_ES' => 'European Spanish',
167 'ee' => 'Ewe',
168 'ewo' => 'Ewondo',
169 'fan' => 'Fang',
170 'fat' => 'Fanti',
171 'fo' => 'Faroese',
172 'fj' => 'Fijian',
173 'fil' => 'Filipino',
174 'fi' => 'Finnish',
175 'fiu' => 'Finno-Ugrian Language',
176 'nl_BE' => 'Flemish',
177 'fon' => 'Fon',
178 'fr' => 'French',
179 'cpf' => 'French-based Creole or Pidgin',
180 'fur' => 'Friulian',
181 'ff' => 'Fulah',
182 'gaa' => 'Ga',
183 'gl' => 'Galician',
184 'lg' => 'Ganda',
185 'gay' => 'Gayo',
186 'gba' => 'Gbaya',
187 'gez' => 'Geez',
188 'ka' => 'Georgian',
189 'de' => 'German',
190 'gem' => 'Germanic Language',
191 'bbj' => 'Ghomala',
192 'gil' => 'Gilbertese',
193 'gon' => 'Gondi',
194 'gor' => 'Gorontalo',
195 'got' => 'Gothic',
196 'grb' => 'Grebo',
197 'el' => 'Greek',
198 'gn' => 'Guarani',
199 'gu' => 'Gujarati',
200 'guz' => 'Gusii',
201 'gwi' => 'Gwichʼin',
202 'hai' => 'Haida',
203 'ht' => 'Haitian',
204 'ha' => 'Hausa',
205 'haw' => 'Hawaiian',
206 'he' => 'Hebrew',
207 'hz' => 'Herero',
208 'hil' => 'Hiligaynon',
209 'him' => 'Himachali',
210 'hi' => 'Hindi',
211 'ho' => 'Hiri Motu',
212 'hit' => 'Hittite',
213 'hmn' => 'Hmong',
214 'hu' => 'Hungarian',
215 'hup' => 'Hupa',
216 'iba' => 'Iban',
217 'ibb' => 'Ibibio',
218 'is' => 'Icelandic',
219 'io' => 'Ido',
220 'ig' => 'Igbo',
221 'ijo' => 'Ijo',
222 'ilo' => 'Iloko',
223 'smn' => 'Inari Sami',
224 'inc' => 'Indic Language',
225 'ine' => 'Indo-European Language',
226 'id' => 'Indonesian',
227 'inh' => 'Ingush',
228 'ia' => 'Interlingua',
229 'ie' => 'Interlingue',
230 'iu' => 'Inuktitut',
231 'ik' => 'Inupiaq',
232 'ira' => 'Iranian Language',
233 'ga' => 'Irish',
234 'iro' => 'Iroquoian Language',
235 'it' => 'Italian',
236 'ja' => 'Japanese',
237 'jv' => 'Javanese',
238 'kaj' => 'Jju',
239 'dyo' => 'Jola-Fonyi',
240 'jrb' => 'Judeo-Arabic',
241 'jpr' => 'Judeo-Persian',
242 'kbd' => 'Kabardian',
243 'kea' => 'Kabuverdianu',
244 'kab' => 'Kabyle',
245 'kac' => 'Kachin',
246 'kkj' => 'Kako',
247 'kl' => 'Kalaallisut',
248 'kln' => 'Kalenjin',
249 'xal' => 'Kalmyk',
250 'kam' => 'Kamba',
251 'kbl' => 'Kanembu',
252 'kn' => 'Kannada',
253 'kr' => 'Kanuri',
254 'kaa' => 'Kara-Kalpak',
255 'krc' => 'Karachay-Balkar',
256 'krl' => 'Karelian',
257 'kar' => 'Karen',
258 'ks' => 'Kashmiri',
259 'csb' => 'Kashubian',
260 'kaw' => 'Kawi',
261 'kk' => 'Kazakh',
262 'kha' => 'Khasi',
263 'km' => 'Khmer',
264 'khi' => 'Khoisan Language',
265 'kho' => 'Khotanese',
266 'ki' => 'Kikuyu',
267 'kmb' => 'Kimbundu',
268 'rw' => 'Kinyarwanda',
269 'ky' => 'Kirghiz',
270 'tlh' => 'Klingon',
271 'bkm' => 'Kom',
272 'kv' => 'Komi',
273 'kg' => 'Kongo',
274 'kok' => 'Konkani',
275 'ko' => 'Korean',
276 'kfo' => 'Koro',
277 'kos' => 'Kosraean',
278 'khq' => 'Koyra Chiini',
279 'ses' => 'Koyraboro Senni',
280 'kpe' => 'Kpelle',
281 'kro' => 'Kru',
282 'kj' => 'Kuanyama',
283 'kum' => 'Kumyk',
284 'ku' => 'Kurdish',
285 'kru' => 'Kurukh',
286 'kut' => 'Kutenai',
287 'nmg' => 'Kwasio',
288 'lad' => 'Ladino',
289 'lah' => 'Lahnda',
290 'lam' => 'Lamba',
291 'lag' => 'Langi',
292 'lo' => 'Lao',
293 'la' => 'Latin',
294 'es_419' => 'Latin American Spanish',
295 'lv' => 'Latvian',
296 'lez' => 'Lezghian',
297 'li' => 'Limburgish',
298 'ln' => 'Lingala',
299 'lt' => 'Lithuanian',
300 'jbo' => 'Lojban',
301 'nds' => 'Low German',
302 'dsb' => 'Lower Sorbian',
303 'loz' => 'Lozi',
304 'lu' => 'Luba-Katanga',
305 'lua' => 'Luba-Lulua',
306 'lui' => 'Luiseno',
307 'smj' => 'Lule Sami',
308 'lun' => 'Lunda',
309 'luo' => 'Luo',
310 'lb' => 'Luxembourgish',
311 'luy' => 'Luyia',
312 'mde' => 'Maba',
313 'mk' => 'Macedonian',
314 'jmc' => 'Machame',
315 'mad' => 'Madurese',
316 'maf' => 'Mafa',
317 'mag' => 'Magahi',
318 'mai' => 'Maithili',
319 'mak' => 'Makasar',
320 'mgh' => 'Makhuwa-Meetto',
321 'kde' => 'Makonde',
322 'mg' => 'Malagasy',
323 'ms' => 'Malay',
324 'ml' => 'Malayalam',
325 'mt' => 'Maltese',
326 'mnc' => 'Manchu',
327 'mdr' => 'Mandar',
328 'man' => 'Mandingo',
329 'mni' => 'Manipuri',
330 'mno' => 'Manobo Language',
331 'gv' => 'Manx',
332 'mi' => 'Maori',
333 'arn' => 'Mapuche',
334 'mr' => 'Marathi',
335 'chm' => 'Mari',
336 'mh' => 'Marshallese',
337 'mwr' => 'Marwari',
338 'mas' => 'Masai',
339 'myn' => 'Mayan Language',
340 'byv' => 'Medumba',
341 'men' => 'Mende',
342 'mer' => 'Meru',
343 'mgo' => 'Meta\'',
344 'mic' => 'Micmac',
345 'dum' => 'Middle Dutch',
346 'enm' => 'Middle English',
347 'frm' => 'Middle French',
348 'gmh' => 'Middle High German',
349 'mga' => 'Middle Irish',
350 'min' => 'Minangkabau',
351 'mwl' => 'Mirandese',
352 'mis' => 'Miscellaneous Language',
353 'lus' => 'Mizo',
354 'ar_001' => 'Modern Standard Arabic',
355 'moh' => 'Mohawk',
356 'mdf' => 'Moksha',
357 'mo' => 'Moldavian',
358 'mkh' => 'Mon-Khmer Language',
359 'lol' => 'Mongo',
360 'mn' => 'Mongolian',
361 'mfe' => 'Morisyen',
362 'mos' => 'Mossi',
363 'mun' => 'Munda Language',
364 'mua' => 'Mundang',
365 'mye' => 'Myene',
366 'nqo' => 'N’Ko',
367 'nah' => 'Nahuatl',
368 'naq' => 'Nama',
369 'na' => 'Nauru',
370 'nv' => 'Navajo',
371 'ng' => 'Ndonga',
372 'nap' => 'Neapolitan',
373 'ne' => 'Nepali',
374 'new' => 'Newari',
375 'sba' => 'Ngambay',
376 'nnh' => 'Ngiemboon',
377 'jgo' => 'Ngomba',
378 'nia' => 'Nias',
379 'nic' => 'Niger-Kordofanian Language',
380 'ssa' => 'Nilo-Saharan Language',
381 'niu' => 'Niuean',
382 'zxx' => 'No linguistic content',
383 'nog' => 'Nogai',
384 'nai' => 'North American Indian Language',
385 'nd' => 'North Ndebele',
386 'frr' => 'Northern Frisian',
387 'se' => 'Northern Sami',
388 'nso' => 'Northern Sotho',
389 'no' => 'Norwegian',
390 'nb' => 'Norwegian Bokmål',
391 'nn' => 'Norwegian Nynorsk',
392 'nub' => 'Nubian Language',
393 'nus' => 'Nuer',
394 'nym' => 'Nyamwezi',
395 'ny' => 'Nyanja',
396 'nyn' => 'Nyankole',
397 'tog' => 'Nyasa Tonga',
398 'nyo' => 'Nyoro',
399 'nzi' => 'Nzima',
400 'oc' => 'Occitan',
401 'oj' => 'Ojibwa',
402 'ang' => 'Old English',
403 'fro' => 'Old French',
404 'goh' => 'Old High German',
405 'sga' => 'Old Irish',
406 'non' => 'Old Norse',
407 'peo' => 'Old Persian',
408 'pro' => 'Old Provençal',
409 'or' => 'Oriya',
410 'om' => 'Oromo',
411 'osa' => 'Osage',
412 'os' => 'Ossetic',
413 'oto' => 'Otomian Language',
414 'ota' => 'Ottoman Turkish',
415 'pal' => 'Pahlavi',
416 'pau' => 'Palauan',
417 'pi' => 'Pali',
418 'pam' => 'Pampanga',
419 'pag' => 'Pangasinan',
420 'pap' => 'Papiamento',
421 'paa' => 'Papuan Language',
422 'ps' => 'Pashto',
423 'fa' => 'Persian',
424 'phi' => 'Philippine Language',
425 'phn' => 'Phoenician',
426 'pon' => 'Pohnpeian',
427 'pl' => 'Polish',
428 'pt' => 'Portuguese',
429 'cpp' => 'Portuguese-based Creole or Pidgin',
430 'pra' => 'Prakrit Language',
431 'pa' => 'Punjabi',
432 'qu' => 'Quechua',
433 'raj' => 'Rajasthani',
434 'rap' => 'Rapanui',
435 'rar' => 'Rarotongan',
436 'roa' => 'Romance Language',
437 'ro' => 'Romanian',
438 'rm' => 'Romansh',
439 'rom' => 'Romany',
440 'rof' => 'Rombo',
441 'root' => 'Root',
442 'rn' => 'Rundi',
443 'ru' => 'Russian',
444 'rwk' => 'Rwa',
445 'ssy' => 'Saho',
446 'sah' => 'Sakha',
447 'sal' => 'Salishan Language',
448 'sam' => 'Samaritan Aramaic',
449 'saq' => 'Samburu',
450 'smi' => 'Sami Language',
451 'sm' => 'Samoan',
452 'sad' => 'Sandawe',
453 'sg' => 'Sango',
454 'sbp' => 'Sangu',
455 'sa' => 'Sanskrit',
456 'sat' => 'Santali',
457 'sc' => 'Sardinian',
458 'sas' => 'Sasak',
459 'sco' => 'Scots',
460 'gd' => 'Scottish Gaelic',
461 'sel' => 'Selkup',
462 'sem' => 'Semitic Language',
463 'seh' => 'Sena',
464 'see' => 'Seneca',
465 'sr' => 'Serbian',
466 'sh' => 'Serbo-Croatian',
467 'srr' => 'Serer',
468 'ksb' => 'Shambala',
469 'shn' => 'Shan',
470 'sn' => 'Shona',
471 'ii' => 'Sichuan Yi',
472 'scn' => 'Sicilian',
473 'sid' => 'Sidamo',
474 'sgn' => 'Sign Language',
475 'bla' => 'Siksika',
476 'zh_Hans' => 'Simplified Chinese',
477 'sd' => 'Sindhi',
478 'si' => 'Sinhala',
479 'sit' => 'Sino-Tibetan Language',
480 'sio' => 'Siouan Language',
481 'sms' => 'Skolt Sami',
482 'den' => 'Slave',
483 'sla' => 'Slavic Language',
484 'sk' => 'Slovak',
485 'sl' => 'Slovenian',
486 'xog' => 'Soga',
487 'sog' => 'Sogdien',
488 'so' => 'Somali',
489 'son' => 'Songhai',
490 'snk' => 'Soninke',
491 'ckb' => 'Sorani Kurdish',
492 'wen' => 'Sorbian Language',
493 'sai' => 'South American Indian Language',
494 'nr' => 'South Ndebele',
495 'alt' => 'Southern Altai',
496 'sma' => 'Southern Sami',
497 'st' => 'Southern Sotho',
498 'es' => 'Spanish',
499 'srn' => 'Sranan Tongo',
500 'suk' => 'Sukuma',
501 'sux' => 'Sumerian',
502 'su' => 'Sundanese',
503 'sus' => 'Susu',
504 'sw' => 'Swahili',
505 'ss' => 'Swati',
506 'sv' => 'Swedish',
507 'fr_CH' => 'Swiss French',
508 'gsw' => 'Swiss German',
509 'de_CH' => 'Swiss High German',
510 'syr' => 'Syriac',
511 'shi' => 'Tachelhit',
512 'tl' => 'Tagalog',
513 'ty' => 'Tahitian',
514 'tai' => 'Tai Language',
515 'dav' => 'Taita',
516 'tg' => 'Tajik',
517 'tmh' => 'Tamashek',
518 'ta' => 'Tamil',
519 'trv' => 'Taroko',
520 'twq' => 'Tasawaq',
521 'tt' => 'Tatar',
522 'te' => 'Telugu',
523 'ter' => 'Tereno',
524 'teo' => 'Teso',
525 'tet' => 'Tetum',
526 'th' => 'Thai',
527 'bo' => 'Tibetan',
528 'tig' => 'Tigre',
529 'ti' => 'Tigrinya',
530 'tem' => 'Timne',
531 'tiv' => 'Tiv',
532 'tli' => 'Tlingit',
533 'tpi' => 'Tok Pisin',
534 'tkl' => 'Tokelau',
535 'to' => 'Tongan',
536 'zh_Hant' => 'Traditional Chinese',
537 'tsi' => 'Tsimshian',
538 'ts' => 'Tsonga',
539 'tn' => 'Tswana',
540 'tum' => 'Tumbuka',
541 'tup' => 'Tupi Language',
542 'tr' => 'Turkish',
543 'tk' => 'Turkmen',
544 'tvl' => 'Tuvalu',
545 'tyv' => 'Tuvinian',
546 'tw' => 'Twi',
547 'kcg' => 'Tyap',
548 'en_US' => 'U.S. English',
549 'udm' => 'Udmurt',
550 'uga' => 'Ugaritic',
551 'ug' => 'Uighur',
552 'uk' => 'Ukrainian',
553 'umb' => 'Umbundu',
554 'und' => 'Unknown Language',
555 'hsb' => 'Upper Sorbian',
556 'ur' => 'Urdu',
557 'uz' => 'Uzbek',
558 'vai' => 'Vai',
559 've' => 'Venda',
560 'vi' => 'Vietnamese',
561 'vo' => 'Volapük',
562 'vot' => 'Votic',
563 'vun' => 'Vunjo',
564 'wak' => 'Wakashan Language',
565 'wa' => 'Walloon',
566 'wae' => 'Walser',
567 'war' => 'Waray',
568 'was' => 'Washo',
569 'cy' => 'Welsh',
570 'fy' => 'Western Frisian',
571 'wal' => 'Wolaytta',
572 'wo' => 'Wolof',
573 'xh' => 'Xhosa',
574 'yav' => 'Yangben',
575 'yao' => 'Yao',
576 'yap' => 'Yapese',
577 'ybb' => 'Yemba',
578 'yi' => 'Yiddish',
579 'yo' => 'Yoruba',
580 'ypk' => 'Yupik Language',
581 'znd' => 'Zande',
582 'zap' => 'Zapotec',
583 'dje' => 'Zarma',
584 'zza' => 'Zaza',
585 'zen' => 'Zenaga',
586 'za' => 'Zhuang',
587 'zu' => 'Zulu',
588 'zun' => 'Zuni',
589 ),
590 'Scripts' => array(
591 'Afak' => 'Afaka',
592 'Hluw' => 'Anatolian Hieroglyphs',
593 'Arab' => 'Arabic',
594 'Armn' => 'Armenian',
595 'Avst' => 'Avestan',
596 'Bali' => 'Balinese',
597 'Bamu' => 'Bamum',
598 'Bass' => 'Bassa Vah',
599 'Batk' => 'Batak',
600 'Beng' => 'Bengali',
601 'Blis' => 'Blissymbols',
602 'Phlv' => 'Book Pahlavi',
603 'Bopo' => 'Bopomofo',
604 'Brah' => 'Brahmi',
605 'Brai' => 'Braille',
606 'Bugi' => 'Buginese',
607 'Buhd' => 'Buhid',
608 'Cari' => 'Carian',
609 'Cakm' => 'Chakma',
610 'Cham' => 'Cham',
611 'Cher' => 'Cherokee',
612 'Cirt' => 'Cirth',
613 'Zyyy' => 'Common',
614 'Copt' => 'Coptic',
615 'Cprt' => 'Cypriot',
616 'Cyrl' => 'Cyrillic',
617 'Dsrt' => 'Deseret',
618 'Deva' => 'Devanagari',
619 'Dupl' => 'Duployan shorthand',
620 'Syrn' => 'Eastern Syriac',
621 'Egyd' => 'Egyptian demotic',
622 'Egyh' => 'Egyptian hieratic',
623 'Egyp' => 'Egyptian hieroglyphs',
624 'Syre' => 'Estrangelo Syriac',
625 'Ethi' => 'Ethiopic',
626 'Latf' => 'Fraktur Latin',
627 'Lisu' => 'Fraser',
628 'Latg' => 'Gaelic Latin',
629 'Geor' => 'Georgian',
630 'Geok' => 'Georgian Khutsuri',
631 'Glag' => 'Glagolitic',
632 'Goth' => 'Gothic',
633 'Gran' => 'Grantha',
634 'Grek' => 'Greek',
635 'Gujr' => 'Gujarati',
636 'Guru' => 'Gurmukhi',
637 'Hani' => 'Han',
638 'Hang' => 'Hangul',
639 'Hano' => 'Hanunoo',
640 'Hebr' => 'Hebrew',
641 'Hira' => 'Hiragana',
642 'Armi' => 'Imperial Aramaic',
643 'Inds' => 'Indus',
644 'Zinh' => 'Inherited',
645 'Phli' => 'Inscriptional Pahlavi',
646 'Prti' => 'Inscriptional Parthian',
647 'Jpan' => 'Japanese',
648 'Hrkt' => 'Japanese syllabaries',
649 'Java' => 'Javanese',
650 'Jurc' => 'Jurchen',
651 'Kthi' => 'Kaithi',
652 'Knda' => 'Kannada',
653 'Kana' => 'Katakana',
654 'Kali' => 'Kayah Li',
655 'Khar' => 'Kharoshthi',
656 'Khmr' => 'Khmer',
657 'Khoj' => 'Khojki',
658 'Sind' => 'Khudawadi',
659 'Kore' => 'Korean',
660 'Kpel' => 'Kpelle',
661 'Lana' => 'Lanna',
662 'Laoo' => 'Lao',
663 'Latn' => 'Latin',
664 'Lepc' => 'Lepcha',
665 'Limb' => 'Limbu',
666 'Lina' => 'Linear A',
667 'Linb' => 'Linear B',
668 'Loma' => 'Loma',
669 'Lyci' => 'Lycian',
670 'Lydi' => 'Lydian',
671 'Mlym' => 'Malayalam',
672 'Mand' => 'Mandaean',
673 'Mani' => 'Manichaean',
674 'Zmth' => 'Mathematical Notation',
675 'Maya' => 'Mayan hieroglyphs',
676 'Mtei' => 'Meitei Mayek',
677 'Mend' => 'Mende',
678 'Mero' => 'Meroitic',
679 'Merc' => 'Meroitic Cursive',
680 'Mong' => 'Mongolian',
681 'Moon' => 'Moon',
682 'Mroo' => 'Mro',
683 'Mymr' => 'Myanmar',
684 'Nkoo' => 'N’Ko',
685 'Nbat' => 'Nabataean',
686 'Nkgb' => 'Naxi Geba',
687 'Talu' => 'New Tai Lue',
688 'Nshu' => 'Nüshu',
689 'Ogam' => 'Ogham',
690 'Olck' => 'Ol Chiki',
691 'Cyrs' => 'Old Church Slavonic Cyrillic',
692 'Hung' => 'Old Hungarian',
693 'Ital' => 'Old Italic',
694 'Narb' => 'Old North Arabian',
695 'Perm' => 'Old Permic',
696 'Xpeo' => 'Old Persian',
697 'Sarb' => 'Old South Arabian',
698 'Orya' => 'Oriya',
699 'Orkh' => 'Orkhon',
700 'Osma' => 'Osmanya',
701 'Hmng' => 'Pahawh Hmong',
702 'Palm' => 'Palmyrene',
703 'Phag' => 'Phags-pa',
704 'Phnx' => 'Phoenician',
705 'Plrd' => 'Pollard Phonetic',
706 'Phlp' => 'Psalter Pahlavi',
707 'Rjng' => 'Rejang',
708 'Roro' => 'Rongorongo',
709 'Runr' => 'Runic',
710 'Samr' => 'Samaritan',
711 'Sara' => 'Sarati',
712 'Saur' => 'Saurashtra',
713 'Shrd' => 'Sharada',
714 'Shaw' => 'Shavian',
715 'Sgnw' => 'SignWriting',
716 'Hans' => 'Simplified',
717 'Sinh' => 'Sinhala',
718 'Sora' => 'Sora Sompeng',
719 'Xsux' => 'Sumero-Akkadian Cuneiform',
720 'Sund' => 'Sundanese',
721 'Sylo' => 'Syloti Nagri',
722 'Zsym' => 'Symbols',
723 'Syrc' => 'Syriac',
724 'Tglg' => 'Tagalog',
725 'Tagb' => 'Tagbanwa',
726 'Tale' => 'Tai Le',
727 'Tavt' => 'Tai Viet',
728 'Takr' => 'Takri',
729 'Taml' => 'Tamil',
730 'Tang' => 'Tangut',
731 'Telu' => 'Telugu',
732 'Teng' => 'Tengwar',
733 'Thaa' => 'Thaana',
734 'Thai' => 'Thai',
735 'Tibt' => 'Tibetan',
736 'Tfng' => 'Tifinagh',
737 'Tirh' => 'Tirhuta',
738 'Hant' => 'Traditional',
739 'Ugar' => 'Ugaritic',
740 'Cans' => 'Unified Canadian Aboriginal Syllabics',
741 'Zzzz' => 'Unknown Script',
742 'Zxxx' => 'Unwritten',
743 'Vaii' => 'Vai',
744 'Wara' => 'Varang Kshiti',
745 'Visp' => 'Visible Speech',
746 'Syrj' => 'Western Syriac',
747 'Wole' => 'Woleai',
748 'Yiii' => 'Yi',
749 ),
750);
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/locales/en.php b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/locales/en.php
new file mode 100644
index 00000000..b1bcafce
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/locales/en.php
@@ -0,0 +1,305 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12return array(
13 'Locales' => array(
14 'af' => 'Afrikaans',
15 'af_NA' => 'Afrikaans (Namibia)',
16 'agq' => 'Aghem',
17 'ak' => 'Akan',
18 'sq' => 'Albanian',
19 'am' => 'Amharic',
20 'ar' => 'Arabic',
21 'ar_DZ' => 'Arabic (Algeria)',
22 'ar_IQ' => 'Arabic (Iraq)',
23 'ar_JO' => 'Arabic (Jordan)',
24 'ar_LB' => 'Arabic (Lebanon)',
25 'ar_LY' => 'Arabic (Libya)',
26 'ar_MR' => 'Arabic (Mauritania)',
27 'ar_MA' => 'Arabic (Morocco)',
28 'ar_PS' => 'Arabic (Palestinian Territories)',
29 'ar_QA' => 'Arabic (Qatar)',
30 'ar_SA' => 'Arabic (Saudi Arabia)',
31 'ar_SY' => 'Arabic (Syria)',
32 'ar_TN' => 'Arabic (Tunisia)',
33 'ar_EH' => 'Arabic (Western Sahara)',
34 'ar_YE' => 'Arabic (Yemen)',
35 'hy' => 'Armenian',
36 'as' => 'Assamese',
37 'asa' => 'Asu',
38 'az' => 'Azerbaijani',
39 'az_Cyrl' => 'Azerbaijani (Cyrillic)',
40 'az_Latn' => 'Azerbaijani (Latin)',
41 'ksf' => 'Bafia',
42 'bm' => 'Bambara',
43 'bas' => 'Basaa',
44 'eu' => 'Basque',
45 'be' => 'Belarusian',
46 'bem' => 'Bemba',
47 'bez' => 'Bena',
48 'bn' => 'Bengali',
49 'bn_IN' => 'Bengali (India)',
50 'brx' => 'Bodo',
51 'bs' => 'Bosnian',
52 'bs_Cyrl' => 'Bosnian (Cyrillic)',
53 'br' => 'Breton',
54 'bg' => 'Bulgarian',
55 'my' => 'Burmese',
56 'my_MM' => 'Burmese (Myanmar [Burma])',
57 'ca' => 'Catalan',
58 'tzm' => 'Central Atlas Tamazight',
59 'tzm_Latn' => 'Central Atlas Tamazight (Latin)',
60 'chr' => 'Cherokee',
61 'chr_US' => 'Cherokee (United States)',
62 'cgg' => 'Chiga',
63 'zh' => 'Chinese',
64 'zh_Hans_HK' => 'Chinese (Simplified, Hong Kong SAR China)',
65 'zh_Hans_MO' => 'Chinese (Simplified, Macau SAR China)',
66 'zh_Hans_SG' => 'Chinese (Simplified, Singapore)',
67 'zh_Hans' => 'Chinese (Simplified)',
68 'zh_Hant_HK' => 'Chinese (Traditional, Hong Kong SAR China)',
69 'zh_Hant_MO' => 'Chinese (Traditional, Macau SAR China)',
70 'zh_Hant' => 'Chinese (Traditional)',
71 'swc' => 'Congo Swahili',
72 'kw' => 'Cornish',
73 'hr' => 'Croatian',
74 'cs' => 'Czech',
75 'da' => 'Danish',
76 'dua' => 'Duala',
77 'nl' => 'Dutch',
78 'nl_BE' => 'Dutch (Belgium)',
79 'dz' => 'Dzongkha',
80 'ebu' => 'Embu',
81 'en' => 'English',
82 'en_AU' => 'English (Australia)',
83 'en_BE' => 'English (Belgium)',
84 'en_BZ' => 'English (Belize)',
85 'en_BW' => 'English (Botswana)',
86 'en_CA' => 'English (Canada)',
87 'en_GI' => 'English (Gibraltar)',
88 'en_GG' => 'English (Guernsey)',
89 'en_HK' => 'English (Hong Kong SAR China)',
90 'en_IN' => 'English (India)',
91 'en_IE' => 'English (Ireland)',
92 'en_IM' => 'English (Isle of Man)',
93 'en_JM' => 'English (Jamaica)',
94 'en_JE' => 'English (Jersey)',
95 'en_LR' => 'English (Liberia)',
96 'en_MT' => 'English (Malta)',
97 'en_NA' => 'English (Namibia)',
98 'en_NZ' => 'English (New Zealand)',
99 'en_PK' => 'English (Pakistan)',
100 'en_PH' => 'English (Philippines)',
101 'en_PR' => 'English (Puerto Rico)',
102 'en_SG' => 'English (Singapore)',
103 'en_ZA' => 'English (South Africa)',
104 'en_TT' => 'English (Trinidad and Tobago)',
105 'en_GB' => 'English (United Kingdom)',
106 'en_US' => 'English (United States)',
107 'en_ZW' => 'English (Zimbabwe)',
108 'eo' => 'Esperanto',
109 'et' => 'Estonian',
110 'ee' => 'Ewe',
111 'ewo' => 'Ewondo',
112 'fo' => 'Faroese',
113 'fil' => 'Filipino',
114 'fil_PH' => 'Filipino (Philippines)',
115 'fi' => 'Finnish',
116 'fr' => 'French',
117 'fr_BE' => 'French (Belgium)',
118 'fr_CA' => 'French (Canada)',
119 'fr_LU' => 'French (Luxembourg)',
120 'fr_CH' => 'French (Switzerland)',
121 'ff' => 'Fulah',
122 'gl' => 'Galician',
123 'lg' => 'Ganda',
124 'ka' => 'Georgian',
125 'de' => 'German',
126 'de_AT' => 'German (Austria)',
127 'de_LI' => 'German (Liechtenstein)',
128 'de_CH' => 'German (Switzerland)',
129 'el' => 'Greek',
130 'el_CY' => 'Greek (Cyprus)',
131 'gu' => 'Gujarati',
132 'guz' => 'Gusii',
133 'ha' => 'Hausa',
134 'ha_Latn' => 'Hausa (Latin)',
135 'haw' => 'Hawaiian',
136 'haw_US' => 'Hawaiian (United States)',
137 'he' => 'Hebrew',
138 'hi' => 'Hindi',
139 'hu' => 'Hungarian',
140 'is' => 'Icelandic',
141 'ig' => 'Igbo',
142 'id' => 'Indonesian',
143 'ga' => 'Irish',
144 'it' => 'Italian',
145 'it_CH' => 'Italian (Switzerland)',
146 'ja' => 'Japanese',
147 'dyo' => 'Jola-Fonyi',
148 'kea' => 'Kabuverdianu',
149 'kab' => 'Kabyle',
150 'kl' => 'Kalaallisut',
151 'kln' => 'Kalenjin',
152 'kam' => 'Kamba',
153 'kn' => 'Kannada',
154 'ks' => 'Kashmiri',
155 'ks_Arab' => 'Kashmiri (Arabic)',
156 'kk' => 'Kazakh',
157 'kk_Cyrl' => 'Kazakh (Cyrillic)',
158 'km' => 'Khmer',
159 'ki' => 'Kikuyu',
160 'rw' => 'Kinyarwanda',
161 'kok' => 'Konkani',
162 'ko' => 'Korean',
163 'khq' => 'Koyra Chiini',
164 'ses' => 'Koyraboro Senni',
165 'nmg' => 'Kwasio',
166 'lag' => 'Langi',
167 'lo' => 'Lao',
168 'lv' => 'Latvian',
169 'ln' => 'Lingala',
170 'lt' => 'Lithuanian',
171 'lu' => 'Luba-Katanga',
172 'luo' => 'Luo',
173 'luy' => 'Luyia',
174 'mk' => 'Macedonian',
175 'jmc' => 'Machame',
176 'mgh' => 'Makhuwa-Meetto',
177 'kde' => 'Makonde',
178 'mg' => 'Malagasy',
179 'ms' => 'Malay',
180 'ms_BN' => 'Malay (Brunei)',
181 'ml' => 'Malayalam',
182 'mt' => 'Maltese',
183 'gv' => 'Manx',
184 'mr' => 'Marathi',
185 'mas' => 'Masai',
186 'mer' => 'Meru',
187 'mgo' => 'Meta\'',
188 'mfe' => 'Morisyen',
189 'mua' => 'Mundang',
190 'naq' => 'Nama',
191 'ne' => 'Nepali',
192 'ne_IN' => 'Nepali (India)',
193 'jgo' => 'Ngomba',
194 'nd' => 'North Ndebele',
195 'nb' => 'Norwegian Bokmål',
196 'nn' => 'Norwegian Nynorsk',
197 'nus' => 'Nuer',
198 'nyn' => 'Nyankole',
199 'or' => 'Oriya',
200 'om' => 'Oromo',
201 'ps' => 'Pashto',
202 'fa' => 'Persian',
203 'fa_AF' => 'Persian (Afghanistan)',
204 'pl' => 'Polish',
205 'pt' => 'Portuguese',
206 'pt_AO' => 'Portuguese (Angola)',
207 'pt_CV' => 'Portuguese (Cape Verde)',
208 'pt_GW' => 'Portuguese (Guinea-Bissau)',
209 'pt_MO' => 'Portuguese (Macau SAR China)',
210 'pt_MZ' => 'Portuguese (Mozambique)',
211 'pt_PT' => 'Portuguese (Portugal)',
212 'pt_ST' => 'Portuguese (São Tomé and Príncipe)',
213 'pt_TL' => 'Portuguese (Timor-Leste)',
214 'pa' => 'Punjabi',
215 'pa_Arab' => 'Punjabi (Arabic)',
216 'pa_Guru' => 'Punjabi (Gurmukhi)',
217 'ro' => 'Romanian',
218 'rm' => 'Romansh',
219 'rof' => 'Rombo',
220 'rn' => 'Rundi',
221 'ru' => 'Russian',
222 'ru_UA' => 'Russian (Ukraine)',
223 'rwk' => 'Rwa',
224 'saq' => 'Samburu',
225 'sg' => 'Sango',
226 'sbp' => 'Sangu',
227 'seh' => 'Sena',
228 'sr' => 'Serbian',
229 'sr_Cyrl_BA' => 'Serbian (Cyrillic, Bosnia and Herzegovina)',
230 'sr_Cyrl' => 'Serbian (Cyrillic)',
231 'sr_Latn_ME' => 'Serbian (Latin, Montenegro)',
232 'sr_Latn' => 'Serbian (Latin)',
233 'ksb' => 'Shambala',
234 'sn' => 'Shona',
235 'ii' => 'Sichuan Yi',
236 'si' => 'Sinhala',
237 'sk' => 'Slovak',
238 'sl' => 'Slovenian',
239 'xog' => 'Soga',
240 'so' => 'Somali',
241 'es' => 'Spanish',
242 'es_AR' => 'Spanish (Argentina)',
243 'es_BO' => 'Spanish (Bolivia)',
244 'es_CL' => 'Spanish (Chile)',
245 'es_CO' => 'Spanish (Colombia)',
246 'es_CR' => 'Spanish (Costa Rica)',
247 'es_CU' => 'Spanish (Cuba)',
248 'es_DO' => 'Spanish (Dominican Republic)',
249 'es_EC' => 'Spanish (Ecuador)',
250 'es_SV' => 'Spanish (El Salvador)',
251 'es_GQ' => 'Spanish (Equatorial Guinea)',
252 'es_GT' => 'Spanish (Guatemala)',
253 'es_HN' => 'Spanish (Honduras)',
254 'es_MX' => 'Spanish (Mexico)',
255 'es_NI' => 'Spanish (Nicaragua)',
256 'es_PA' => 'Spanish (Panama)',
257 'es_PY' => 'Spanish (Paraguay)',
258 'es_PE' => 'Spanish (Peru)',
259 'es_PH' => 'Spanish (Philippines)',
260 'es_PR' => 'Spanish (Puerto Rico)',
261 'es_US' => 'Spanish (United States)',
262 'es_UY' => 'Spanish (Uruguay)',
263 'es_VE' => 'Spanish (Venezuela)',
264 'sw' => 'Swahili',
265 'sw_KE' => 'Swahili (Kenya)',
266 'sv' => 'Swedish',
267 'sv_FI' => 'Swedish (Finland)',
268 'gsw' => 'Swiss German',
269 'shi' => 'Tachelhit',
270 'shi_Latn' => 'Tachelhit (Latin)',
271 'shi_Tfng' => 'Tachelhit (Tifinagh)',
272 'dav' => 'Taita',
273 'ta' => 'Tamil',
274 'ta_MY' => 'Tamil (Malaysia)',
275 'ta_SG' => 'Tamil (Singapore)',
276 'twq' => 'Tasawaq',
277 'te' => 'Telugu',
278 'teo' => 'Teso',
279 'th' => 'Thai',
280 'bo' => 'Tibetan',
281 'ti' => 'Tigrinya',
282 'ti_ER' => 'Tigrinya (Eritrea)',
283 'to' => 'Tongan',
284 'tr' => 'Turkish',
285 'uk' => 'Ukrainian',
286 'ur' => 'Urdu',
287 'ur_IN' => 'Urdu (India)',
288 'uz' => 'Uzbek',
289 'uz_Arab' => 'Uzbek (Arabic)',
290 'uz_Cyrl' => 'Uzbek (Cyrillic)',
291 'uz_Latn' => 'Uzbek (Latin)',
292 'vai' => 'Vai',
293 'vai_Latn_LR' => 'Vai (Latin, Liberia)',
294 'vai_Latn' => 'Vai (Latin)',
295 'vai_Vaii_LR' => 'Vai (Vai, Liberia)',
296 'vai_Vaii' => 'Vai (Vai)',
297 'vi' => 'Vietnamese',
298 'vun' => 'Vunjo',
299 'cy' => 'Welsh',
300 'yav' => 'Yangben',
301 'yo' => 'Yoruba',
302 'dje' => 'Zarma',
303 'zu' => 'Zulu',
304 ),
305);
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/region/en.php b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/region/en.php
new file mode 100644
index 00000000..f42d6576
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/region/en.php
@@ -0,0 +1,273 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12return array(
13 'Countries' => array(
14 'AF' => 'Afghanistan',
15 'AX' => 'Ã…land Islands',
16 'AL' => 'Albania',
17 'DZ' => 'Algeria',
18 'AS' => 'American Samoa',
19 'AD' => 'Andorra',
20 'AO' => 'Angola',
21 'AI' => 'Anguilla',
22 'AQ' => 'Antarctica',
23 'AG' => 'Antigua and Barbuda',
24 'AR' => 'Argentina',
25 'AM' => 'Armenia',
26 'AW' => 'Aruba',
27 'AC' => 'Ascension Island',
28 'AU' => 'Australia',
29 'AT' => 'Austria',
30 'AZ' => 'Azerbaijan',
31 'BS' => 'Bahamas',
32 'BH' => 'Bahrain',
33 'BD' => 'Bangladesh',
34 'BB' => 'Barbados',
35 'BY' => 'Belarus',
36 'BE' => 'Belgium',
37 'BZ' => 'Belize',
38 'BJ' => 'Benin',
39 'BM' => 'Bermuda',
40 'BT' => 'Bhutan',
41 'BO' => 'Bolivia',
42 'BA' => 'Bosnia and Herzegovina',
43 'BW' => 'Botswana',
44 'BV' => 'Bouvet Island',
45 'BR' => 'Brazil',
46 'IO' => 'British Indian Ocean Territory',
47 'VG' => 'British Virgin Islands',
48 'BN' => 'Brunei',
49 'BG' => 'Bulgaria',
50 'BF' => 'Burkina Faso',
51 'BI' => 'Burundi',
52 'KH' => 'Cambodia',
53 'CM' => 'Cameroon',
54 'CA' => 'Canada',
55 'IC' => 'Canary Islands',
56 'CV' => 'Cape Verde',
57 'BQ' => 'Caribbean Netherlands',
58 'KY' => 'Cayman Islands',
59 'CF' => 'Central African Republic',
60 'EA' => 'Ceuta and Melilla',
61 'TD' => 'Chad',
62 'CL' => 'Chile',
63 'CN' => 'China',
64 'CX' => 'Christmas Island',
65 'CP' => 'Clipperton Island',
66 'CC' => 'Cocos [Keeling] Islands',
67 'CO' => 'Colombia',
68 'KM' => 'Comoros',
69 'CG' => 'Congo - Brazzaville',
70 'CD' => 'Congo - Kinshasa',
71 'CK' => 'Cook Islands',
72 'CR' => 'Costa Rica',
73 'CI' => 'Côte d’Ivoire',
74 'HR' => 'Croatia',
75 'CU' => 'Cuba',
76 'CW' => 'Curaçao',
77 'CY' => 'Cyprus',
78 'CZ' => 'Czech Republic',
79 'DK' => 'Denmark',
80 'DG' => 'Diego Garcia',
81 'DJ' => 'Djibouti',
82 'DM' => 'Dominica',
83 'DO' => 'Dominican Republic',
84 'EC' => 'Ecuador',
85 'EG' => 'Egypt',
86 'SV' => 'El Salvador',
87 'GQ' => 'Equatorial Guinea',
88 'ER' => 'Eritrea',
89 'EE' => 'Estonia',
90 'ET' => 'Ethiopia',
91 'EU' => 'European Union',
92 'FK' => 'Falkland Islands',
93 'FO' => 'Faroe Islands',
94 'FJ' => 'Fiji',
95 'FI' => 'Finland',
96 'FR' => 'France',
97 'GF' => 'French Guiana',
98 'PF' => 'French Polynesia',
99 'TF' => 'French Southern Territories',
100 'GA' => 'Gabon',
101 'GM' => 'Gambia',
102 'GE' => 'Georgia',
103 'DE' => 'Germany',
104 'GH' => 'Ghana',
105 'GI' => 'Gibraltar',
106 'GR' => 'Greece',
107 'GL' => 'Greenland',
108 'GD' => 'Grenada',
109 'GP' => 'Guadeloupe',
110 'GU' => 'Guam',
111 'GT' => 'Guatemala',
112 'GG' => 'Guernsey',
113 'GN' => 'Guinea',
114 'GW' => 'Guinea-Bissau',
115 'GY' => 'Guyana',
116 'HT' => 'Haiti',
117 'HM' => 'Heard Island and McDonald Islands',
118 'HN' => 'Honduras',
119 'HK' => 'Hong Kong SAR China',
120 'HU' => 'Hungary',
121 'IS' => 'Iceland',
122 'IN' => 'India',
123 'ID' => 'Indonesia',
124 'IR' => 'Iran',
125 'IQ' => 'Iraq',
126 'IE' => 'Ireland',
127 'IM' => 'Isle of Man',
128 'IL' => 'Israel',
129 'IT' => 'Italy',
130 'JM' => 'Jamaica',
131 'JP' => 'Japan',
132 'JE' => 'Jersey',
133 'JO' => 'Jordan',
134 'KZ' => 'Kazakhstan',
135 'KE' => 'Kenya',
136 'KI' => 'Kiribati',
137 'KW' => 'Kuwait',
138 'KG' => 'Kyrgyzstan',
139 'LA' => 'Laos',
140 'LV' => 'Latvia',
141 'LB' => 'Lebanon',
142 'LS' => 'Lesotho',
143 'LR' => 'Liberia',
144 'LY' => 'Libya',
145 'LI' => 'Liechtenstein',
146 'LT' => 'Lithuania',
147 'LU' => 'Luxembourg',
148 'MO' => 'Macau SAR China',
149 'MK' => 'Macedonia',
150 'MG' => 'Madagascar',
151 'MW' => 'Malawi',
152 'MY' => 'Malaysia',
153 'MV' => 'Maldives',
154 'ML' => 'Mali',
155 'MT' => 'Malta',
156 'MH' => 'Marshall Islands',
157 'MQ' => 'Martinique',
158 'MR' => 'Mauritania',
159 'MU' => 'Mauritius',
160 'YT' => 'Mayotte',
161 'MX' => 'Mexico',
162 'FM' => 'Micronesia',
163 'MD' => 'Moldova',
164 'MC' => 'Monaco',
165 'MN' => 'Mongolia',
166 'ME' => 'Montenegro',
167 'MS' => 'Montserrat',
168 'MA' => 'Morocco',
169 'MZ' => 'Mozambique',
170 'MM' => 'Myanmar [Burma]',
171 'NA' => 'Namibia',
172 'NR' => 'Nauru',
173 'NP' => 'Nepal',
174 'NL' => 'Netherlands',
175 'AN' => 'Netherlands Antilles',
176 'NC' => 'New Caledonia',
177 'NZ' => 'New Zealand',
178 'NI' => 'Nicaragua',
179 'NE' => 'Niger',
180 'NG' => 'Nigeria',
181 'NU' => 'Niue',
182 'NF' => 'Norfolk Island',
183 'KP' => 'North Korea',
184 'MP' => 'Northern Mariana Islands',
185 'NO' => 'Norway',
186 'OM' => 'Oman',
187 'QO' => 'Outlying Oceania',
188 'PK' => 'Pakistan',
189 'PW' => 'Palau',
190 'PS' => 'Palestinian Territories',
191 'PA' => 'Panama',
192 'PG' => 'Papua New Guinea',
193 'PY' => 'Paraguay',
194 'PE' => 'Peru',
195 'PH' => 'Philippines',
196 'PN' => 'Pitcairn Islands',
197 'PL' => 'Poland',
198 'PT' => 'Portugal',
199 'PR' => 'Puerto Rico',
200 'QA' => 'Qatar',
201 'RE' => 'Réunion',
202 'RO' => 'Romania',
203 'RU' => 'Russia',
204 'RW' => 'Rwanda',
205 'BL' => 'Saint Barthélemy',
206 'SH' => 'Saint Helena',
207 'KN' => 'Saint Kitts and Nevis',
208 'LC' => 'Saint Lucia',
209 'MF' => 'Saint Martin',
210 'PM' => 'Saint Pierre and Miquelon',
211 'VC' => 'Saint Vincent and the Grenadines',
212 'WS' => 'Samoa',
213 'SM' => 'San Marino',
214 'ST' => 'São Tomé and Príncipe',
215 'SA' => 'Saudi Arabia',
216 'SN' => 'Senegal',
217 'RS' => 'Serbia',
218 'SC' => 'Seychelles',
219 'SL' => 'Sierra Leone',
220 'SG' => 'Singapore',
221 'SX' => 'Sint Maarten',
222 'SK' => 'Slovakia',
223 'SI' => 'Slovenia',
224 'SB' => 'Solomon Islands',
225 'SO' => 'Somalia',
226 'ZA' => 'South Africa',
227 'GS' => 'South Georgia and the South Sandwich Islands',
228 'KR' => 'South Korea',
229 'SS' => 'South Sudan',
230 'ES' => 'Spain',
231 'LK' => 'Sri Lanka',
232 'SD' => 'Sudan',
233 'SR' => 'Suriname',
234 'SJ' => 'Svalbard and Jan Mayen',
235 'SZ' => 'Swaziland',
236 'SE' => 'Sweden',
237 'CH' => 'Switzerland',
238 'SY' => 'Syria',
239 'TW' => 'Taiwan',
240 'TJ' => 'Tajikistan',
241 'TZ' => 'Tanzania',
242 'TH' => 'Thailand',
243 'TL' => 'Timor-Leste',
244 'TG' => 'Togo',
245 'TK' => 'Tokelau',
246 'TO' => 'Tonga',
247 'TT' => 'Trinidad and Tobago',
248 'TA' => 'Tristan da Cunha',
249 'TN' => 'Tunisia',
250 'TR' => 'Turkey',
251 'TM' => 'Turkmenistan',
252 'TC' => 'Turks and Caicos Islands',
253 'TV' => 'Tuvalu',
254 'UM' => 'U.S. Outlying Islands',
255 'VI' => 'U.S. Virgin Islands',
256 'UG' => 'Uganda',
257 'UA' => 'Ukraine',
258 'AE' => 'United Arab Emirates',
259 'GB' => 'United Kingdom',
260 'US' => 'United States',
261 'UY' => 'Uruguay',
262 'UZ' => 'Uzbekistan',
263 'VU' => 'Vanuatu',
264 'VA' => 'Vatican City',
265 'VE' => 'Venezuela',
266 'VN' => 'Vietnam',
267 'WF' => 'Wallis and Futuna',
268 'EH' => 'Western Sahara',
269 'YE' => 'Yemen',
270 'ZM' => 'Zambia',
271 'ZW' => 'Zimbabwe',
272 ),
273);
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/version.txt b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/version.txt
new file mode 100644
index 00000000..da316782
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/Resources/data/version.txt
@@ -0,0 +1 @@
50.1.2
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/Tests/IcuIntegrationTest.php b/vendor/symfony/icu/Symfony/Component/Icu/Tests/IcuIntegrationTest.php
new file mode 100644
index 00000000..9fb65af3
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/Tests/IcuIntegrationTest.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Icu\Tests;
13
14use Symfony\Component\Icu\IcuCurrencyBundle;
15use Symfony\Component\Icu\IcuLanguageBundle;
16use Symfony\Component\Icu\IcuLocaleBundle;
17use Symfony\Component\Icu\IcuRegionBundle;
18use Symfony\Component\Intl\ResourceBundle\Reader\PhpBundleReader;
19use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReader;
20
21/**
22 * Verifies that the data files can actually be read.
23 *
24 * @author Bernhard Schussek <bschussek@gmail.com>
25 */
26class IcuIntegrationTest extends \PHPUnit_Framework_TestCase
27{
28 public function testCurrencyBundle()
29 {
30 $bundle = new IcuCurrencyBundle(new StructuredBundleReader(new PhpBundleReader()));
31
32 $this->assertSame('€', $bundle->getCurrencySymbol('EUR', 'en'));
33 }
34
35 public function testLanguageBundle()
36 {
37 $bundle = new IcuLanguageBundle(new StructuredBundleReader(new PhpBundleReader()));
38
39 $this->assertSame('German', $bundle->getLanguageName('de', null, 'en'));
40 }
41
42 public function testLocaleBundle()
43 {
44 $bundle = new IcuLocaleBundle(new StructuredBundleReader(new PhpBundleReader()));
45
46 $this->assertSame('Azerbaijani', $bundle->getLocaleName('az', 'en'));
47 }
48
49 public function testRegionBundle()
50 {
51 $bundle = new IcuRegionBundle(new StructuredBundleReader(new PhpBundleReader()));
52
53 $this->assertSame('United Kingdom', $bundle->getCountryName('GB', 'en'));
54 }
55}
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/composer.json b/vendor/symfony/icu/Symfony/Component/Icu/composer.json
new file mode 100644
index 00000000..279430ad
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/composer.json
@@ -0,0 +1,26 @@
1{
2 "name": "symfony/icu",
3 "type": "library",
4 "description": "Contains an excerpt of the ICU data and classes to load it.",
5 "keywords": ["icu", "intl"],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Bernhard Schussek",
11 "email": "bschussek@gmail.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3",
20 "symfony/intl": "~2.3"
21 },
22 "autoload": {
23 "psr-0": { "Symfony\\Component\\Icu\\": "" }
24 },
25 "target-dir": "Symfony/Component/Icu"
26}
diff --git a/vendor/symfony/icu/Symfony/Component/Icu/phpunit.xml.dist b/vendor/symfony/icu/Symfony/Component/Icu/phpunit.xml.dist
new file mode 100644
index 00000000..acfe4bd9
--- /dev/null
+++ b/vendor/symfony/icu/Symfony/Component/Icu/phpunit.xml.dist
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony Icu Component Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./Tests</directory>
25 <directory>./vendor</directory>
26 </exclude>
27 </whitelist>
28 </filter>
29</phpunit>
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/.gitignore b/vendor/symfony/intl/Symfony/Component/Intl/.gitignore
new file mode 100644
index 00000000..c49a5d8d
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/.gitignore
@@ -0,0 +1,3 @@
1vendor/
2composer.lock
3phpunit.xml
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/CONTRIBUTING.md b/vendor/symfony/intl/Symfony/Component/Intl/CONTRIBUTING.md
new file mode 100644
index 00000000..315c28ab
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/CONTRIBUTING.md
@@ -0,0 +1,91 @@
1Contributing to the Intl component
2==================================
3
4A very good way of contributing to the Intl component is by updating the
5included data for the ICU version you have installed on your system.
6
7Preparation
8-----------
9
10To prepare, you need to install the development dependencies of the component.
11
12 $ cd /path/to/Symfony/Component/Intl
13 $ composer.phar install --dev
14
15Determining your ICU version
16---------------------------
17
18The ICU version installed in your PHP environment can be found by running
19icu-version.php:
20
21 $ php Resources/bin/icu-version.php
22
23Updating the ICU data
24---------------------
25
26To update the data files, run the update-icu-component.php script:
27
28 $ php Resources/bin/update-icu-component.php
29
30The script needs the binaries "svn" and "make" to be available on your system.
31It will download the latest version of the ICU sources for the ICU version
32installed in your PHP environment. The script will then compile the "genrb"
33binary and use it to compile the ICU data files to binaries. The binaries are
34copied to the Resources/ directory of the Icu component found in the
35vendor/symfony/icu/ directory.
36
37Updating the stub data
38----------------------
39
40In the previous step you updated the Icu component for the ICU version
41installed on your system. If you are using the latest ICU version, you should
42also create the stub data files which will be used by people who don't have
43the intl extension installed.
44
45To update the stub files, run the update-stubs.php script:
46
47 $ php Resources/bin/update-stubs.php
48
49The script will fail if you don't have the latest ICU version. If you want to
50upgrade the ICU version, adjust the return value of the
51`Intl::getIcuStubVersion()` before you run the script.
52
53The script creates copies of the binary resource bundles in the Icu component
54and stores them in the Resources/ directory of the Intl component. The copies
55are made for the locale "en" only and are stored in .php files, so that they
56can be read even if the intl extension is not available.
57
58Creating a pull request
59-----------------------
60
61You need to create up to two pull requests:
62
63* If you updated the Icu component, you need to push that change and create a
64 pull request in the `symfony/Icu` repository. Make sure to submit the pull
65 request to the correct master branch. If you updated the ICU data for version
66 4.8, your pull request goes to branch `48-master`, for version 49 to
67 `49-master` and so on.
68
69* If you updated the stub files of the Intl component, you need to push that
70 change and create a pull request in the `symfony/symfony` repository. The
71 pull request should be based on the `master` branch.
72
73Combining .res files to a .dat-package
74--------------------------------------
75
76The individual *.res files can be combined into a single .dat-file.
77Unfortunately, PHP's `ResourceBundle` class is currently not able to handle
78.dat-files.
79
80Once it is, the following steps have to be followed to build the .dat-file:
81
821. Package the resource bundles into a single file
83
84 $ find . -name *.res | sed -e "s/\.\///g" > packagelist.txt
85 $ pkgdata -p region -T build -d . packagelist.txt
86
872. Clean up
88
89 $ rm -rf build packagelist.txt
90
913. You can now move region.dat to replace the version bundled with Symfony2.
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Collator/Collator.php b/vendor/symfony/intl/Symfony/Component/Intl/Collator/Collator.php
new file mode 100644
index 00000000..8c0ffc33
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Collator/Collator.php
@@ -0,0 +1,295 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Collator;
13
14use Symfony\Component\Intl\Exception\MethodNotImplementedException;
15use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException;
16use Symfony\Component\Intl\Globals\IntlGlobals;
17use Symfony\Component\Intl\Locale\Locale;
18
19/**
20 * Replacement for PHP's native {@link \Collator} class.
21 *
22 * The only methods currently supported in this class are:
23 *
24 * - {@link \__construct}
25 * - {@link create}
26 * - {@link asort}
27 * - {@link getErrorCode}
28 * - {@link getErrorMessage}
29 * - {@link getLocale}
30 *
31 * @author Igor Wiedler <igor@wiedler.ch>
32 * @author Bernhard Schussek <bschussek@gmail.com>
33 */
34class Collator
35{
36 /* Attribute constants */
37 const FRENCH_COLLATION = 0;
38 const ALTERNATE_HANDLING = 1;
39 const CASE_FIRST = 2;
40 const CASE_LEVEL = 3;
41 const NORMALIZATION_MODE = 4;
42 const STRENGTH = 5;
43 const HIRAGANA_QUATERNARY_MODE = 6;
44 const NUMERIC_COLLATION = 7;
45
46 /* Attribute constants values */
47 const DEFAULT_VALUE = -1;
48
49 const PRIMARY = 0;
50 const SECONDARY = 1;
51 const TERTIARY = 2;
52 const DEFAULT_STRENGTH = 2;
53 const QUATERNARY = 3;
54 const IDENTICAL = 15;
55
56 const OFF = 16;
57 const ON = 17;
58
59 const SHIFTED = 20;
60 const NON_IGNORABLE = 21;
61
62 const LOWER_FIRST = 24;
63 const UPPER_FIRST = 25;
64
65 /* Sorting options */
66 const SORT_REGULAR = 0;
67 const SORT_NUMERIC = 2;
68 const SORT_STRING = 1;
69
70 /**
71 * Constructor
72 *
73 * @param string $locale The locale code. The only currently supported locale is "en".
74 *
75 * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
76 */
77 public function __construct($locale)
78 {
79 if ('en' != $locale) {
80 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the locale "en" is supported');
81 }
82 }
83
84 /**
85 * Static constructor
86 *
87 * @param string $locale The locale code. The only currently supported locale is "en".
88 *
89 * @return Collator
90 *
91 * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
92 */
93 public static function create($locale)
94 {
95 return new self($locale);
96 }
97
98 /**
99 * Sort array maintaining index association
100 *
101 * @param array &$array Input array
102 * @param integer $sortFlag Flags for sorting, can be one of the following:
103 * Collator::SORT_REGULAR - compare items normally (don't change types)
104 * Collator::SORT_NUMERIC - compare items numerically
105 * Collator::SORT_STRING - compare items as strings
106 *
107 * @return Boolean True on success or false on failure
108 */
109 public function asort(&$array, $sortFlag = self::SORT_REGULAR)
110 {
111 $intlToPlainFlagMap = array(
112 self::SORT_REGULAR => \SORT_REGULAR,
113 self::SORT_NUMERIC => \SORT_NUMERIC,
114 self::SORT_STRING => \SORT_STRING,
115 );
116
117 $plainSortFlag = isset($intlToPlainFlagMap[$sortFlag]) ? $intlToPlainFlagMap[$sortFlag] : self::SORT_REGULAR;
118
119 return asort($array, $plainSortFlag);
120 }
121
122 /**
123 * Not supported. Compare two Unicode strings
124 *
125 * @param string $str1 The first string to compare
126 * @param string $str2 The second string to compare
127 *
128 * @return Boolean|int Return the comparison result or false on failure:
129 * 1 if $str1 is greater than $str2
130 * 0 if $str1 is equal than $str2
131 * -1 if $str1 is less than $str2
132 *
133 * @see http://www.php.net/manual/en/collator.compare.php
134 *
135 * @throws MethodNotImplementedException
136 */
137 public function compare($str1, $str2)
138 {
139 throw new MethodNotImplementedException(__METHOD__);
140 }
141
142 /**
143 * Not supported. Get a value of an integer collator attribute
144 *
145 * @param int $attr An attribute specifier, one of the attribute constants
146 *
147 * @return Boolean|int The attribute value on success or false on error
148 *
149 * @see http://www.php.net/manual/en/collator.getattribute.php
150 *
151 * @throws MethodNotImplementedException
152 */
153 public function getAttribute($attr)
154 {
155 throw new MethodNotImplementedException(__METHOD__);
156 }
157
158 /**
159 * Returns collator's last error code. Always returns the U_ZERO_ERROR class constant value
160 *
161 * @return int The error code from last collator call
162 */
163 public function getErrorCode()
164 {
165 return IntlGlobals::U_ZERO_ERROR;
166 }
167
168 /**
169 * Returns collator's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value
170 *
171 * @return string The error message from last collator call
172 */
173 public function getErrorMessage()
174 {
175 return 'U_ZERO_ERROR';
176 }
177
178 /**
179 * Returns the collator's locale
180 *
181 * @param int $type Not supported. The locale name type to return (Locale::VALID_LOCALE or Locale::ACTUAL_LOCALE)
182 *
183 * @return string The locale used to create the collator. Currently always
184 * returns "en".
185 */
186 public function getLocale($type = Locale::ACTUAL_LOCALE)
187 {
188 return 'en';
189 }
190
191 /**
192 * Not supported. Get sorting key for a string
193 *
194 * @param string $string The string to produce the key from
195 *
196 * @return string The collation key for $string
197 *
198 * @see http://www.php.net/manual/en/collator.getsortkey.php
199 *
200 * @throws MethodNotImplementedException
201 */
202 public function getSortKey($string)
203 {
204 throw new MethodNotImplementedException(__METHOD__);
205 }
206
207 /**
208 * Not supported. Get current collator's strength
209 *
210 * @return Boolean|int The current collator's strength or false on failure
211 *
212 * @see http://www.php.net/manual/en/collator.getstrength.php
213 *
214 * @throws MethodNotImplementedException
215 */
216 public function getStrength()
217 {
218 throw new MethodNotImplementedException(__METHOD__);
219 }
220
221 /**
222 * Not supported. Set a collator's attribute
223 *
224 * @param int $attr An attribute specifier, one of the attribute constants
225 * @param int $val The attribute value, one of the attribute value constants
226 *
227 * @return Boolean True on success or false on failure
228 *
229 * @see http://www.php.net/manual/en/collator.setattribute.php
230 *
231 * @throws MethodNotImplementedException
232 */
233 public function setAttribute($attr, $val)
234 {
235 throw new MethodNotImplementedException(__METHOD__);
236 }
237
238 /**
239 * Not supported. Set the collator's strength
240 *
241 * @param int $strength Strength to set, possible values:
242 * Collator::PRIMARY
243 * Collator::SECONDARY
244 * Collator::TERTIARY
245 * Collator::QUATERNARY
246 * Collator::IDENTICAL
247 * Collator::DEFAULT
248 *
249 * @return Boolean True on success or false on failure
250 *
251 * @see http://www.php.net/manual/en/collator.setstrength.php
252 *
253 * @throws MethodNotImplementedException
254 */
255 public function setStrength($strength)
256 {
257 throw new MethodNotImplementedException(__METHOD__);
258 }
259
260 /**
261 * Not supported. Sort array using specified collator and sort keys
262 *
263 * @param array &$arr Array of strings to sort
264 *
265 * @return Boolean True on success or false on failure
266 *
267 * @see http://www.php.net/manual/en/collator.sortwithsortkeys.php
268 *
269 * @throws MethodNotImplementedException
270 */
271 public function sortWithSortKeys(&$arr)
272 {
273 throw new MethodNotImplementedException(__METHOD__);
274 }
275
276 /**
277 * Not supported. Sort array using specified collator
278 *
279 * @param array &$arr Array of string to sort
280 * @param int $sortFlag Optional sorting type, one of the following:
281 * Collator::SORT_REGULAR
282 * Collator::SORT_NUMERIC
283 * Collator::SORT_STRING
284 *
285 * @return Boolean True on success or false on failure
286 *
287 * @see http://www.php.net/manual/en/collator.sort.php
288 *
289 * @throws MethodNotImplementedException
290 */
291 public function sort(&$arr, $sortFlag = self::SORT_REGULAR)
292 {
293 throw new MethodNotImplementedException(__METHOD__);
294 }
295}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/AmPmTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/AmPmTransformer.php
new file mode 100644
index 00000000..1a9601d8
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/AmPmTransformer.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for AM/PM markers format
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class AmPmTransformer extends Transformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 return $dateTime->format('A');
27 }
28
29 /**
30 * {@inheritDoc}
31 */
32 public function getReverseMatchingRegExp($length)
33 {
34 return 'AM|PM';
35 }
36
37 /**
38 * {@inheritDoc}
39 */
40 public function extractDateOptions($matched, $length)
41 {
42 return array(
43 'marker' => $matched
44 );
45 }
46}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayOfWeekTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayOfWeekTransformer.php
new file mode 100644
index 00000000..ee53a4e6
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayOfWeekTransformer.php
@@ -0,0 +1,59 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for day of week format
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class DayOfWeekTransformer extends Transformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 $dayOfWeek = $dateTime->format('l');
27 switch ($length) {
28 case 4:
29 return $dayOfWeek;
30 case 5:
31 return $dayOfWeek[0];
32 default:
33 return substr($dayOfWeek, 0, 3);
34 }
35 }
36
37 /**
38 * {@inheritDoc}
39 */
40 public function getReverseMatchingRegExp($length)
41 {
42 switch ($length) {
43 case 4:
44 return 'Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday';
45 case 5:
46 return '[MTWFS]';
47 default:
48 return 'Mon|Tue|Wed|Thu|Fri|Sat|Sun';
49 }
50 }
51
52 /**
53 * {@inheritDoc}
54 */
55 public function extractDateOptions($matched, $length)
56 {
57 return array();
58 }
59}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayOfYearTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayOfYearTransformer.php
new file mode 100644
index 00000000..2c33888c
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayOfYearTransformer.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for day of year format
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class DayOfYearTransformer extends Transformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 $dayOfYear = $dateTime->format('z') + 1;
27
28 return $this->padLeft($dayOfYear, $length);
29 }
30
31 /**
32 * {@inheritDoc}
33 */
34 public function getReverseMatchingRegExp($length)
35 {
36 return '\d{'.$length.'}';
37 }
38
39 /**
40 * {@inheritDoc}
41 */
42 public function extractDateOptions($matched, $length)
43 {
44 return array();
45 }
46}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayTransformer.php
new file mode 100644
index 00000000..19d30e74
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/DayTransformer.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for day format
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class DayTransformer extends Transformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 return $this->padLeft($dateTime->format('j'), $length);
27 }
28
29 /**
30 * {@inheritDoc}
31 */
32 public function getReverseMatchingRegExp($length)
33 {
34 return 1 === $length ? '\d{1,2}' : '\d{'.$length.'}';
35 }
36
37 /**
38 * {@inheritDoc}
39 */
40 public function extractDateOptions($matched, $length)
41 {
42 return array(
43 'day' => (int) $matched,
44 );
45 }
46}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/FullTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/FullTransformer.php
new file mode 100644
index 00000000..b89db363
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/FullTransformer.php
@@ -0,0 +1,356 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14use Symfony\Component\Intl\Exception\NotImplementedException;
15use Symfony\Component\Intl\Globals\IntlGlobals;
16use Symfony\Component\Intl\DateFormatter\DateFormat\MonthTransformer;
17
18/**
19 * Parser and formatter for date formats
20 *
21 * @author Igor Wiedler <igor@wiedler.ch>
22 */
23class FullTransformer
24{
25 private $quoteMatch = "'(?:[^']+|'')*'";
26 private $implementedChars = 'MLydQqhDEaHkKmsz';
27 private $notImplementedChars = 'GYuwWFgecSAZvVW';
28 private $regExp;
29
30 /**
31 * @var Transformer[]
32 */
33 private $transformers;
34
35 private $pattern;
36 private $timezone;
37
38 /**
39 * Constructor
40 *
41 * @param string $pattern The pattern to be used to format and/or parse values
42 * @param string $timezone The timezone to perform the date/time calculations
43 */
44 public function __construct($pattern, $timezone)
45 {
46 $this->pattern = $pattern;
47 $this->timezone = $timezone;
48
49 $implementedCharsMatch = $this->buildCharsMatch($this->implementedChars);
50 $notImplementedCharsMatch = $this->buildCharsMatch($this->notImplementedChars);
51 $this->regExp = "/($this->quoteMatch|$implementedCharsMatch|$notImplementedCharsMatch)/";
52
53 $this->transformers = array(
54 'M' => new MonthTransformer(),
55 'L' => new MonthTransformer(),
56 'y' => new YearTransformer(),
57 'd' => new DayTransformer(),
58 'q' => new QuarterTransformer(),
59 'Q' => new QuarterTransformer(),
60 'h' => new Hour1201Transformer(),
61 'D' => new DayOfYearTransformer(),
62 'E' => new DayOfWeekTransformer(),
63 'a' => new AmPmTransformer(),
64 'H' => new Hour2400Transformer(),
65 'K' => new Hour1200Transformer(),
66 'k' => new Hour2401Transformer(),
67 'm' => new MinuteTransformer(),
68 's' => new SecondTransformer(),
69 'z' => new TimeZoneTransformer(),
70 );
71 }
72
73 /**
74 * Return the array of Transformer objects
75 *
76 * @return Transformer[] Associative array of Transformer objects (format char => Transformer)
77 */
78 public function getTransformers()
79 {
80 return $this->transformers;
81 }
82
83 /**
84 * Format a DateTime using ICU dateformat pattern
85 *
86 * @param \DateTime $dateTime A DateTime object to be used to generate the formatted value
87 *
88 * @return string The formatted value
89 */
90 public function format(\DateTime $dateTime)
91 {
92 $that = $this;
93
94 $formatted = preg_replace_callback($this->regExp, function($matches) use ($that, $dateTime) {
95 return $that->formatReplace($matches[0], $dateTime);
96 }, $this->pattern);
97
98 return $formatted;
99 }
100
101 /**
102 * Return the formatted ICU value for the matched date characters
103 *
104 * @param string $dateChars The date characters to be replaced with a formatted ICU value
105 * @param DateTime $dateTime A DateTime object to be used to generate the formatted value
106 *
107 * @return string The formatted value
108 *
109 * @throws NotImplementedException When it encounters a not implemented date character
110 */
111 public function formatReplace($dateChars, $dateTime)
112 {
113 $length = strlen($dateChars);
114
115 if ($this->isQuoteMatch($dateChars)) {
116 return $this->replaceQuoteMatch($dateChars);
117 }
118
119 if (isset($this->transformers[$dateChars[0]])) {
120 $transformer = $this->transformers[$dateChars[0]];
121
122 return $transformer->format($dateTime, $length);
123 }
124
125 // handle unimplemented characters
126 if (false !== strpos($this->notImplementedChars, $dateChars[0])) {
127 throw new NotImplementedException(sprintf("Unimplemented date character '%s' in format '%s'", $dateChars[0], $this->pattern));
128 }
129 }
130
131 /**
132 * Parse a pattern based string to a timestamp value
133 *
134 * @param \DateTime $dateTime A configured DateTime object to use to perform the date calculation
135 * @param string $value String to convert to a time value
136 *
137 * @return int The corresponding Unix timestamp
138 *
139 * @throws \InvalidArgumentException When the value can not be matched with pattern
140 */
141 public function parse(\DateTime $dateTime, $value)
142 {
143 $reverseMatchingRegExp = $this->getReverseMatchingRegExp($this->pattern);
144 $reverseMatchingRegExp = '/^'.$reverseMatchingRegExp.'$/';
145
146 $options = array();
147
148 if (preg_match($reverseMatchingRegExp, $value, $matches)) {
149 $matches = $this->normalizeArray($matches);
150
151 foreach ($this->transformers as $char => $transformer) {
152 if (isset($matches[$char])) {
153 $length = strlen($matches[$char]['pattern']);
154 $options = array_merge($options, $transformer->extractDateOptions($matches[$char]['value'], $length));
155 }
156 }
157
158 // reset error code and message
159 IntlGlobals::setError(IntlGlobals::U_ZERO_ERROR);
160
161 return $this->calculateUnixTimestamp($dateTime, $options);
162 }
163
164 // behave like the intl extension
165 IntlGlobals::setError(IntlGlobals::U_PARSE_ERROR, 'Date parsing failed');
166
167 return false;
168 }
169
170 /**
171 * Retrieve a regular expression to match with a formatted value.
172 *
173 * @param string $pattern The pattern to create the reverse matching regular expression
174 *
175 * @return string The reverse matching regular expression with named captures being formed by the
176 * transformer index in the $transformer array
177 */
178 public function getReverseMatchingRegExp($pattern)
179 {
180 $that = $this;
181
182 $escapedPattern = preg_quote($pattern, '/');
183
184 // ICU 4.8 recognizes slash ("/") in a value to be parsed as a dash ("-") and vice-versa
185 // when parsing a date/time value
186 $escapedPattern = preg_replace('/\\\[\-|\/]/', '[\/\-]', $escapedPattern);
187
188 $reverseMatchingRegExp = preg_replace_callback($this->regExp, function($matches) use ($that) {
189 $length = strlen($matches[0]);
190 $transformerIndex = $matches[0][0];
191
192 $dateChars = $matches[0];
193 if ($that->isQuoteMatch($dateChars)) {
194 return $that->replaceQuoteMatch($dateChars);
195 }
196
197 $transformers = $that->getTransformers();
198 if (isset($transformers[$transformerIndex])) {
199 $transformer = $transformers[$transformerIndex];
200 $captureName = str_repeat($transformerIndex, $length);
201
202 return "(?P<$captureName>".$transformer->getReverseMatchingRegExp($length).')';
203 }
204 }, $escapedPattern);
205
206 return $reverseMatchingRegExp;
207 }
208
209 /**
210 * Check if the first char of a string is a single quote
211 *
212 * @param string $quoteMatch The string to check
213 *
214 * @return Boolean true if matches, false otherwise
215 */
216 public function isQuoteMatch($quoteMatch)
217 {
218 return ("'" === $quoteMatch[0]);
219 }
220
221 /**
222 * Replaces single quotes at the start or end of a string with two single quotes
223 *
224 * @param string $quoteMatch The string to replace the quotes
225 *
226 * @return string A string with the single quotes replaced
227 */
228 public function replaceQuoteMatch($quoteMatch)
229 {
230 if (preg_match("/^'+$/", $quoteMatch)) {
231 return str_replace("''", "'", $quoteMatch);
232 }
233
234 return str_replace("''", "'", substr($quoteMatch, 1, -1));
235 }
236
237 /**
238 * Builds a chars match regular expression
239 *
240 * @param string $specialChars A string of chars to build the regular expression
241 *
242 * @return string The chars match regular expression
243 */
244 protected function buildCharsMatch($specialChars)
245 {
246 $specialCharsArray = str_split($specialChars);
247
248 $specialCharsMatch = implode('|', array_map(function($char) {
249 return $char.'+';
250 }, $specialCharsArray));
251
252 return $specialCharsMatch;
253 }
254
255 /**
256 * Normalize a preg_replace match array, removing the numeric keys and returning an associative array
257 * with the value and pattern values for the matched Transformer
258 *
259 * @param array $data
260 *
261 * @return array
262 */
263 protected function normalizeArray(array $data)
264 {
265 $ret = array();
266
267 foreach ($data as $key => $value) {
268 if (!is_string($key)) {
269 continue;
270 }
271
272 $ret[$key[0]] = array(
273 'value' => $value,
274 'pattern' => $key
275 );
276 }
277
278 return $ret;
279 }
280
281 /**
282 * Calculates the Unix timestamp based on the matched values by the reverse matching regular
283 * expression of parse()
284 *
285 * @param \DateTime $dateTime The DateTime object to be used to calculate the timestamp
286 * @param array $options An array with the matched values to be used to calculate the timestamp
287 *
288 * @return Boolean|int The calculated timestamp or false if matched date is invalid
289 */
290 protected function calculateUnixTimestamp(\DateTime $dateTime, array $options)
291 {
292 $options = $this->getDefaultValueForOptions($options);
293
294 $year = $options['year'];
295 $month = $options['month'];
296 $day = $options['day'];
297 $hour = $options['hour'];
298 $hourInstance = $options['hourInstance'];
299 $minute = $options['minute'];
300 $second = $options['second'];
301 $marker = $options['marker'];
302 $timezone = $options['timezone'];
303
304 // If month is false, return immediately (intl behavior)
305 if (false === $month) {
306 IntlGlobals::setError(IntlGlobals::U_PARSE_ERROR, 'Date parsing failed');
307
308 return false;
309 }
310
311 // Normalize hour
312 if ($hourInstance instanceof HourTransformer) {
313 $hour = $hourInstance->normalizeHour($hour, $marker);
314 }
315
316 // Set the timezone if different from the default one
317 if (null !== $timezone && $timezone !== $this->timezone) {
318 $dateTime->setTimezone(new \DateTimeZone($timezone));
319 }
320
321 // Normalize yy year
322 preg_match_all($this->regExp, $this->pattern, $matches);
323 if (in_array('yy', $matches[0])) {
324 $dateTime->setTimestamp(time());
325 $year = $year > $dateTime->format('y') + 20 ? 1900 + $year : 2000 + $year;
326 }
327
328 $dateTime->setDate($year, $month, $day);
329 $dateTime->setTime($hour, $minute, $second);
330
331 return $dateTime->getTimestamp();
332 }
333
334 /**
335 * Add sensible default values for missing items in the extracted date/time options array. The values
336 * are base in the beginning of the Unix era
337 *
338 * @param array $options
339 *
340 * @return array
341 */
342 private function getDefaultValueForOptions(array $options)
343 {
344 return array(
345 'year' => isset($options['year']) ? $options['year'] : 1970,
346 'month' => isset($options['month']) ? $options['month'] : 1,
347 'day' => isset($options['day']) ? $options['day'] : 1,
348 'hour' => isset($options['hour']) ? $options['hour'] : 0,
349 'hourInstance' => isset($options['hourInstance']) ? $options['hourInstance'] : null,
350 'minute' => isset($options['minute']) ? $options['minute'] : 0,
351 'second' => isset($options['second']) ? $options['second'] : 0,
352 'marker' => isset($options['marker']) ? $options['marker'] : null,
353 'timezone' => isset($options['timezone']) ? $options['timezone'] : null,
354 );
355 }
356}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour1200Transformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour1200Transformer.php
new file mode 100644
index 00000000..8c8f5ef4
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour1200Transformer.php
@@ -0,0 +1,62 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for 12 hour format (0-11)
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class Hour1200Transformer extends HourTransformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 $hourOfDay = $dateTime->format('g');
27 $hourOfDay = '12' == $hourOfDay ? '0' : $hourOfDay;
28
29 return $this->padLeft($hourOfDay, $length);
30 }
31
32 /**
33 * {@inheritDoc}
34 */
35 public function normalizeHour($hour, $marker = null)
36 {
37 if ('PM' === $marker) {
38 $hour += 12;
39 }
40
41 return $hour;
42 }
43
44 /**
45 * {@inheritDoc}
46 */
47 public function getReverseMatchingRegExp($length)
48 {
49 return '\d{1,2}';
50 }
51
52 /**
53 * {@inheritDoc}
54 */
55 public function extractDateOptions($matched, $length)
56 {
57 return array(
58 'hour' => (int) $matched,
59 'hourInstance' => $this
60 );
61 }
62}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour1201Transformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour1201Transformer.php
new file mode 100644
index 00000000..a8c43702
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour1201Transformer.php
@@ -0,0 +1,62 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for 12 hour format (1-12)
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class Hour1201Transformer extends HourTransformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 return $this->padLeft($dateTime->format('g'), $length);
27 }
28
29 /**
30 * {@inheritDoc}
31 */
32 public function normalizeHour($hour, $marker = null)
33 {
34 if ('PM' !== $marker && 12 === $hour) {
35 $hour = 0;
36 } elseif ('PM' === $marker && 12 !== $hour) {
37 // If PM and hour is not 12 (1-12), sum 12 hour
38 $hour += 12;
39 }
40
41 return $hour;
42 }
43
44 /**
45 * {@inheritDoc}
46 */
47 public function getReverseMatchingRegExp($length)
48 {
49 return '\d{1,2}';
50 }
51
52 /**
53 * {@inheritDoc}
54 */
55 public function extractDateOptions($matched, $length)
56 {
57 return array(
58 'hour' => (int) $matched,
59 'hourInstance' => $this
60 );
61 }
62}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour2400Transformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour2400Transformer.php
new file mode 100644
index 00000000..8f22da13
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour2400Transformer.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for 24 hour format (0-23)
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class Hour2400Transformer extends HourTransformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 return $this->padLeft($dateTime->format('G'), $length);
27 }
28
29 /**
30 * {@inheritDoc}
31 */
32 public function normalizeHour($hour, $marker = null)
33 {
34 if ('AM' == $marker) {
35 $hour = 0;
36 } elseif ('PM' == $marker) {
37 $hour = 12;
38 }
39
40 return $hour;
41 }
42
43 /**
44 * {@inheritDoc}
45 */
46 public function getReverseMatchingRegExp($length)
47 {
48 return '\d{1,2}';
49 }
50
51 /**
52 * {@inheritDoc}
53 */
54 public function extractDateOptions($matched, $length)
55 {
56 return array(
57 'hour' => (int) $matched,
58 'hourInstance' => $this
59 );
60 }
61}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour2401Transformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour2401Transformer.php
new file mode 100644
index 00000000..b0f486b9
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Hour2401Transformer.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for 24 hour format (1-24)
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class Hour2401Transformer extends HourTransformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 $hourOfDay = $dateTime->format('G');
27 $hourOfDay = ('0' == $hourOfDay) ? '24' : $hourOfDay;
28
29 return $this->padLeft($hourOfDay, $length);
30 }
31
32 /**
33 * {@inheritDoc}
34 */
35 public function normalizeHour($hour, $marker = null)
36 {
37 if ((null === $marker && 24 === $hour) || 'AM' == $marker) {
38 $hour = 0;
39 } elseif ('PM' == $marker) {
40 $hour = 12;
41 }
42
43 return $hour;
44 }
45
46 /**
47 * {@inheritDoc}
48 */
49 public function getReverseMatchingRegExp($length)
50 {
51 return '\d{1,2}';
52 }
53
54 /**
55 * {@inheritDoc}
56 */
57 public function extractDateOptions($matched, $length)
58 {
59 return array(
60 'hour' => (int) $matched,
61 'hourInstance' => $this
62 );
63 }
64}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/HourTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/HourTransformer.php
new file mode 100644
index 00000000..51097d92
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/HourTransformer.php
@@ -0,0 +1,30 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Base class for hour transformers
16 *
17 * @author Eriksen Costa <eriksen.costa@infranology.com.br>
18 */
19abstract class HourTransformer extends Transformer
20{
21 /**
22 * Returns a normalized hour value suitable for the hour transformer type
23 *
24 * @param int $hour The hour value
25 * @param string $marker An optional AM/PM marker
26 *
27 * @return int The normalized hour value
28 */
29 abstract public function normalizeHour($hour, $marker = null);
30}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/MinuteTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/MinuteTransformer.php
new file mode 100644
index 00000000..b48de292
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/MinuteTransformer.php
@@ -0,0 +1,48 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for minute format
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class MinuteTransformer extends Transformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 $minuteOfHour = (int) $dateTime->format('i');
27
28 return $this->padLeft($minuteOfHour, $length);
29 }
30
31 /**
32 * {@inheritDoc}
33 */
34 public function getReverseMatchingRegExp($length)
35 {
36 return 1 === $length ? '\d{1,2}' : '\d{'.$length.'}';
37 }
38
39 /**
40 * {@inheritDoc}
41 */
42 public function extractDateOptions($matched, $length)
43 {
44 return array(
45 'minute' => (int) $matched,
46 );
47 }
48}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/MonthTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/MonthTransformer.php
new file mode 100644
index 00000000..30c15af7
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/MonthTransformer.php
@@ -0,0 +1,143 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for month format
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class MonthTransformer extends Transformer
20{
21 /**
22 * @var array
23 */
24 protected static $months = array(
25 'January',
26 'February',
27 'March',
28 'April',
29 'May',
30 'June',
31 'July',
32 'August',
33 'September',
34 'October',
35 'November',
36 'December'
37 );
38
39 /**
40 * Short months names (first 3 letters)
41 * @var array
42 */
43 protected static $shortMonths = array();
44
45 /**
46 * Flipped $months array, $name => $index
47 * @var array
48 */
49 protected static $flippedMonths = array();
50
51 /**
52 * Flipped $shortMonths array, $name => $index
53 * @var array
54 */
55 protected static $flippedShortMonths = array();
56
57 /**
58 * Constructor
59 */
60 public function __construct()
61 {
62 if (0 === count(self::$shortMonths)) {
63 self::$shortMonths = array_map(function($month) {
64 return substr($month, 0, 3);
65 }, self::$months);
66
67 self::$flippedMonths = array_flip(self::$months);
68 self::$flippedShortMonths = array_flip(self::$shortMonths);
69 }
70 }
71
72 /**
73 * {@inheritDoc}
74 */
75 public function format(\DateTime $dateTime, $length)
76 {
77 $matchLengthMap = array(
78 1 => 'n',
79 2 => 'm',
80 3 => 'M',
81 4 => 'F',
82 );
83
84 if (isset($matchLengthMap[$length])) {
85 return $dateTime->format($matchLengthMap[$length]);
86 }
87
88 if (5 === $length) {
89 return substr($dateTime->format('M'), 0, 1);
90 }
91
92 return $this->padLeft($dateTime->format('m'), $length);
93 }
94
95 /**
96 * {@inheritDoc}
97 */
98 public function getReverseMatchingRegExp($length)
99 {
100 switch ($length) {
101 case 1:
102 $regExp = '\d{1,2}';
103 break;
104 case 3:
105 $regExp = implode('|', self::$shortMonths);
106 break;
107 case 4:
108 $regExp = implode('|', self::$months);
109 break;
110 case 5:
111 $regExp = '[JFMASOND]';
112 break;
113 default:
114 $regExp = '\d{'.$length.'}';
115 break;
116 }
117
118 return $regExp;
119 }
120
121 /**
122 * {@inheritDoc}
123 */
124 public function extractDateOptions($matched, $length)
125 {
126 if (!is_numeric($matched)) {
127 if (3 === $length) {
128 $matched = self::$flippedShortMonths[$matched] + 1;
129 } elseif (4 === $length) {
130 $matched = self::$flippedMonths[$matched] + 1;
131 } elseif (5 === $length) {
132 // IntlDateFormatter::parse() always returns false for MMMMM or LLLLL
133 $matched = false;
134 }
135 } else {
136 $matched = (int) $matched;
137 }
138
139 return array(
140 'month' => $matched,
141 );
142 }
143}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/QuarterTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/QuarterTransformer.php
new file mode 100644
index 00000000..8e83dc75
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/QuarterTransformer.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for quarter format
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class QuarterTransformer extends Transformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 $month = (int) $dateTime->format('n');
27 $quarter = (int) floor(($month - 1) / 3) + 1;
28 switch ($length) {
29 case 1:
30 case 2:
31 return $this->padLeft($quarter, $length);
32 case 3:
33 return 'Q'.$quarter;
34 default:
35 $map = array(1 => '1st quarter', 2 => '2nd quarter', 3 => '3rd quarter', 4 => '4th quarter');
36
37 return $map[$quarter];
38 }
39 }
40
41 /**
42 * {@inheritDoc}
43 */
44 public function getReverseMatchingRegExp($length)
45 {
46 switch ($length) {
47 case 1:
48 case 2:
49 return '\d{'.$length.'}';
50 case 3:
51 return 'Q\d';
52 default:
53 return '(?:1st|2nd|3rd|4th) quarter';
54 }
55 }
56
57 /**
58 * {@inheritDoc}
59 */
60 public function extractDateOptions($matched, $length)
61 {
62 return array();
63 }
64}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/SecondTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/SecondTransformer.php
new file mode 100644
index 00000000..ccbcdb41
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/SecondTransformer.php
@@ -0,0 +1,48 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for the second format
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class SecondTransformer extends Transformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 $secondOfMinute = (int) $dateTime->format('s');
27
28 return $this->padLeft($secondOfMinute, $length);
29 }
30
31 /**
32 * {@inheritDoc}
33 */
34 public function getReverseMatchingRegExp($length)
35 {
36 return 1 === $length ? '\d{1,2}' : '\d{'.$length.'}';
37 }
38
39 /**
40 * {@inheritDoc}
41 */
42 public function extractDateOptions($matched, $length)
43 {
44 return array(
45 'second' => (int) $matched,
46 );
47 }
48}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/TimeZoneTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/TimeZoneTransformer.php
new file mode 100644
index 00000000..7d74bd36
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/TimeZoneTransformer.php
@@ -0,0 +1,99 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14use Symfony\Component\Intl\Exception\NotImplementedException;
15
16/**
17 * Parser and formatter for time zone format
18 *
19 * @author Igor Wiedler <igor@wiedler.ch>
20 */
21class TimeZoneTransformer extends Transformer
22{
23 /**
24 * {@inheritDoc}
25 *
26 * @throws NotImplementedException When time zone is different than UTC or GMT (Etc/GMT)
27 */
28 public function format(\DateTime $dateTime, $length)
29 {
30 $timeZone = substr($dateTime->getTimezone()->getName(), 0, 3);
31
32 if (!in_array($timeZone, array('Etc', 'UTC'))) {
33 throw new NotImplementedException('Time zone different than GMT or UTC is not supported as a formatting output.');
34 }
35
36 // From ICU >= 4.8, the zero offset is not more used, example: GMT instead of GMT+00:00
37 $format = (0 !== (int) $dateTime->format('O')) ? '\G\M\TP' : '\G\M\T';
38
39 return $dateTime->format($format);
40 }
41
42 /**
43 * {@inheritDoc}
44 */
45 public function getReverseMatchingRegExp($length)
46 {
47 return 'GMT[+-]\d{2}:?\d{2}';
48 }
49
50 /**
51 * {@inheritDoc}
52 */
53 public function extractDateOptions($matched, $length)
54 {
55 return array(
56 'timezone' => self::getEtcTimeZoneId($matched)
57 );
58 }
59
60 /**
61 * Get an Etc/GMT timezone identifier for the specified timezone
62 *
63 * The PHP documentation for timezones states to not use the 'Other' time zones because them exists
64 * "for backwards compatibility". However all Etc/GMT time zones are in the tz database 'etcetera' file,
65 * which indicates they are not deprecated (neither are old names).
66 *
67 * Only GMT, Etc/Universal, Etc/Zulu, Etc/Greenwich, Etc/GMT-0, Etc/GMT+0 and Etc/GMT0 are old names and
68 * are linked to Etc/GMT or Etc/UTC.
69 *
70 * @param string $formattedTimeZone A GMT timezone string (GMT-03:00, e.g.)
71 *
72 * @return string A timezone identifier
73 *
74 * @see http://php.net/manual/en/timezones.others.php
75 * @see http://www.twinsun.com/tz/tz-link.htm
76 *
77 * @throws NotImplementedException When the GMT time zone have minutes offset different than zero
78 * @throws \InvalidArgumentException When the value can not be matched with pattern
79 */
80 public static function getEtcTimeZoneId($formattedTimeZone)
81 {
82 if (preg_match('/GMT(?P<signal>[+-])(?P<hours>\d{2}):?(?P<minutes>\d{2})/', $formattedTimeZone, $matches)) {
83 $hours = (int) $matches['hours'];
84 $minutes = (int) $matches['minutes'];
85 $signal = $matches['signal'] == '-' ? '+' : '-';
86
87 if (0 < $minutes) {
88 throw new NotImplementedException(sprintf(
89 'It is not possible to use a GMT time zone with minutes offset different than zero (0). GMT time zone tried: %s.',
90 $formattedTimeZone
91 ));
92 }
93
94 return 'Etc/GMT'.($hours !== 0 ? $signal.$hours : '');
95 }
96
97 throw new \InvalidArgumentException('The GMT time zone \'%s\' does not match with the supported formats GMT[+-]HH:MM or GMT[+-]HHMM.');
98 }
99}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Transformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Transformer.php
new file mode 100644
index 00000000..0e67f8ae
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/Transformer.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for date formats
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19abstract class Transformer
20{
21 /**
22 * Format a value using a configured DateTime as date/time source
23 *
24 *
25 * @param \DateTime $dateTime A DateTime object to be used to generate the formatted value
26 * @param int $length The formatted value string length
27 *
28 * @return string The formatted value
29 */
30 abstract public function format(\DateTime $dateTime, $length);
31
32 /**
33 * Returns a reverse matching regular expression of a string generated by format()
34 *
35 * @param int $length The length of the value to be reverse matched
36 *
37 * @return string The reverse matching regular expression
38 */
39 abstract public function getReverseMatchingRegExp($length);
40
41 /**
42 * Extract date options from a matched value returned by the processing of the reverse matching
43 * regular expression
44 *
45 * @param string $matched The matched value
46 * @param int $length The length of the Transformer pattern string
47 *
48 * @return array An associative array
49 */
50 abstract public function extractDateOptions($matched, $length);
51
52 /**
53 * Pad a string with zeros to the left
54 *
55 * @param string $value The string to be padded
56 * @param int $length The length to pad
57 *
58 * @return string The padded string
59 */
60 protected function padLeft($value, $length)
61 {
62 return str_pad($value, $length, '0', STR_PAD_LEFT);
63 }
64}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/YearTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/YearTransformer.php
new file mode 100644
index 00000000..c3bd699d
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/DateFormat/YearTransformer.php
@@ -0,0 +1,50 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter\DateFormat;
13
14/**
15 * Parser and formatter for year format
16 *
17 * @author Igor Wiedler <igor@wiedler.ch>
18 */
19class YearTransformer extends Transformer
20{
21 /**
22 * {@inheritDoc}
23 */
24 public function format(\DateTime $dateTime, $length)
25 {
26 if (2 === $length) {
27 return $dateTime->format('y');
28 }
29
30 return $this->padLeft($dateTime->format('Y'), $length);
31 }
32
33 /**
34 * {@inheritDoc}
35 */
36 public function getReverseMatchingRegExp($length)
37 {
38 return 2 === $length ? '\d{2}' : '\d{4}';
39 }
40
41 /**
42 * {@inheritDoc}
43 */
44 public function extractDateOptions($matched, $length)
45 {
46 return array(
47 'year' => (int) $matched,
48 );
49 }
50}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php
new file mode 100644
index 00000000..33a499a8
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php
@@ -0,0 +1,631 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\DateFormatter;
13
14use Symfony\Component\Intl\Globals\IntlGlobals;
15use Symfony\Component\Intl\DateFormatter\DateFormat\FullTransformer;
16use Symfony\Component\Intl\Exception\MethodNotImplementedException;
17use Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException;
18use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException;
19use Symfony\Component\Intl\Locale\Locale;
20
21/**
22 * Replacement for PHP's native {@link \IntlDateFormatter} class.
23 *
24 * The only methods currently supported in this class are:
25 *
26 * - {@link __construct}
27 * - {@link create}
28 * - {@link format}
29 * - {@link getCalendar}
30 * - {@link getDateType}
31 * - {@link getErrorCode}
32 * - {@link getErrorMessage}
33 * - {@link getLocale}
34 * - {@link getPattern}
35 * - {@link getTimeType}
36 * - {@link getTimeZoneId}
37 * - {@link isLenient}
38 * - {@link parse}
39 * - {@link setLenient}
40 * - {@link setPattern}
41 * - {@link setTimeZoneId}
42 * - {@link setTimeZone}
43 *
44 * @author Igor Wiedler <igor@wiedler.ch>
45 * @author Bernhard Schussek <bschussek@gmail.com>
46 */
47class IntlDateFormatter
48{
49 /**
50 * The error code from the last operation
51 *
52 * @var integer
53 */
54 protected $errorCode = IntlGlobals::U_ZERO_ERROR;
55
56 /**
57 * The error message from the last operation
58 *
59 * @var string
60 */
61 protected $errorMessage = 'U_ZERO_ERROR';
62
63 /* date/time format types */
64 const NONE = -1;
65 const FULL = 0;
66 const LONG = 1;
67 const MEDIUM = 2;
68 const SHORT = 3;
69
70 /* calendar formats */
71 const TRADITIONAL = 0;
72 const GREGORIAN = 1;
73
74 /**
75 * Patterns used to format the date when no pattern is provided
76 *
77 * @var array
78 */
79 private $defaultDateFormats = array(
80 self::NONE => '',
81 self::FULL => 'EEEE, LLLL d, y',
82 self::LONG => 'LLLL d, y',
83 self::MEDIUM => 'LLL d, y',
84 self::SHORT => 'M/d/yy',
85 );
86
87 /**
88 * Patterns used to format the time when no pattern is provided
89 *
90 * @var array
91 */
92 private $defaultTimeFormats = array(
93 self::FULL => 'h:mm:ss a zzzz',
94 self::LONG => 'h:mm:ss a z',
95 self::MEDIUM => 'h:mm:ss a',
96 self::SHORT => 'h:mm a',
97 );
98
99 /**
100 * @var int
101 */
102 private $datetype;
103
104 /**
105 * @var int
106 */
107 private $timetype;
108
109 /**
110 * @var string
111 */
112 private $pattern;
113
114 /**
115 * @var \DateTimeZone
116 */
117 private $dateTimeZone;
118
119 /**
120 * @var Boolean
121 */
122 private $unitializedTimeZoneId = false;
123
124 /**
125 * @var string
126 */
127 private $timeZoneId;
128
129 /**
130 * Constructor
131 *
132 * @param string $locale The locale code. The only currently supported locale is "en".
133 * @param int $datetype Type of date formatting, one of the format type constants
134 * @param int $timetype Type of time formatting, one of the format type constants
135 * @param string $timezone Timezone identifier
136 * @param int $calendar Calendar to use for formatting or parsing. The only currently
137 * supported value is IntlDateFormatter::GREGORIAN.
138 * @param string $pattern Optional pattern to use when formatting
139 *
140 * @see http://www.php.net/manual/en/intldateformatter.create.php
141 * @see http://userguide.icu-project.org/formatparse/datetime
142 *
143 * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
144 * @throws MethodArgumentValueNotImplementedException When $calendar different than GREGORIAN is passed
145 */
146 public function __construct($locale, $datetype, $timetype, $timezone = null, $calendar = self::GREGORIAN, $pattern = null)
147 {
148 if ('en' !== $locale) {
149 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the locale "en" is supported');
150 }
151
152 if (self::GREGORIAN !== $calendar) {
153 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'calendar', $calendar, 'Only the GREGORIAN calendar is supported');
154 }
155
156 $this->datetype = $datetype;
157 $this->timetype = $timetype;
158
159 $this->setPattern($pattern);
160 $this->setTimeZoneId($timezone);
161 }
162
163 /**
164 * Static constructor
165 *
166 * @param string $locale The locale code. The only currently supported locale is "en".
167 * @param int $datetype Type of date formatting, one of the format type constants
168 * @param int $timetype Type of time formatting, one of the format type constants
169 * @param string $timezone Timezone identifier
170 * @param int $calendar Calendar to use for formatting or parsing; default is Gregorian.
171 * One of the calendar constants.
172 * @param string $pattern Optional pattern to use when formatting
173 *
174 * @return IntlDateFormatter
175 *
176 * @see http://www.php.net/manual/en/intldateformatter.create.php
177 * @see http://userguide.icu-project.org/formatparse/datetime
178 *
179 * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
180 * @throws MethodArgumentValueNotImplementedException When $calendar different than GREGORIAN is passed
181 */
182 public static function create($locale, $datetype, $timetype, $timezone = null, $calendar = self::GREGORIAN, $pattern = null)
183 {
184 return new self($locale, $datetype, $timetype, $timezone, $calendar, $pattern);
185 }
186
187 /**
188 * Format the date/time value (timestamp) as a string
189 *
190 * @param integer|\DateTime $timestamp The timestamp to format. \DateTime objects
191 * are supported as of PHP 5.3.4.
192 *
193 * @return string|Boolean The formatted value or false if formatting failed.
194 *
195 * @see http://www.php.net/manual/en/intldateformatter.format.php
196 *
197 * @throws MethodArgumentValueNotImplementedException If one of the formatting characters is not implemented
198 */
199 public function format($timestamp)
200 {
201 // intl allows timestamps to be passed as arrays - we don't
202 if (is_array($timestamp)) {
203 $message = version_compare(PHP_VERSION, '5.3.4', '>=') ?
204 'Only integer unix timestamps and DateTime objects are supported' :
205 'Only integer unix timestamps are supported';
206
207 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'timestamp', $timestamp, $message);
208 }
209
210 // behave like the intl extension
211 $argumentError = null;
212 if (version_compare(PHP_VERSION, '5.3.4', '<') && !is_int($timestamp)) {
213 $argumentError = 'datefmt_format: takes either an array or an integer timestamp value ';
214 } elseif (version_compare(PHP_VERSION, '5.3.4', '>=') && !is_int($timestamp) && !$timestamp instanceof \DateTime) {
215 $argumentError = 'datefmt_format: takes either an array or an integer timestamp value or a DateTime object';
216 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=') && !is_int($timestamp)) {
217 $argumentError = sprintf('datefmt_format: string \'%s\' is not numeric, which would be required for it to be a valid date', $timestamp);
218 }
219 }
220
221 if (null !== $argumentError) {
222 IntlGlobals::setError(IntlGlobals::U_ILLEGAL_ARGUMENT_ERROR, $argumentError);
223 $this->errorCode = IntlGlobals::getErrorCode();
224 $this->errorMessage = IntlGlobals::getErrorMessage();
225
226 return false;
227 }
228
229 // As of PHP 5.3.4, IntlDateFormatter::format() accepts DateTime instances
230 if (version_compare(PHP_VERSION, '5.3.4', '>=') && $timestamp instanceof \DateTime) {
231 $timestamp = $timestamp->getTimestamp();
232 }
233
234 $transformer = new FullTransformer($this->getPattern(), $this->getTimeZoneId());
235 $formatted = $transformer->format($this->createDateTime($timestamp));
236
237 // behave like the intl extension
238 IntlGlobals::setError(IntlGlobals::U_ZERO_ERROR);
239 $this->errorCode = IntlGlobals::getErrorCode();
240 $this->errorMessage = IntlGlobals::getErrorMessage();
241
242 return $formatted;
243 }
244
245 /**
246 * Not supported. Formats an object
247 *
248 * @param object $object
249 * @param mixed $format
250 * @param string $locale
251 *
252 * @return string The formatted value
253 *
254 * @see http://www.php.net/manual/en/intldateformatter.formatobject.php
255 *
256 * @throws MethodNotImplementedException
257 */
258 public function formatObject($object, $format = null, $locale = null)
259 {
260 throw new MethodNotImplementedException(__METHOD__);
261 }
262
263 /**
264 * Returns the formatter's calendar
265 *
266 * @return int The calendar being used by the formatter. Currently always returns
267 * IntlDateFormatter::GREGORIAN.
268 *
269 * @see http://www.php.net/manual/en/intldateformatter.getcalendar.php
270 */
271 public function getCalendar()
272 {
273 return self::GREGORIAN;
274 }
275
276 /**
277 * Not supported. Returns the formatter's calendar object
278 *
279 * @return object The calendar's object being used by the formatter
280 *
281 * @see http://www.php.net/manual/en/intldateformatter.getcalendarobject.php
282 *
283 * @throws MethodNotImplementedException
284 */
285 public function getCalendarObject()
286 {
287 throw new MethodNotImplementedException(__METHOD__);
288 }
289
290 /**
291 * Returns the formatter's datetype
292 *
293 * @return int The current value of the formatter
294 *
295 * @see http://www.php.net/manual/en/intldateformatter.getdatetype.php
296 */
297 public function getDateType()
298 {
299 return $this->datetype;
300 }
301
302 /**
303 * Returns formatter's last error code. Always returns the U_ZERO_ERROR class constant value
304 *
305 * @return int The error code from last formatter call
306 *
307 * @see http://www.php.net/manual/en/intldateformatter.geterrorcode.php
308 */
309 public function getErrorCode()
310 {
311 return $this->errorCode;
312 }
313
314 /**
315 * Returns formatter's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value
316 *
317 * @return string The error message from last formatter call
318 *
319 * @see http://www.php.net/manual/en/intldateformatter.geterrormessage.php
320 */
321 public function getErrorMessage()
322 {
323 return $this->errorMessage;
324 }
325
326 /**
327 * Returns the formatter's locale
328 *
329 * @param int $type Not supported. The locale name type to return (Locale::VALID_LOCALE or Locale::ACTUAL_LOCALE)
330 *
331 * @return string The locale used to create the formatter. Currently always
332 * returns "en".
333 *
334 * @see http://www.php.net/manual/en/intldateformatter.getlocale.php
335 */
336 public function getLocale($type = Locale::ACTUAL_LOCALE)
337 {
338 return 'en';
339 }
340
341 /**
342 * Returns the formatter's pattern
343 *
344 * @return string The pattern string used by the formatter
345 *
346 * @see http://www.php.net/manual/en/intldateformatter.getpattern.php
347 */
348 public function getPattern()
349 {
350 return $this->pattern;
351 }
352
353 /**
354 * Returns the formatter's time type
355 *
356 * @return string The time type used by the formatter
357 *
358 * @see http://www.php.net/manual/en/intldateformatter.gettimetype.php
359 */
360 public function getTimeType()
361 {
362 return $this->timetype;
363 }
364
365 /**
366 * Returns the formatter's timezone identifier
367 *
368 * @return string The timezone identifier used by the formatter
369 *
370 * @see http://www.php.net/manual/en/intldateformatter.gettimezoneid.php
371 */
372 public function getTimeZoneId()
373 {
374 if (!$this->unitializedTimeZoneId) {
375 return $this->timeZoneId;
376 }
377
378 // In PHP 5.5 default timezone depends on `date_default_timezone_get()` method
379 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
380 return date_default_timezone_get();
381 }
382
383 return null;
384 }
385
386 /**
387 * Not supported. Returns the formatter's timezone
388 *
389 * @return mixed The timezone used by the formatter
390 *
391 * @see http://www.php.net/manual/en/intldateformatter.gettimezone.php
392 *
393 * @throws MethodNotImplementedException
394 */
395 public function getTimeZone()
396 {
397 throw new MethodNotImplementedException(__METHOD__);
398 }
399
400 /**
401 * Returns whether the formatter is lenient
402 *
403 * @return Boolean Currently always returns false.
404 *
405 * @see http://www.php.net/manual/en/intldateformatter.islenient.php
406 *
407 * @throws MethodNotImplementedException
408 */
409 public function isLenient()
410 {
411 return false;
412 }
413
414 /**
415 * Not supported. Parse string to a field-based time value
416 *
417 * @param string $value String to convert to a time value
418 * @param int $position Position at which to start the parsing in $value (zero-based).
419 * If no error occurs before $value is consumed, $parse_pos will
420 * contain -1 otherwise it will contain the position at which parsing
421 * ended. If $parse_pos > strlen($value), the parse fails immediately.
422 *
423 * @return string Localtime compatible array of integers: contains 24 hour clock value in tm_hour field
424 *
425 * @see http://www.php.net/manual/en/intldateformatter.localtime.php
426 *
427 * @throws MethodNotImplementedException
428 */
429 public function localtime($value, &$position = 0)
430 {
431 throw new MethodNotImplementedException(__METHOD__);
432 }
433
434 /**
435 * Parse string to a timestamp value
436 *
437 * @param string $value String to convert to a time value
438 * @param int $position Not supported. Position at which to start the parsing in $value (zero-based).
439 * If no error occurs before $value is consumed, $parse_pos will
440 * contain -1 otherwise it will contain the position at which parsing
441 * ended. If $parse_pos > strlen($value), the parse fails immediately.
442 *
443 * @return string Parsed value as a timestamp
444 *
445 * @see http://www.php.net/manual/en/intldateformatter.parse.php
446 *
447 * @throws MethodArgumentNotImplementedException When $position different than null, behavior not implemented
448 */
449 public function parse($value, &$position = null)
450 {
451 // We don't calculate the position when parsing the value
452 if (null !== $position) {
453 throw new MethodArgumentNotImplementedException(__METHOD__, 'position');
454 }
455
456 $dateTime = $this->createDateTime(0);
457 $transformer = new FullTransformer($this->getPattern(), $this->getTimeZoneId());
458
459 $timestamp = $transformer->parse($dateTime, $value);
460
461 // behave like the intl extension. FullTransformer::parse() set the proper error
462 $this->errorCode = IntlGlobals::getErrorCode();
463 $this->errorMessage = IntlGlobals::getErrorMessage();
464
465 return $timestamp;
466 }
467
468 /**
469 * Not supported. Set the formatter's calendar
470 *
471 * @param string $calendar The calendar to use. Default is IntlDateFormatter::GREGORIAN.
472 *
473 * @return Boolean true on success or false on failure
474 *
475 * @see http://www.php.net/manual/en/intldateformatter.setcalendar.php
476 *
477 * @throws MethodNotImplementedException
478 */
479 public function setCalendar($calendar)
480 {
481 throw new MethodNotImplementedException(__METHOD__);
482 }
483
484 /**
485 * Set the leniency of the parser
486 *
487 * Define if the parser is strict or lenient in interpreting inputs that do not match the pattern
488 * exactly. Enabling lenient parsing allows the parser to accept otherwise flawed date or time
489 * patterns, parsing as much as possible to obtain a value. Extra space, unrecognized tokens, or
490 * invalid values ("February 30th") are not accepted.
491 *
492 * @param Boolean $lenient Sets whether the parser is lenient or not. Currently
493 * only false (strict) is supported.
494 *
495 * @return Boolean true on success or false on failure
496 *
497 * @see http://www.php.net/manual/en/intldateformatter.setlenient.php
498 *
499 * @throws MethodArgumentValueNotImplementedException When $lenient is true
500 */
501 public function setLenient($lenient)
502 {
503 if ($lenient) {
504 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'lenient', $lenient, 'Only the strict parser is supported');
505 }
506
507 return true;
508 }
509
510 /**
511 * Set the formatter's pattern
512 *
513 * @param string $pattern A pattern string in conformance with the ICU IntlDateFormatter documentation
514 *
515 * @return Boolean true on success or false on failure
516 *
517 * @see http://www.php.net/manual/en/intldateformatter.setpattern.php
518 * @see http://userguide.icu-project.org/formatparse/datetime
519 */
520 public function setPattern($pattern)
521 {
522 if (null === $pattern) {
523 $pattern = $this->getDefaultPattern();
524 }
525
526 $this->pattern = $pattern;
527
528 return true;
529 }
530
531 /**
532 * Set the formatter's timezone identifier
533 *
534 * @param string $timeZoneId The time zone ID string of the time zone to use.
535 * If NULL or the empty string, the default time zone for the
536 * runtime is used.
537 *
538 * @return Boolean true on success or false on failure
539 *
540 * @see http://www.php.net/manual/en/intldateformatter.settimezoneid.php
541 */
542 public function setTimeZoneId($timeZoneId)
543 {
544 if (null === $timeZoneId) {
545 // In PHP 5.5 if $timeZoneId is null it fallbacks to `date_default_timezone_get()` method
546 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
547 $timeZoneId = date_default_timezone_get();
548 } else {
549 // TODO: changes were made to ext/intl in PHP 5.4.4 release that need to be investigated since it will
550 // use ini's date.timezone when the time zone is not provided. As a not well tested workaround, uses UTC.
551 // See the first two items of the commit message for more information:
552 // https://github.com/php/php-src/commit/eb346ef0f419b90739aadfb6cc7b7436c5b521d9
553 $timeZoneId = getenv('TZ') ?: 'UTC';
554 }
555
556 $this->unitializedTimeZoneId = true;
557 }
558
559 // Backup original passed time zone
560 $timeZone = $timeZoneId;
561
562 // Get an Etc/GMT time zone that is accepted for \DateTimeZone
563 if ('GMT' !== $timeZoneId && 0 === strpos($timeZoneId, 'GMT')) {
564 try {
565 $timeZoneId = DateFormat\TimeZoneTransformer::getEtcTimeZoneId($timeZoneId);
566 } catch (\InvalidArgumentException $e) {
567 // Does nothing, will fallback to UTC
568 }
569 }
570
571 try {
572 $this->dateTimeZone = new \DateTimeZone($timeZoneId);
573 } catch (\Exception $e) {
574 $this->dateTimeZone = new \DateTimeZone('UTC');
575 }
576
577 $this->timeZoneId = $timeZone;
578
579 return true;
580 }
581
582 /**
583 * This method was added in PHP 5.5 as replacement for `setTimeZoneId()`
584 *
585 * @param mixed $timeZone
586 *
587 * @return Boolean true on success or false on failure
588 *
589 * @see http://www.php.net/manual/en/intldateformatter.settimezone.php
590 */
591 public function setTimeZone($timeZone)
592 {
593 return $this->setTimeZoneId($timeZone);
594 }
595
596 /**
597 * Create and returns a DateTime object with the specified timestamp and with the
598 * current time zone
599 *
600 * @param int $timestamp
601 *
602 * @return \DateTime
603 */
604 protected function createDateTime($timestamp)
605 {
606 $dateTime = new \DateTime();
607 $dateTime->setTimestamp($timestamp);
608 $dateTime->setTimezone($this->dateTimeZone);
609
610 return $dateTime;
611 }
612
613 /**
614 * Returns a pattern string based in the datetype and timetype values
615 *
616 * @return string
617 */
618 protected function getDefaultPattern()
619 {
620 $patternParts = array();
621 if (self::NONE !== $this->datetype) {
622 $patternParts[] = $this->defaultDateFormats[$this->datetype];
623 }
624 if (self::NONE !== $this->timetype) {
625 $patternParts[] = $this->defaultTimeFormats[$this->timetype];
626 }
627 $pattern = implode(' ', $patternParts);
628
629 return $pattern;
630 }
631}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Exception/BadMethodCallException.php b/vendor/symfony/intl/Symfony/Component/Intl/Exception/BadMethodCallException.php
new file mode 100644
index 00000000..ca79729f
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Exception/BadMethodCallException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Exception;
13
14/**
15 * Base BadMethodCallException for the Intl component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Exception/ExceptionInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..4fc076ca
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Exception/ExceptionInterface.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Exception;
13
14/**
15 * Base ExceptionInterface for the Intl component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface ExceptionInterface
20{
21}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Exception/InvalidArgumentException.php b/vendor/symfony/intl/Symfony/Component/Intl/Exception/InvalidArgumentException.php
new file mode 100644
index 00000000..10f69ee3
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Exception/InvalidArgumentException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Exception;
13
14/**
15 * InvalidArgumentException for the Intl component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodArgumentNotImplementedException.php b/vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodArgumentNotImplementedException.php
new file mode 100644
index 00000000..570609d0
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodArgumentNotImplementedException.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Exception;
13
14use Symfony\Component\Intl\Exception\NotImplementedException;
15
16/**
17 * @author Eriksen Costa <eriksen.costa@infranology.com.br>
18 */
19class MethodArgumentNotImplementedException extends NotImplementedException
20{
21 /**
22 * Constructor
23 *
24 * @param string $methodName The method name that raised the exception
25 * @param string $argName The argument name that is not implemented
26 */
27 public function __construct($methodName, $argName)
28 {
29 $message = sprintf('The %s() method\'s argument $%s behavior is not implemented.', $methodName, $argName);
30 parent::__construct($message);
31 }
32}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodArgumentValueNotImplementedException.php b/vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodArgumentValueNotImplementedException.php
new file mode 100644
index 00000000..76e3f634
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodArgumentValueNotImplementedException.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Exception;
13
14use Symfony\Component\Intl\Exception\NotImplementedException;
15
16/**
17 * @author Eriksen Costa <eriksen.costa@infranology.com.br>
18 */
19class MethodArgumentValueNotImplementedException extends NotImplementedException
20{
21 /**
22 * Constructor
23 *
24 * @param string $methodName The method name that raised the exception
25 * @param string $argName The argument name
26 * @param string $argValue The argument value that is not implemented
27 * @param string $additionalMessage An optional additional message to append to the exception message
28 */
29 public function __construct($methodName, $argName, $argValue, $additionalMessage = '')
30 {
31 $message = sprintf(
32 'The %s() method\'s argument $%s value %s behavior is not implemented.%s',
33 $methodName,
34 $argName,
35 var_export($argValue, true),
36 $additionalMessage !== '' ? ' '.$additionalMessage.'. ' : ''
37 );
38
39 parent::__construct($message);
40 }
41}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodNotImplementedException.php b/vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodNotImplementedException.php
new file mode 100644
index 00000000..d8a0e90f
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Exception/MethodNotImplementedException.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Exception;
13
14/**
15 * @author Eriksen Costa <eriksen.costa@infranology.com.br>
16 */
17class MethodNotImplementedException extends NotImplementedException
18{
19 /**
20 * Constructor
21 *
22 * @param string $methodName The name of the method
23 */
24 public function __construct($methodName)
25 {
26 parent::__construct(sprintf('The %s() is not implemented.', $methodName));
27 }
28}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Exception/NotImplementedException.php b/vendor/symfony/intl/Symfony/Component/Intl/Exception/NotImplementedException.php
new file mode 100644
index 00000000..1f3ba46b
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Exception/NotImplementedException.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Exception;
13
14/**
15 * Base exception class for not implemented behaviors of the intl extension in the Locale component.
16 *
17 * @author Eriksen Costa <eriksen.costa@infranology.com.br>
18 */
19class NotImplementedException extends RuntimeException
20{
21 const INTL_INSTALL_MESSAGE = 'Please install the "intl" extension for full localization capabilities.';
22
23 /**
24 * Constructor
25 *
26 * @param string $message The exception message. A note to install the intl extension is appended to this string
27 */
28 public function __construct($message)
29 {
30 parent::__construct($message.' '.self::INTL_INSTALL_MESSAGE);
31 }
32}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Exception/OutOfBoundsException.php b/vendor/symfony/intl/Symfony/Component/Intl/Exception/OutOfBoundsException.php
new file mode 100644
index 00000000..2727141d
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Exception/OutOfBoundsException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Exception;
13
14/**
15 * Base OutOfBoundsException for the Intl component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Exception/RuntimeException.php b/vendor/symfony/intl/Symfony/Component/Intl/Exception/RuntimeException.php
new file mode 100644
index 00000000..98937142
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Exception/RuntimeException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Exception;
13
14/**
15 * RuntimeException for the Intl component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class RuntimeException extends \RuntimeException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Globals/IntlGlobals.php b/vendor/symfony/intl/Symfony/Component/Intl/Globals/IntlGlobals.php
new file mode 100644
index 00000000..6da00011
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Globals/IntlGlobals.php
@@ -0,0 +1,137 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Globals;
13
14/**
15 * Provides fake static versions of the global functions in the intl extension
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19abstract class IntlGlobals
20{
21 /**
22 * Indicates that no error occurred
23 *
24 * @var integer
25 */
26 const U_ZERO_ERROR = 0;
27
28 /**
29 * Indicates that an invalid argument was passed
30 *
31 * @var integer
32 */
33 const U_ILLEGAL_ARGUMENT_ERROR = 1;
34
35 /**
36 * Indicates that the parse() operation failed
37 *
38 * @var integer
39 */
40 const U_PARSE_ERROR = 9;
41
42 /**
43 * All known error codes
44 *
45 * @var array
46 */
47 private static $errorCodes = array(
48 self::U_ZERO_ERROR => 'U_ZERO_ERROR',
49 self::U_ILLEGAL_ARGUMENT_ERROR => 'U_ILLEGAL_ARGUMENT_ERROR',
50 self::U_PARSE_ERROR => 'U_PARSE_ERROR',
51 );
52
53 /**
54 * The error code of the last operation
55 *
56 * @var integer
57 */
58 private static $errorCode = self::U_ZERO_ERROR;
59
60 /**
61 * The error code of the last operation
62 *
63 * @var integer
64 */
65 private static $errorMessage = 'U_ZERO_ERROR';
66
67 /**
68 * Returns whether the error code indicates a failure
69 *
70 * @param integer $errorCode The error code returned by IntlGlobals::getErrorCode()
71 *
72 * @return Boolean
73 */
74 public static function isFailure($errorCode)
75 {
76 return isset(self::$errorCodes[$errorCode])
77 && $errorCode > self::U_ZERO_ERROR;
78 }
79
80 /**
81 * Returns the error code of the last operation
82 *
83 * Returns IntlGlobals::U_ZERO_ERROR if no error occurred.
84 *
85 * @return integer
86 */
87 public static function getErrorCode()
88 {
89 return self::$errorCode;
90 }
91
92 /**
93 * Returns the error message of the last operation
94 *
95 * Returns "U_ZERO_ERROR" if no error occurred.
96 *
97 * @return string
98 */
99 public static function getErrorMessage()
100 {
101 return self::$errorMessage;
102 }
103
104 /**
105 * Returns the symbolic name for a given error code
106 *
107 * @param integer $code The error code returned by IntlGlobals::getErrorCode()
108 *
109 * @return string
110 */
111 public static function getErrorName($code)
112 {
113 if (isset(self::$errorCodes[$code])) {
114 return self::$errorCodes[$code];
115 }
116
117 return '[BOGUS UErrorCode]';
118 }
119
120 /**
121 * Sets the current error
122 *
123 * @param integer $code One of the error constants in this class
124 * @param string $message The ICU class error message
125 *
126 * @throws \InvalidArgumentException If the code is not one of the error constants in this class
127 */
128 public static function setError($code, $message = '')
129 {
130 if (!isset(self::$errorCodes[$code])) {
131 throw new \InvalidArgumentException(sprintf('No such error code: "%s"', $code));
132 }
133
134 self::$errorMessage = $message ? sprintf('%s: %s', $message, self::$errorCodes[$code]) : self::$errorCodes[$code];
135 self::$errorCode = $code;
136 }
137}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Intl.php b/vendor/symfony/intl/Symfony/Component/Intl/Intl.php
new file mode 100644
index 00000000..c13899a4
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Intl.php
@@ -0,0 +1,211 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl;
13
14use Symfony\Component\Icu\IcuCurrencyBundle;
15use Symfony\Component\Icu\IcuData;
16use Symfony\Component\Icu\IcuLanguageBundle;
17use Symfony\Component\Icu\IcuLocaleBundle;
18use Symfony\Component\Icu\IcuRegionBundle;
19use Symfony\Component\Intl\ResourceBundle\Reader\BufferedBundleReader;
20use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReader;
21
22/**
23 * Gives access to internationalization data.
24 *
25 * @author Bernhard Schussek <bschussek@gmail.com>
26 */
27class Intl
28{
29 /**
30 * The number of resource bundles to buffer. Loading the same resource
31 * bundle for n locales takes up n spots in the buffer.
32 */
33 const BUFFER_SIZE = 10;
34
35 /**
36 * @var ResourceBundle\CurrencyBundleInterface
37 */
38 private static $currencyBundle;
39
40 /**
41 * @var ResourceBundle\LanguageBundleInterface
42 */
43 private static $languageBundle;
44
45 /**
46 * @var ResourceBundle\LocaleBundleInterface
47 */
48 private static $localeBundle;
49
50 /**
51 * @var ResourceBundle\RegionBundleInterface
52 */
53 private static $regionBundle;
54
55 /**
56 * @var string|Boolean|null
57 */
58 private static $icuVersion = false;
59
60 /**
61 * @var string
62 */
63 private static $icuDataVersion = false;
64
65 /**
66 * @var ResourceBundle\Reader\StructuredBundleReaderInterface
67 */
68 private static $bundleReader;
69
70 /**
71 * Returns whether the intl extension is installed.
72 *
73 * @return Boolean Returns true if the intl extension is installed, false otherwise.
74 */
75 public static function isExtensionLoaded()
76 {
77 return class_exists('\ResourceBundle');
78 }
79
80 /**
81 * Returns the bundle containing currency information.
82 *
83 * @return ResourceBundle\CurrencyBundleInterface The currency resource bundle.
84 */
85 public static function getCurrencyBundle()
86 {
87 if (null === self::$currencyBundle) {
88 self::$currencyBundle = new IcuCurrencyBundle(self::getBundleReader());
89 }
90
91 return self::$currencyBundle;
92 }
93
94 /**
95 * Returns the bundle containing language information.
96 *
97 * @return ResourceBundle\LanguageBundleInterface The language resource bundle.
98 */
99 public static function getLanguageBundle()
100 {
101 if (null === self::$languageBundle) {
102 self::$languageBundle = new IcuLanguageBundle(self::getBundleReader());
103 }
104
105 return self::$languageBundle;
106 }
107
108 /**
109 * Returns the bundle containing locale information.
110 *
111 * @return ResourceBundle\LocaleBundleInterface The locale resource bundle.
112 */
113 public static function getLocaleBundle()
114 {
115 if (null === self::$localeBundle) {
116 self::$localeBundle = new IcuLocaleBundle(self::getBundleReader());
117 }
118
119 return self::$localeBundle;
120 }
121
122 /**
123 * Returns the bundle containing region information.
124 *
125 * @return ResourceBundle\RegionBundleInterface The region resource bundle.
126 */
127 public static function getRegionBundle()
128 {
129 if (null === self::$regionBundle) {
130 self::$regionBundle = new IcuRegionBundle(self::getBundleReader());
131 }
132
133 return self::$regionBundle;
134 }
135
136 /**
137 * Returns the version of the installed ICU library.
138 *
139 * @return null|string The ICU version or NULL if it could not be determined.
140 */
141 public static function getIcuVersion()
142 {
143 if (false === self::$icuVersion) {
144 if (!self::isExtensionLoaded()) {
145 self::$icuVersion = self::getIcuStubVersion();
146 } elseif (defined('INTL_ICU_VERSION')) {
147 self::$icuVersion = INTL_ICU_VERSION;
148 } else {
149 try {
150 $reflector = new \ReflectionExtension('intl');
151 ob_start();
152 $reflector->info();
153 $output = strip_tags(ob_get_clean());
154 preg_match('/^ICU version (?:=>)?(.*)$/m', $output, $matches);
155
156 self::$icuVersion = trim($matches[1]);
157 } catch (\ReflectionException $e) {
158 self::$icuVersion = null;
159 }
160 }
161 }
162
163 return self::$icuVersion;
164 }
165
166 /**
167 * Returns the version of the installed ICU data.
168 *
169 * @return string The version of the installed ICU data.
170 */
171 public static function getIcuDataVersion()
172 {
173 if (false === self::$icuDataVersion) {
174 self::$icuDataVersion = IcuData::getVersion();
175 }
176
177 return self::$icuDataVersion;
178 }
179
180 /**
181 * Returns the ICU version that the stub classes mimic.
182 *
183 * @return string The ICU version of the stub classes.
184 */
185 public static function getIcuStubVersion()
186 {
187 return '50.1.2';
188 }
189
190 /**
191 * Returns a resource bundle reader for .php resource bundle files.
192 *
193 * @return ResourceBundle\Reader\StructuredBundleReaderInterface The resource reader.
194 */
195 private static function getBundleReader()
196 {
197 if (null === self::$bundleReader) {
198 self::$bundleReader = new StructuredBundleReader(new BufferedBundleReader(
199 IcuData::getBundleReader(),
200 self::BUFFER_SIZE
201 ));
202 }
203
204 return self::$bundleReader;
205 }
206
207 /**
208 * This class must not be instantiated.
209 */
210 private function __construct() {}
211}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/LICENSE b/vendor/symfony/intl/Symfony/Component/Intl/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Locale/Locale.php b/vendor/symfony/intl/Symfony/Component/Intl/Locale/Locale.php
new file mode 100644
index 00000000..cca4e9e4
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Locale/Locale.php
@@ -0,0 +1,317 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Locale;
13
14use Symfony\Component\Intl\Exception\MethodNotImplementedException;
15
16/**
17 * Replacement for PHP's native {@link \Locale} class.
18 *
19 * The only method supported in this class is {@link getDefault}. This method
20 * will always return "en". All other methods will throw an exception when used.
21 *
22 * @author Eriksen Costa <eriksen.costa@infranology.com.br>
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class Locale
26{
27 const DEFAULT_LOCALE = null;
28
29 /* Locale method constants */
30 const ACTUAL_LOCALE = 0;
31 const VALID_LOCALE = 1;
32
33 /* Language tags constants */
34 const LANG_TAG = 'language';
35 const EXTLANG_TAG = 'extlang';
36 const SCRIPT_TAG = 'script';
37 const REGION_TAG = 'region';
38 const VARIANT_TAG = 'variant';
39 const GRANDFATHERED_LANG_TAG = 'grandfathered';
40 const PRIVATE_TAG = 'private';
41
42 /**
43 * Not supported. Returns the best available locale based on HTTP "Accept-Language" header according to RFC 2616
44 *
45 * @param string $header The string containing the "Accept-Language" header value
46 *
47 * @return string The corresponding locale code
48 *
49 * @see http://www.php.net/manual/en/locale.acceptfromhttp.php
50 *
51 * @throws MethodNotImplementedException
52 */
53 public static function acceptFromHttp($header)
54 {
55 throw new MethodNotImplementedException(__METHOD__);
56 }
57
58 /**
59 * Not supported. Returns a correctly ordered and delimited locale code
60 *
61 * @param array $subtags A keyed array where the keys identify the particular locale code subtag
62 *
63 * @return string The corresponding locale code
64 *
65 * @see http://www.php.net/manual/en/locale.composelocale.php
66 *
67 * @throws MethodNotImplementedException
68 */
69 public static function composeLocale(array $subtags)
70 {
71 throw new MethodNotImplementedException(__METHOD__);
72 }
73
74 /**
75 * Not supported. Checks if a language tag filter matches with locale
76 *
77 * @param string $langtag The language tag to check
78 * @param string $locale The language range to check against
79 * @param Boolean $canonicalize
80 *
81 * @return string The corresponding locale code
82 *
83 * @see http://www.php.net/manual/en/locale.filtermatches.php
84 *
85 * @throws MethodNotImplementedException
86 */
87 public static function filterMatches($langtag, $locale, $canonicalize = false)
88 {
89 throw new MethodNotImplementedException(__METHOD__);
90 }
91
92 /**
93 * Not supported. Returns the variants for the input locale
94 *
95 * @param string $locale The locale to extract the variants from
96 *
97 * @return array The locale variants
98 *
99 * @see http://www.php.net/manual/en/locale.getallvariants.php
100 *
101 * @throws MethodNotImplementedException
102 */
103 public static function getAllVariants($locale)
104 {
105 throw new MethodNotImplementedException(__METHOD__);
106 }
107
108 /**
109 * Returns the default locale
110 *
111 * @return string The default locale code. Always returns 'en'
112 *
113 * @see http://www.php.net/manual/en/locale.getdefault.php
114 */
115 public static function getDefault()
116 {
117 return 'en';
118 }
119
120 /**
121 * Not supported. Returns the localized display name for the locale language
122 *
123 * @param string $locale The locale code to return the display language from
124 * @param string $inLocale Optional format locale code to use to display the language name
125 *
126 * @return string The localized language display name
127 *
128 * @see http://www.php.net/manual/en/locale.getdisplaylanguage.php
129 *
130 * @throws MethodNotImplementedException
131 */
132 public static function getDisplayLanguage($locale, $inLocale = null)
133 {
134 throw new MethodNotImplementedException(__METHOD__);
135 }
136
137 /**
138 * Not supported. Returns the localized display name for the locale
139 *
140 * @param string $locale The locale code to return the display locale name from
141 * @param string $inLocale Optional format locale code to use to display the locale name
142 *
143 * @return string The localized locale display name
144 *
145 * @see http://www.php.net/manual/en/locale.getdisplayname.php
146 *
147 * @throws MethodNotImplementedException
148 */
149 public static function getDisplayName($locale, $inLocale = null)
150 {
151 throw new MethodNotImplementedException(__METHOD__);
152 }
153
154 /**
155 * Not supported. Returns the localized display name for the locale region
156 *
157 * @param string $locale The locale code to return the display region from
158 * @param string $inLocale Optional format locale code to use to display the region name
159 *
160 * @return string The localized region display name
161 *
162 * @see http://www.php.net/manual/en/locale.getdisplayregion.php
163 *
164 * @throws MethodNotImplementedException
165 */
166 public static function getDisplayRegion($locale, $inLocale = null)
167 {
168 throw new MethodNotImplementedException(__METHOD__);
169 }
170
171 /**
172 * Not supported. Returns the localized display name for the locale script
173 *
174 * @param string $locale The locale code to return the display script from
175 * @param string $inLocale Optional format locale code to use to display the script name
176 *
177 * @return string The localized script display name
178 *
179 * @see http://www.php.net/manual/en/locale.getdisplayscript.php
180 *
181 * @throws MethodNotImplementedException
182 */
183 public static function getDisplayScript($locale, $inLocale = null)
184 {
185 throw new MethodNotImplementedException(__METHOD__);
186 }
187
188 /**
189 * Not supported. Returns the localized display name for the locale variant
190 *
191 * @param string $locale The locale code to return the display variant from
192 * @param string $inLocale Optional format locale code to use to display the variant name
193 *
194 * @return string The localized variant display name
195 *
196 * @see http://www.php.net/manual/en/locale.getdisplayvariant.php
197 *
198 * @throws MethodNotImplementedException
199 */
200 public static function getDisplayVariant($locale, $inLocale = null)
201 {
202 throw new MethodNotImplementedException(__METHOD__);
203 }
204
205 /**
206 * Not supported. Returns the keywords for the locale
207 *
208 * @param string $locale The locale code to extract the keywords from
209 *
210 * @return array Associative array with the extracted variants
211 *
212 * @see http://www.php.net/manual/en/locale.getkeywords.php
213 *
214 * @throws MethodNotImplementedException
215 */
216 public static function getKeywords($locale)
217 {
218 throw new MethodNotImplementedException(__METHOD__);
219 }
220
221 /**
222 * Not supported. Returns the primary language for the locale
223 *
224 * @param string $locale The locale code to extract the language code from
225 *
226 * @return string|null The extracted language code or null in case of error
227 *
228 * @see http://www.php.net/manual/en/locale.getprimarylanguage.php
229 *
230 * @throws MethodNotImplementedException
231 */
232 public static function getPrimaryLanguage($locale)
233 {
234 throw new MethodNotImplementedException(__METHOD__);
235 }
236
237 /**
238 * Not supported. Returns the region for the locale
239 *
240 * @param string $locale The locale code to extract the region code from
241 *
242 * @return string|null The extracted region code or null if not present
243 *
244 * @see http://www.php.net/manual/en/locale.getregion.php
245 *
246 * @throws MethodNotImplementedException
247 */
248 public static function getRegion($locale)
249 {
250 throw new MethodNotImplementedException(__METHOD__);
251 }
252
253 /**
254 * Not supported. Returns the script for the locale
255 *
256 * @param string $locale The locale code to extract the script code from
257 *
258 * @return string|null The extracted script code or null if not present
259 *
260 * @see http://www.php.net/manual/en/locale.getscript.php
261 *
262 * @throws MethodNotImplementedException
263 */
264 public static function getScript($locale)
265 {
266 throw new MethodNotImplementedException(__METHOD__);
267 }
268
269 /**
270 * Not supported. Returns the closest language tag for the locale
271 *
272 * @param array $langtag A list of the language tags to compare to locale
273 * @param string $locale The locale to use as the language range when matching
274 * @param Boolean $canonicalize If true, the arguments will be converted to canonical form before matching
275 * @param string $default The locale to use if no match is found
276 *
277 * @see http://www.php.net/manual/en/locale.lookup.php
278 *
279 * @throws MethodNotImplementedException
280 */
281 public static function lookup(array $langtag, $locale, $canonicalize = false, $default = null)
282 {
283 throw new MethodNotImplementedException(__METHOD__);
284 }
285
286 /**
287 * Not supported. Returns an associative array of locale identifier subtags
288 *
289 * @param string $locale The locale code to extract the subtag array from
290 *
291 * @return array Associative array with the extracted subtags
292 *
293 * @see http://www.php.net/manual/en/locale.parselocale.php
294 *
295 * @throws MethodNotImplementedException
296 */
297 public static function parseLocale($locale)
298 {
299 throw new MethodNotImplementedException(__METHOD__);
300 }
301
302 /**
303 * Not supported. Sets the default runtime locale
304 *
305 * @param string $locale The locale code
306 *
307 * @return Boolean true on success or false on failure
308 *
309 * @see http://www.php.net/manual/en/locale.parselocale.php
310 *
311 * @throws MethodNotImplementedException
312 */
313 public static function setDefault($locale)
314 {
315 throw new MethodNotImplementedException(__METHOD__);
316 }
317}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/vendor/symfony/intl/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php
new file mode 100644
index 00000000..0e5652e2
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php
@@ -0,0 +1,891 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\NumberFormatter;
13
14use Symfony\Component\Intl\Exception\NotImplementedException;
15use Symfony\Component\Intl\Exception\MethodNotImplementedException;
16use Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException;
17use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException;
18use Symfony\Component\Intl\Globals\IntlGlobals;
19use Symfony\Component\Intl\Intl;
20use Symfony\Component\Intl\Locale\Locale;
21
22/**
23 * Replacement for PHP's native {@link \NumberFormatter} class.
24 *
25 * The only methods currently supported in this class are:
26 *
27 * - {@link __construct}
28 * - {@link create}
29 * - {@link formatCurrency}
30 * - {@link format}
31 * - {@link getAttribute}
32 * - {@link getErrorCode}
33 * - {@link getErrorMessage}
34 * - {@link getLocale}
35 * - {@link parse}
36 * - {@link setAttribute}
37 *
38 * @author Eriksen Costa <eriksen.costa@infranology.com.br>
39 * @author Bernhard Schussek <bschussek@gmail.com>
40 */
41class NumberFormatter
42{
43 /* Format style constants */
44 const PATTERN_DECIMAL = 0;
45 const DECIMAL = 1;
46 const CURRENCY = 2;
47 const PERCENT = 3;
48 const SCIENTIFIC = 4;
49 const SPELLOUT = 5;
50 const ORDINAL = 6;
51 const DURATION = 7;
52 const PATTERN_RULEBASED = 9;
53 const IGNORE = 0;
54 const DEFAULT_STYLE = 1;
55
56 /* Format type constants */
57 const TYPE_DEFAULT = 0;
58 const TYPE_INT32 = 1;
59 const TYPE_INT64 = 2;
60 const TYPE_DOUBLE = 3;
61 const TYPE_CURRENCY = 4;
62
63 /* Numeric attribute constants */
64 const PARSE_INT_ONLY = 0;
65 const GROUPING_USED = 1;
66 const DECIMAL_ALWAYS_SHOWN = 2;
67 const MAX_INTEGER_DIGITS = 3;
68 const MIN_INTEGER_DIGITS = 4;
69 const INTEGER_DIGITS = 5;
70 const MAX_FRACTION_DIGITS = 6;
71 const MIN_FRACTION_DIGITS = 7;
72 const FRACTION_DIGITS = 8;
73 const MULTIPLIER = 9;
74 const GROUPING_SIZE = 10;
75 const ROUNDING_MODE = 11;
76 const ROUNDING_INCREMENT = 12;
77 const FORMAT_WIDTH = 13;
78 const PADDING_POSITION = 14;
79 const SECONDARY_GROUPING_SIZE = 15;
80 const SIGNIFICANT_DIGITS_USED = 16;
81 const MIN_SIGNIFICANT_DIGITS = 17;
82 const MAX_SIGNIFICANT_DIGITS = 18;
83 const LENIENT_PARSE = 19;
84
85 /* Text attribute constants */
86 const POSITIVE_PREFIX = 0;
87 const POSITIVE_SUFFIX = 1;
88 const NEGATIVE_PREFIX = 2;
89 const NEGATIVE_SUFFIX = 3;
90 const PADDING_CHARACTER = 4;
91 const CURRENCY_CODE = 5;
92 const DEFAULT_RULESET = 6;
93 const PUBLIC_RULESETS = 7;
94
95 /* Format symbol constants */
96 const DECIMAL_SEPARATOR_SYMBOL = 0;
97 const GROUPING_SEPARATOR_SYMBOL = 1;
98 const PATTERN_SEPARATOR_SYMBOL = 2;
99 const PERCENT_SYMBOL = 3;
100 const ZERO_DIGIT_SYMBOL = 4;
101 const DIGIT_SYMBOL = 5;
102 const MINUS_SIGN_SYMBOL = 6;
103 const PLUS_SIGN_SYMBOL = 7;
104 const CURRENCY_SYMBOL = 8;
105 const INTL_CURRENCY_SYMBOL = 9;
106 const MONETARY_SEPARATOR_SYMBOL = 10;
107 const EXPONENTIAL_SYMBOL = 11;
108 const PERMILL_SYMBOL = 12;
109 const PAD_ESCAPE_SYMBOL = 13;
110 const INFINITY_SYMBOL = 14;
111 const NAN_SYMBOL = 15;
112 const SIGNIFICANT_DIGIT_SYMBOL = 16;
113 const MONETARY_GROUPING_SEPARATOR_SYMBOL = 17;
114
115 /* Rounding mode values used by NumberFormatter::setAttribute() with NumberFormatter::ROUNDING_MODE attribute */
116 const ROUND_CEILING = 0;
117 const ROUND_FLOOR = 1;
118 const ROUND_DOWN = 2;
119 const ROUND_UP = 3;
120 const ROUND_HALFEVEN = 4;
121 const ROUND_HALFDOWN = 5;
122 const ROUND_HALFUP = 6;
123
124 /* Pad position values used by NumberFormatter::setAttribute() with NumberFormatter::PADDING_POSITION attribute */
125 const PAD_BEFORE_PREFIX = 0;
126 const PAD_AFTER_PREFIX = 1;
127 const PAD_BEFORE_SUFFIX = 2;
128 const PAD_AFTER_SUFFIX = 3;
129
130 /**
131 * The error code from the last operation
132 *
133 * @var integer
134 */
135 protected $errorCode = IntlGlobals::U_ZERO_ERROR;
136
137 /**
138 * The error message from the last operation
139 *
140 * @var string
141 */
142 protected $errorMessage = 'U_ZERO_ERROR';
143
144 /**
145 * @var int
146 */
147 private $style;
148
149 /**
150 * Default values for the en locale
151 *
152 * @var array
153 */
154 private $attributes = array(
155 self::FRACTION_DIGITS => 0,
156 self::GROUPING_USED => 1,
157 self::ROUNDING_MODE => self::ROUND_HALFEVEN
158 );
159
160 /**
161 * Holds the initialized attributes code
162 *
163 * @var array
164 */
165 private $initializedAttributes = array();
166
167 /**
168 * The supported styles to the constructor $styles argument
169 *
170 * @var array
171 */
172 private static $supportedStyles = array(
173 'CURRENCY' => self::CURRENCY,
174 'DECIMAL' => self::DECIMAL
175 );
176
177 /**
178 * Supported attributes to the setAttribute() $attr argument
179 *
180 * @var array
181 */
182 private static $supportedAttributes = array(
183 'FRACTION_DIGITS' => self::FRACTION_DIGITS,
184 'GROUPING_USED' => self::GROUPING_USED,
185 'ROUNDING_MODE' => self::ROUNDING_MODE
186 );
187
188 /**
189 * The available rounding modes for setAttribute() usage with
190 * NumberFormatter::ROUNDING_MODE. NumberFormatter::ROUND_DOWN
191 * and NumberFormatter::ROUND_UP does not have a PHP only equivalent
192 *
193 * @var array
194 */
195 private static $roundingModes = array(
196 'ROUND_HALFEVEN' => self::ROUND_HALFEVEN,
197 'ROUND_HALFDOWN' => self::ROUND_HALFDOWN,
198 'ROUND_HALFUP' => self::ROUND_HALFUP
199 );
200
201 /**
202 * The mapping between NumberFormatter rounding modes to the available
203 * modes in PHP's round() function.
204 *
205 * @see http://www.php.net/manual/en/function.round.php
206 *
207 * @var array
208 */
209 private static $phpRoundingMap = array(
210 self::ROUND_HALFDOWN => \PHP_ROUND_HALF_DOWN,
211 self::ROUND_HALFEVEN => \PHP_ROUND_HALF_EVEN,
212 self::ROUND_HALFUP => \PHP_ROUND_HALF_UP
213 );
214
215 /**
216 * The maximum values of the integer type in 32 bit platforms.
217 *
218 * @var array
219 */
220 private static $int32Range = array(
221 'positive' => 2147483647,
222 'negative' => -2147483648
223 );
224
225 /**
226 * The maximum values of the integer type in 64 bit platforms.
227 *
228 * @var array
229 */
230 private static $int64Range = array(
231 'positive' => 9223372036854775807,
232 'negative' => -9223372036854775808
233 );
234
235 /**
236 * Constructor.
237 *
238 * @param string $locale The locale code. The only currently supported locale is "en".
239 * @param int $style Style of the formatting, one of the format style constants.
240 * The only supported styles are NumberFormatter::DECIMAL
241 * and NumberFormatter::CURRENCY.
242 * @param string $pattern Not supported. A pattern string in case $style is NumberFormat::PATTERN_DECIMAL or
243 * NumberFormat::PATTERN_RULEBASED. It must conform to the syntax
244 * described in the ICU DecimalFormat or ICU RuleBasedNumberFormat documentation
245 *
246 * @see http://www.php.net/manual/en/numberformatter.create.php
247 * @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
248 * @see http://www.icu-project.org/apiref/icu4c/classRuleBasedNumberFormat.html#_details
249 *
250 * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
251 * @throws MethodArgumentValueNotImplementedException When the $style is not supported
252 * @throws MethodArgumentNotImplementedException When the pattern value is different than null
253 */
254 public function __construct($locale = 'en', $style = null, $pattern = null)
255 {
256 if ('en' != $locale) {
257 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the locale "en" is supported');
258 }
259
260 if (!in_array($style, self::$supportedStyles)) {
261 $message = sprintf('The available styles are: %s.', implode(', ', array_keys(self::$supportedStyles)));
262 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'style', $style, $message);
263 }
264
265 if (null !== $pattern) {
266 throw new MethodArgumentNotImplementedException(__METHOD__, 'pattern');
267 }
268
269 $this->style = $style;
270 }
271
272 /**
273 * Static constructor.
274 *
275 * @param string $locale The locale code. The only supported locale is "en".
276 * @param int $style Style of the formatting, one of the format style constants.
277 * The only currently supported styles are NumberFormatter::DECIMAL
278 * and NumberFormatter::CURRENCY.
279 * @param string $pattern Not supported. A pattern string in case $style is NumberFormat::PATTERN_DECIMAL or
280 * NumberFormat::PATTERN_RULEBASED. It must conform to the syntax
281 * described in the ICU DecimalFormat or ICU RuleBasedNumberFormat documentation
282 *
283 * @return NumberFormatter
284 *
285 * @see http://www.php.net/manual/en/numberformatter.create.php
286 * @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
287 * @see http://www.icu-project.org/apiref/icu4c/classRuleBasedNumberFormat.html#_details
288 *
289 * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
290 * @throws MethodArgumentValueNotImplementedException When the $style is not supported
291 * @throws MethodArgumentNotImplementedException When the pattern value is different than null
292 */
293 public static function create($locale = 'en', $style = null, $pattern = null)
294 {
295 return new self($locale, $style, $pattern);
296 }
297
298 /**
299 * Format a currency value
300 *
301 * @param float $value The numeric currency value
302 * @param string $currency The 3-letter ISO 4217 currency code indicating the currency to use
303 *
304 * @return string The formatted currency value
305 *
306 * @see http://www.php.net/manual/en/numberformatter.formatcurrency.php
307 * @see http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm
308 */
309 public function formatCurrency($value, $currency)
310 {
311 if ($this->style == self::DECIMAL) {
312 return $this->format($value);
313 }
314
315 $symbol = Intl::getCurrencyBundle()->getCurrencySymbol($currency, 'en');
316 $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency);
317
318 $value = $this->roundCurrency($value, $currency);
319
320 $negative = false;
321 if (0 > $value) {
322 $negative = true;
323 $value *= -1;
324 }
325
326 $value = $this->formatNumber($value, $fractionDigits);
327
328 $ret = $symbol.$value;
329
330 return $negative ? '('.$ret.')' : $ret;
331 }
332
333 /**
334 * Format a number
335 *
336 * @param number $value The value to format
337 * @param int $type Type of the formatting, one of the format type constants.
338 * Only type NumberFormatter::TYPE_DEFAULT is currently supported.
339 *
340 * @return Boolean|string The formatted value or false on error
341 *
342 * @see http://www.php.net/manual/en/numberformatter.format.php
343 *
344 * @throws NotImplementedException If the method is called with the class $style 'CURRENCY'
345 * @throws MethodArgumentValueNotImplementedException If the $type is different than TYPE_DEFAULT
346 */
347 public function format($value, $type = self::TYPE_DEFAULT)
348 {
349 // The original NumberFormatter does not support this format type
350 if ($type == self::TYPE_CURRENCY) {
351 trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);
352
353 return false;
354 }
355
356 if ($this->style == self::CURRENCY) {
357 throw new NotImplementedException(sprintf(
358 '%s() method does not support the formatting of currencies (instance with CURRENCY style). %s',
359 __METHOD__, NotImplementedException::INTL_INSTALL_MESSAGE
360 ));
361 }
362
363 // Only the default type is supported.
364 if ($type != self::TYPE_DEFAULT) {
365 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'type', $type, 'Only TYPE_DEFAULT is supported');
366 }
367
368 $fractionDigits = $this->getAttribute(self::FRACTION_DIGITS);
369
370 $value = $this->round($value, $fractionDigits);
371 $value = $this->formatNumber($value, $fractionDigits);
372
373 // behave like the intl extension
374 $this->resetError();
375
376 return $value;
377 }
378
379 /**
380 * Returns an attribute value
381 *
382 * @param int $attr An attribute specifier, one of the numeric attribute constants
383 *
384 * @return Boolean|int The attribute value on success or false on error
385 *
386 * @see http://www.php.net/manual/en/numberformatter.getattribute.php
387 */
388 public function getAttribute($attr)
389 {
390 return isset($this->attributes[$attr]) ? $this->attributes[$attr] : null;
391 }
392
393 /**
394 * Returns formatter's last error code. Always returns the U_ZERO_ERROR class constant value
395 *
396 * @return int The error code from last formatter call
397 *
398 * @see http://www.php.net/manual/en/numberformatter.geterrorcode.php
399 */
400 public function getErrorCode()
401 {
402 return $this->errorCode;
403 }
404
405 /**
406 * Returns formatter's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value
407 *
408 * @return string The error message from last formatter call
409 *
410 * @see http://www.php.net/manual/en/numberformatter.geterrormessage.php
411 */
412 public function getErrorMessage()
413 {
414 return $this->errorMessage;
415 }
416
417 /**
418 * Returns the formatter's locale
419 *
420 * The parameter $type is currently ignored.
421 *
422 * @param int $type Not supported. The locale name type to return (Locale::VALID_LOCALE or Locale::ACTUAL_LOCALE)
423 *
424 * @return string The locale used to create the formatter. Currently always
425 * returns "en".
426 *
427 * @see http://www.php.net/manual/en/numberformatter.getlocale.php
428 */
429 public function getLocale($type = Locale::ACTUAL_LOCALE)
430 {
431 return 'en';
432 }
433
434 /**
435 * Not supported. Returns the formatter's pattern
436 *
437 * @return Boolean|string The pattern string used by the formatter or false on error
438 *
439 * @see http://www.php.net/manual/en/numberformatter.getpattern.php
440 *
441 * @throws MethodNotImplementedException
442 */
443 public function getPattern()
444 {
445 throw new MethodNotImplementedException(__METHOD__);
446 }
447
448 /**
449 * Not supported. Returns a formatter symbol value
450 *
451 * @param int $attr A symbol specifier, one of the format symbol constants
452 *
453 * @return Boolean|string The symbol value or false on error
454 *
455 * @see http://www.php.net/manual/en/numberformatter.getsymbol.php
456 *
457 * @throws MethodNotImplementedException
458 */
459 public function getSymbol($attr)
460 {
461 throw new MethodNotImplementedException(__METHOD__);
462 }
463
464 /**
465 * Not supported. Returns a formatter text attribute value
466 *
467 * @param int $attr An attribute specifier, one of the text attribute constants
468 *
469 * @return Boolean|string The attribute value or false on error
470 *
471 * @see http://www.php.net/manual/en/numberformatter.gettextattribute.php
472 *
473 * @throws MethodNotImplementedException
474 */
475 public function getTextAttribute($attr)
476 {
477 throw new MethodNotImplementedException(__METHOD__);
478 }
479
480 /**
481 * Not supported. Parse a currency number
482 *
483 * @param string $value The value to parse
484 * @param string $currency Parameter to receive the currency name (reference)
485 * @param int $position Offset to begin the parsing on return this value will hold the offset at which the parsing ended
486 *
487 * @return Boolean|string The parsed numeric value of false on error
488 *
489 * @see http://www.php.net/manual/en/numberformatter.parsecurrency.php
490 *
491 * @throws MethodNotImplementedException
492 */
493 public function parseCurrency($value, &$currency, &$position = null)
494 {
495 throw new MethodNotImplementedException(__METHOD__);
496 }
497
498 /**
499 * Parse a number
500 *
501 * @param string $value The value to parse
502 * @param int $type Type of the formatting, one of the format type constants.
503 * The only currently supported types are NumberFormatter::TYPE_DOUBLE,
504 * NumberFormatter::TYPE_INT32 and NumberFormatter::TYPE_INT64.
505 * @param int $position Not supported. Offset to begin the parsing on return this value will hold the offset at which the parsing ended
506 *
507 * @return Boolean|string The parsed value of false on error
508 *
509 * @see http://www.php.net/manual/en/numberformatter.parse.php
510 *
511 * @throws MethodArgumentNotImplementedException When $position different than null, behavior not implemented
512 */
513 public function parse($value, $type = self::TYPE_DOUBLE, &$position = null)
514 {
515 if ($type == self::TYPE_DEFAULT || $type == self::TYPE_CURRENCY) {
516 trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);
517
518 return false;
519 }
520
521 // We don't calculate the position when parsing the value
522 if (null !== $position) {
523 throw new MethodArgumentNotImplementedException(__METHOD__, 'position');
524 }
525
526 preg_match('/^([^0-9\-]{0,})(.*)/', $value, $matches);
527
528 // Any string before the numeric value causes error in the parsing
529 if (isset($matches[1]) && !empty($matches[1])) {
530 IntlGlobals::setError(IntlGlobals::U_PARSE_ERROR, 'Number parsing failed');
531 $this->errorCode = IntlGlobals::getErrorCode();
532 $this->errorMessage = IntlGlobals::getErrorMessage();
533
534 return false;
535 }
536
537 // Remove everything that is not number or dot (.)
538 $value = preg_replace('/[^0-9\.\-]/', '', $value);
539 $value = $this->convertValueDataType($value, $type);
540
541 // behave like the intl extension
542 $this->resetError();
543
544 return $value;
545 }
546
547 /**
548 * Set an attribute
549 *
550 * @param int $attr An attribute specifier, one of the numeric attribute constants.
551 * The only currently supported attributes are NumberFormatter::FRACTION_DIGITS,
552 * NumberFormatter::GROUPING_USED and NumberFormatter::ROUNDING_MODE.
553 * @param int $value The attribute value. The only currently supported rounding modes are
554 * NumberFormatter::ROUND_HALFEVEN, NumberFormatter::ROUND_HALFDOWN and
555 * NumberFormatter::ROUND_HALFUP.
556 *
557 * @return Boolean true on success or false on failure
558 *
559 * @see http://www.php.net/manual/en/numberformatter.setattribute.php
560 *
561 * @throws MethodArgumentValueNotImplementedException When the $attr is not supported
562 * @throws MethodArgumentValueNotImplementedException When the $value is not supported
563 */
564 public function setAttribute($attr, $value)
565 {
566 if (!in_array($attr, self::$supportedAttributes)) {
567 $message = sprintf(
568 'The available attributes are: %s',
569 implode(', ', array_keys(self::$supportedAttributes))
570 );
571
572 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'attr', $value, $message);
573 }
574
575 if (self::$supportedAttributes['ROUNDING_MODE'] == $attr && $this->isInvalidRoundingMode($value)) {
576 $message = sprintf(
577 'The supported values for ROUNDING_MODE are: %s',
578 implode(', ', array_keys(self::$roundingModes))
579 );
580
581 throw new MethodArgumentValueNotImplementedException(__METHOD__, 'attr', $value, $message);
582 }
583
584 if (self::$supportedAttributes['GROUPING_USED'] == $attr) {
585 $value = $this->normalizeGroupingUsedValue($value);
586 }
587
588 if (self::$supportedAttributes['FRACTION_DIGITS'] == $attr) {
589 $value = $this->normalizeFractionDigitsValue($value);
590 }
591
592 $this->attributes[$attr] = $value;
593 $this->initializedAttributes[$attr] = true;
594
595 return true;
596 }
597
598 /**
599 * Not supported. Set the formatter's pattern
600 *
601 * @param string $pattern A pattern string in conformance with the ICU DecimalFormat documentation
602 *
603 * @return Boolean true on success or false on failure
604 *
605 * @see http://www.php.net/manual/en/numberformatter.setpattern.php
606 * @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
607 *
608 * @throws MethodNotImplementedException
609 */
610 public function setPattern($pattern)
611 {
612 throw new MethodNotImplementedException(__METHOD__);
613 }
614
615 /**
616 * Not supported. Set the formatter's symbol
617 *
618 * @param int $attr A symbol specifier, one of the format symbol constants
619 * @param string $value The value for the symbol
620 *
621 * @return Boolean true on success or false on failure
622 *
623 * @see http://www.php.net/manual/en/numberformatter.setsymbol.php
624 *
625 * @throws MethodNotImplementedException
626 */
627 public function setSymbol($attr, $value)
628 {
629 throw new MethodNotImplementedException(__METHOD__);
630 }
631
632 /**
633 * Not supported. Set a text attribute
634 *
635 * @param int $attr An attribute specifier, one of the text attribute constants
636 * @param int $value The attribute value
637 *
638 * @return Boolean true on success or false on failure
639 *
640 * @see http://www.php.net/manual/en/numberformatter.settextattribute.php
641 *
642 * @throws MethodNotImplementedException
643 */
644 public function setTextAttribute($attr, $value)
645 {
646 throw new MethodNotImplementedException(__METHOD__);
647 }
648
649 /**
650 * Set the error to the default U_ZERO_ERROR
651 */
652 protected function resetError()
653 {
654 IntlGlobals::setError(IntlGlobals::U_ZERO_ERROR);
655 $this->errorCode = IntlGlobals::getErrorCode();
656 $this->errorMessage = IntlGlobals::getErrorMessage();
657 }
658
659 /**
660 * Rounds a currency value, applying increment rounding if applicable
661 *
662 * When a currency have a rounding increment, an extra round is made after the first one. The rounding factor is
663 * determined in the ICU data and is explained as of:
664 *
665 * "the rounding increment is given in units of 10^(-fraction_digits)"
666 *
667 * The only actual rounding data as of this writing, is CHF.
668 *
669 * @param float $value The numeric currency value
670 * @param string $currency The 3-letter ISO 4217 currency code indicating the currency to use
671 *
672 * @return string The rounded numeric currency value
673 *
674 * @see http://en.wikipedia.org/wiki/Swedish_rounding
675 * @see http://www.docjar.com/html/api/com/ibm/icu/util/Currency.java.html#1007
676 */
677 private function roundCurrency($value, $currency)
678 {
679 $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency);
680 $roundingIncrement = Intl::getCurrencyBundle()->getRoundingIncrement($currency);
681
682 // Round with the formatter rounding mode
683 $value = $this->round($value, $fractionDigits);
684
685 // Swiss rounding
686 if (0 < $roundingIncrement && 0 < $fractionDigits) {
687 $roundingFactor = $roundingIncrement / pow(10, $fractionDigits);
688 $value = round($value / $roundingFactor) * $roundingFactor;
689 }
690
691 return $value;
692 }
693
694 /**
695 * Rounds a value.
696 *
697 * @param integer|float $value The value to round
698 * @param int $precision The number of decimal digits to round to
699 *
700 * @return integer|float The rounded value
701 */
702 private function round($value, $precision)
703 {
704 $precision = $this->getUnitializedPrecision($value, $precision);
705
706 $roundingMode = self::$phpRoundingMap[$this->getAttribute(self::ROUNDING_MODE)];
707 $value = round($value, $precision, $roundingMode);
708
709 return $value;
710 }
711
712 /**
713 * Formats a number.
714 *
715 * @param integer|float $value The numeric value to format
716 * @param int $precision The number of decimal digits to use
717 *
718 * @return string The formatted number
719 */
720 private function formatNumber($value, $precision)
721 {
722 $precision = $this->getUnitializedPrecision($value, $precision);
723
724 return number_format($value, $precision, '.', $this->getAttribute(self::GROUPING_USED) ? ',' : '');
725 }
726
727 /**
728 * Returns the precision value if the DECIMAL style is being used and the FRACTION_DIGITS attribute is unitialized.
729 *
730 * @param integer|float $value The value to get the precision from if the FRACTION_DIGITS attribute is unitialized
731 * @param int $precision The precision value to returns if the FRACTION_DIGITS attribute is initialized
732 *
733 * @return int The precision value
734 */
735 private function getUnitializedPrecision($value, $precision)
736 {
737 if ($this->style == self::CURRENCY) {
738 return $precision;
739 }
740
741 if (!$this->isInitializedAttribute(self::FRACTION_DIGITS)) {
742 preg_match('/.*\.(.*)/', (string) $value, $digits);
743 if (isset($digits[1])) {
744 $precision = strlen($digits[1]);
745 }
746 }
747
748 return $precision;
749 }
750
751 /**
752 * Check if the attribute is initialized (value set by client code).
753 *
754 * @param string $attr The attribute name
755 *
756 * @return Boolean true if the value was set by client, false otherwise
757 */
758 private function isInitializedAttribute($attr)
759 {
760 return isset($this->initializedAttributes[$attr]);
761 }
762
763 /**
764 * Returns the numeric value using the $type to convert to the right data type.
765 *
766 * @param mixed $value The value to be converted
767 * @param int $type The type to convert. Can be TYPE_DOUBLE (float) or TYPE_INT32 (int)
768 *
769 * @return integer|float The converted value
770 */
771 private function convertValueDataType($value, $type)
772 {
773 if ($type == self::TYPE_DOUBLE) {
774 $value = (float) $value;
775 } elseif ($type == self::TYPE_INT32) {
776 $value = $this->getInt32Value($value);
777 } elseif ($type == self::TYPE_INT64) {
778 $value = $this->getInt64Value($value);
779 }
780
781 return $value;
782 }
783
784 /**
785 * Convert the value data type to int or returns false if the value is out of the integer value range.
786 *
787 * @param mixed $value The value to be converted
788 *
789 * @return int The converted value
790 */
791 private function getInt32Value($value)
792 {
793 if ($value > self::$int32Range['positive'] || $value < self::$int32Range['negative']) {
794 return false;
795 }
796
797 return (int) $value;
798 }
799
800 /**
801 * Convert the value data type to int or returns false if the value is out of the integer value range.
802 *
803 * @param mixed $value The value to be converted
804 *
805 * @return int|float The converted value
806 *
807 * @see https://bugs.php.net/bug.php?id=59597 Bug #59597
808 */
809 private function getInt64Value($value)
810 {
811 if ($value > self::$int64Range['positive'] || $value < self::$int64Range['negative']) {
812 return false;
813 }
814
815 if (PHP_INT_SIZE !== 8 && ($value > self::$int32Range['positive'] || $value <= self::$int32Range['negative'])) {
816 // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
817 // The negative PHP_INT_MAX was being converted to float
818 if (
819 $value == self::$int32Range['negative'] &&
820 (
821 (version_compare(PHP_VERSION, '5.4.0', '<') && version_compare(PHP_VERSION, '5.3.14', '>=')) ||
822 version_compare(PHP_VERSION, '5.4.4', '>=')
823 )
824 ) {
825 return (int) $value;
826 }
827
828 return (float) $value;
829 }
830
831 if (PHP_INT_SIZE === 8) {
832 // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
833 // A 32 bit integer was being generated instead of a 64 bit integer
834 if (
835 ($value > self::$int32Range['positive'] || $value < self::$int32Range['negative']) &&
836 (
837 (version_compare(PHP_VERSION, '5.3.14', '<')) ||
838 (version_compare(PHP_VERSION, '5.4.0', '>=') && version_compare(PHP_VERSION, '5.4.4', '<'))
839 )
840 ) {
841 $value = (-2147483648 - ($value % -2147483648)) * ($value / abs($value));
842 }
843 }
844
845 return (int) $value;
846 }
847
848 /**
849 * Check if the rounding mode is invalid.
850 *
851 * @param int $value The rounding mode value to check
852 *
853 * @return Boolean true if the rounding mode is invalid, false otherwise
854 */
855 private function isInvalidRoundingMode($value)
856 {
857 if (in_array($value, self::$roundingModes, true)) {
858 return false;
859 }
860
861 return true;
862 }
863
864 /**
865 * Returns the normalized value for the GROUPING_USED attribute. Any value that can be converted to int will be
866 * cast to Boolean and then to int again. This way, negative values are converted to 1 and string values to 0.
867 *
868 * @param mixed $value The value to be normalized
869 *
870 * @return int The normalized value for the attribute (0 or 1)
871 */
872 private function normalizeGroupingUsedValue($value)
873 {
874 return (int) (Boolean) (int) $value;
875 }
876
877 /**
878 * Returns the normalized value for the FRACTION_DIGITS attribute. The value is converted to int and if negative,
879 * the returned value will be 0.
880 *
881 * @param mixed $value The value to be normalized
882 *
883 * @return int The normalized value for the attribute
884 */
885 private function normalizeFractionDigitsValue($value)
886 {
887 $value = (int) $value;
888
889 return (0 > $value) ? 0 : $value;
890 }
891}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/README.md b/vendor/symfony/intl/Symfony/Component/Intl/README.md
new file mode 100644
index 00000000..ef4ba505
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/README.md
@@ -0,0 +1,25 @@
1Intl Component
2=============
3
4A PHP replacement layer for the C intl extension that includes additional data
5from the ICU library.
6
7The replacement layer is limited to the locale "en". If you want to use other
8locales, you should [install the intl extension] [1] instead.
9
10Documentation
11-------------
12
13The documentation for the component can be found [online] [2].
14
15Resources
16---------
17
18You can run the unit tests with the following command:
19
20 $ cd path/to/Symfony/Component/Intl/
21 $ composer.phar install --dev
22 $ phpunit
23
24[0]: http://www.php.net/manual/en/intl.setup.php
25[1]: http://symfony.com/doc/2.3/components/intl.html
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/AbstractBundle.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/AbstractBundle.php
new file mode 100644
index 00000000..d1d523c4
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/AbstractBundle.php
@@ -0,0 +1,71 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14use Symfony\Component\Intl\Intl;
15use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
16
17/**
18 * Base class for {@link ResourceBundleInterface} implementations.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22abstract class AbstractBundle implements ResourceBundleInterface
23{
24 /**
25 * @var string
26 */
27 private $path;
28
29 /**
30 * @var StructuredBundleReaderInterface
31 */
32 private $reader;
33
34 /**
35 * Creates a bundle at the given path using the given reader for reading
36 * bundle entries.
37 *
38 * @param string $path The path to the bundle.
39 * @param StructuredBundleReaderInterface $reader The reader for reading
40 * the bundle.
41 */
42 public function __construct($path, StructuredBundleReaderInterface $reader)
43 {
44 $this->path = $path;
45 $this->reader = $reader;
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 public function getLocales()
52 {
53 return $this->reader->getLocales($this->path);
54 }
55
56 /**
57 * Proxy method for {@link StructuredBundleReaderInterface#read}.
58 */
59 protected function read($locale)
60 {
61 return $this->reader->read($this->path, $locale);
62 }
63
64 /**
65 * Proxy method for {@link StructuredBundleReaderInterface#readEntry}.
66 */
67 protected function readEntry($locale, array $indices, $mergeFallback = false)
68 {
69 return $this->reader->readEntry($this->path, $locale, $indices, $mergeFallback);
70 }
71}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Compiler/BundleCompiler.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Compiler/BundleCompiler.php
new file mode 100644
index 00000000..174aa179
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Compiler/BundleCompiler.php
@@ -0,0 +1,71 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Compiler;
13
14use Symfony\Component\Intl\Exception\RuntimeException;
15
16/**
17 * Compiles .txt resource bundles to binary .res files.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class BundleCompiler implements BundleCompilerInterface
22{
23 /**
24 * @var string The path to the "genrb" executable.
25 */
26 private $genrb;
27
28 /**
29 * Creates a new compiler based on the "genrb" executable.
30 *
31 * @param string $genrb Optional. The path to the "genrb" executable.
32 * @param string $envVars Optional. Environment variables to be loaded when
33 * running "genrb".
34 *
35 * @throws RuntimeException If the "genrb" cannot be found.
36 */
37 public function __construct($genrb = 'genrb', $envVars = '')
38 {
39 exec('which ' . $genrb, $output, $status);
40
41 if (0 !== $status) {
42 throw new RuntimeException(sprintf(
43 'The command "%s" is not installed',
44 $genrb
45 ));
46 }
47
48 $this->genrb = ($envVars ? $envVars . ' ' : '') . $genrb;
49 }
50
51 /**
52 * {@inheritdoc}
53 */
54 public function compile($sourcePath, $targetDir)
55 {
56 if (is_dir($sourcePath)) {
57 $sourcePath .= '/*.txt';
58 }
59
60 exec($this->genrb.' --quiet -e UTF-8 -d '.$targetDir.' '.$sourcePath, $output, $status);
61
62 if ($status !== 0) {
63 throw new RuntimeException(sprintf(
64 'genrb failed with status %d while compiling %s to %s.',
65 $status,
66 $sourcePath,
67 $targetDir
68 ));
69 }
70 }
71}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Compiler/BundleCompilerInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Compiler/BundleCompilerInterface.php
new file mode 100644
index 00000000..6184ea3e
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Compiler/BundleCompilerInterface.php
@@ -0,0 +1,29 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Compiler;
13
14/**
15 * Compiles a resource bundle.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface BundleCompilerInterface
20{
21 /**
22 * Compiles a resource bundle at the given source to the given target
23 * directory.
24 *
25 * @param string $sourcePath
26 * @param string $targetDir
27 */
28 public function compile($sourcePath, $targetDir);
29}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php
new file mode 100644
index 00000000..6f2a0ed3
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php
@@ -0,0 +1,94 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14/**
15 * Default implementation of {@link CurrencyBundleInterface}.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class CurrencyBundle extends AbstractBundle implements CurrencyBundleInterface
20{
21 const INDEX_NAME = 0;
22
23 const INDEX_SYMBOL = 1;
24
25 const INDEX_FRACTION_DIGITS = 2;
26
27 const INDEX_ROUNDING_INCREMENT = 3;
28
29 /**
30 * {@inheritdoc}
31 */
32 public function getCurrencySymbol($currency, $locale = null)
33 {
34 if (null === $locale) {
35 $locale = \Locale::getDefault();
36 }
37
38 return $this->readEntry($locale, array('Currencies', $currency, static::INDEX_SYMBOL));
39 }
40
41 /**
42 * {@inheritdoc}
43 */
44 public function getCurrencyName($currency, $locale = null)
45 {
46 if (null === $locale) {
47 $locale = \Locale::getDefault();
48 }
49
50 return $this->readEntry($locale, array('Currencies', $currency, static::INDEX_NAME));
51 }
52
53 /**
54 * {@inheritdoc}
55 */
56 public function getCurrencyNames($locale = null)
57 {
58 if (null === $locale) {
59 $locale = \Locale::getDefault();
60 }
61
62 if (null === ($currencies = $this->readEntry($locale, array('Currencies')))) {
63 return array();
64 }
65
66 if ($currencies instanceof \Traversable) {
67 $currencies = iterator_to_array($currencies);
68 }
69
70 $index = static::INDEX_NAME;
71
72 array_walk($currencies, function (&$value) use ($index) {
73 $value = $value[$index];
74 });
75
76 return $currencies;
77 }
78
79 /**
80 * {@inheritdoc}
81 */
82 public function getFractionDigits($currency)
83 {
84 return $this->readEntry('en', array('Currencies', $currency, static::INDEX_FRACTION_DIGITS));
85 }
86
87 /**
88 * {@inheritdoc}
89 */
90 public function getRoundingIncrement($currency)
91 {
92 return $this->readEntry('en', array('Currencies', $currency, static::INDEX_ROUNDING_INCREMENT));
93 }
94}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php
new file mode 100644
index 00000000..1a88e937
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php
@@ -0,0 +1,74 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14/**
15 * Gives access to currency-related ICU data.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface CurrencyBundleInterface extends ResourceBundleInterface
20{
21 /**
22 * Returns the symbol used for a currency.
23 *
24 * @param string $currency A currency code (e.g. "EUR").
25 * @param string $locale Optional. The locale to return the result in.
26 * Defaults to {@link \Locale::getDefault()}.
27 *
28 * @return string|null The currency symbol or NULL if not found.
29 */
30 public function getCurrencySymbol($currency, $locale = null);
31
32 /**
33 * Returns the name of a currency.
34 *
35 * @param string $currency A currency code (e.g. "EUR").
36 * @param string $locale Optional. The locale to return the name in.
37 * Defaults to {@link \Locale::getDefault()}.
38 *
39 * @return string|null The name of the currency or NULL if not found.
40 */
41 public function getCurrencyName($currency, $locale = null);
42
43 /**
44 * Returns the names of all known currencies.
45 *
46 * @param string $locale Optional. The locale to return the names in.
47 * Defaults to {@link \Locale::getDefault()}.
48 *
49 * @return string[] A list of currency names indexed by currency codes.
50 */
51 public function getCurrencyNames($locale = null);
52
53 /**
54 * Returns the number of digits after the comma of a currency.
55 *
56 * @param string $currency A currency code (e.g. "EUR").
57 *
58 * @return integer|null The number of digits after the comma or NULL if not found.
59 */
60 public function getFractionDigits($currency);
61
62 /**
63 * Returns the rounding increment of a currency.
64 *
65 * The rounding increment indicates to which number a currency is rounded.
66 * For example, 1230 rounded to the nearest 50 is 1250. 1.234 rounded to the
67 * nearest 0.65 is 1.3.
68 *
69 * @param string $currency A currency code (e.g. "EUR").
70 *
71 * @return float|integer|null The rounding increment or NULL if not found.
72 */
73 public function getRoundingIncrement($currency);
74}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php
new file mode 100644
index 00000000..c449f9c1
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php
@@ -0,0 +1,115 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14/**
15 * Default implementation of {@link LanguageBundleInterface}.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class LanguageBundle extends AbstractBundle implements LanguageBundleInterface
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function getLanguageName($lang, $region = null, $locale = null)
25 {
26 if (null === $locale) {
27 $locale = \Locale::getDefault();
28 }
29
30 if (null === ($languages = $this->readEntry($locale, array('Languages')))) {
31 return null;
32 }
33
34 // Some languages are translated together with their region,
35 // i.e. "en_GB" is translated as "British English"
36 if (null !== $region && isset($languages[$lang.'_'.$region])) {
37 return $languages[$lang.'_'.$region];
38 }
39
40 return $languages[$lang];
41 }
42
43 /**
44 * {@inheritdoc}
45 */
46 public function getLanguageNames($locale = null)
47 {
48 if (null === $locale) {
49 $locale = \Locale::getDefault();
50 }
51
52 if (null === ($languages = $this->readEntry($locale, array('Languages')))) {
53 return array();
54 }
55
56 if ($languages instanceof \Traversable) {
57 $languages = iterator_to_array($languages);
58 }
59
60 return $languages;
61 }
62
63 /**
64 * {@inheritdoc}
65 */
66 public function getScriptName($script, $lang = null, $locale = null)
67 {
68 if (null === $locale) {
69 $locale = \Locale::getDefault();
70 }
71
72 $data = $this->read($locale);
73
74 // Some languages are translated together with their script,
75 // e.g. "zh_Hans" is translated as "Simplified Chinese"
76 if (null !== $lang && isset($data['Languages'][$lang.'_'.$script])) {
77 $langName = $data['Languages'][$lang.'_'.$script];
78
79 // If the script is appended in braces, extract it, e.g. "zh_Hans"
80 // is translated as "Chinesisch (vereinfacht)" in locale "de"
81 if (strpos($langName, '(') !== false) {
82 list($langName, $scriptName) = preg_split('/[\s()]/', $langName, null, PREG_SPLIT_NO_EMPTY);
83
84 return $scriptName;
85 }
86 }
87
88 // "af" (Afrikaans) has no "Scripts" block
89 if (!isset($data['Scripts'][$script])) {
90 return null;
91 }
92
93 return $data['Scripts'][$script];
94 }
95
96 /**
97 * {@inheritdoc}
98 */
99 public function getScriptNames($locale = null)
100 {
101 if (null === $locale) {
102 $locale = \Locale::getDefault();
103 }
104
105 if (null === ($scripts = $this->readEntry($locale, array('Scripts')))) {
106 return array();
107 }
108
109 if ($scripts instanceof \Traversable) {
110 $scripts = iterator_to_array($scripts);
111 }
112
113 return $scripts;
114 }
115}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php
new file mode 100644
index 00000000..de50bda0
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14/**
15 * Gives access to language-related ICU data.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface LanguageBundleInterface extends ResourceBundleInterface
20{
21 /**
22 * Returns the name of a language.
23 *
24 * @param string $lang A language code (e.g. "en").
25 * @param string|null $region Optional. A region code (e.g. "US").
26 * @param string $locale Optional. The locale to return the name in.
27 * Defaults to {@link \Locale::getDefault()}.
28 *
29 * @return string|null The name of the language or NULL if not found.
30 */
31 public function getLanguageName($lang, $region = null, $locale = null);
32
33 /**
34 * Returns the names of all known languages.
35 *
36 * @param string $locale Optional. The locale to return the names in.
37 * Defaults to {@link \Locale::getDefault()}.
38 *
39 * @return string[] A list of language names indexed by language codes.
40 */
41 public function getLanguageNames($locale = null);
42
43 /**
44 * Returns the name of a script.
45 *
46 * @param string $script A script code (e.g. "Hans").
47 * @param string $lang Optional. A language code (e.g. "zh").
48 * @param string $locale Optional. The locale to return the name in.
49 * Defaults to {@link \Locale::getDefault()}.
50 *
51 * @return string|null The name of the script or NULL if not found.
52 */
53 public function getScriptName($script, $lang = null, $locale = null);
54
55 /**
56 * Returns the names of all known scripts.
57 *
58 * @param string $locale Optional. The locale to return the names in.
59 * Defaults to {@link \Locale::getDefault()}.
60 *
61 * @return string[] A list of script names indexed by script codes.
62 */
63 public function getScriptNames($locale = null);
64}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php
new file mode 100644
index 00000000..6f6cdfcb
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php
@@ -0,0 +1,52 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14/**
15 * Default implementation of {@link LocaleBundleInterface}.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class LocaleBundle extends AbstractBundle implements LocaleBundleInterface
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function getLocaleName($ofLocale, $locale = null)
25 {
26 if (null === $locale) {
27 $locale = \Locale::getDefault();
28 }
29
30 return $this->readEntry($locale, array('Locales', $ofLocale));
31 }
32
33 /**
34 * {@inheritdoc}
35 */
36 public function getLocaleNames($locale = null)
37 {
38 if (null === $locale) {
39 $locale = \Locale::getDefault();
40 }
41
42 if (null === ($locales = $this->readEntry($locale, array('Locales')))) {
43 return array();
44 }
45
46 if ($locales instanceof \Traversable) {
47 $locales = iterator_to_array($locales);
48 }
49
50 return $locales;
51 }
52}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php
new file mode 100644
index 00000000..daf5be68
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14/**
15 * Gives access to locale-related ICU data.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface LocaleBundleInterface extends ResourceBundleInterface
20{
21 /**
22 * Returns the name of a locale.
23 *
24 * @param string $ofLocale The locale to return the name of (e.g. "de_AT").
25 * @param string $locale Optional. The locale to return the name in.
26 * Defaults to {@link \Locale::getDefault()}.
27 *
28 * @return string|null The name of the locale or NULL if not found.
29 */
30 public function getLocaleName($ofLocale, $locale = null);
31
32 /**
33 * Returns the names of all known locales.
34 *
35 * @param string $locale Optional. The locale to return the names in.
36 * Defaults to {@link \Locale::getDefault()}.
37 *
38 * @return string[] A list of locale names indexed by locale codes.
39 */
40 public function getLocaleNames($locale = null);
41}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/AbstractBundleReader.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/AbstractBundleReader.php
new file mode 100644
index 00000000..c30693ac
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/AbstractBundleReader.php
@@ -0,0 +1,42 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Reader;
13
14/**
15 * Base class for {@link BundleReaderInterface} implementations.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19abstract class AbstractBundleReader implements BundleReaderInterface
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function getLocales($path)
25 {
26 $extension = '.' . $this->getFileExtension();
27 $locales = glob($path . '/*' . $extension);
28
29 // Remove file extension and sort
30 array_walk($locales, function (&$locale) use ($extension) { $locale = basename($locale, $extension); });
31 sort($locales);
32
33 return $locales;
34 }
35
36 /**
37 * Returns the extension of locale files in this bundle.
38 *
39 * @return string The file extension (without leading dot).
40 */
41 abstract protected function getFileExtension();
42}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BinaryBundleReader.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BinaryBundleReader.php
new file mode 100644
index 00000000..56cef806
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BinaryBundleReader.php
@@ -0,0 +1,51 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Reader;
13
14use Symfony\Component\Intl\Exception\RuntimeException;
15use Symfony\Component\Intl\ResourceBundle\Util\ArrayAccessibleResourceBundle;
16
17/**
18 * Reads binary .res resource bundles.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class BinaryBundleReader extends AbstractBundleReader implements BundleReaderInterface
23{
24 /**
25 * {@inheritdoc}
26 */
27 public function read($path, $locale)
28 {
29 // Point for future extension: Modify this class so that it works also
30 // if the \ResourceBundle class is not available.
31 $bundle = new \ResourceBundle($locale, $path);
32
33 if (null === $bundle) {
34 throw new RuntimeException(sprintf(
35 'Could not load the resource bundle "%s/%s.res".',
36 $path,
37 $locale
38 ));
39 }
40
41 return new ArrayAccessibleResourceBundle($bundle);
42 }
43
44 /**
45 * {@inheritdoc}
46 */
47 protected function getFileExtension()
48 {
49 return 'res';
50 }
51}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BufferedBundleReader.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BufferedBundleReader.php
new file mode 100644
index 00000000..e44074b1
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BufferedBundleReader.php
@@ -0,0 +1,62 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Reader;
13
14use Symfony\Component\Intl\ResourceBundle\Util\RingBuffer;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class BufferedBundleReader implements BundleReaderInterface
20{
21 /**
22 * @var BundleReaderInterface
23 */
24 private $reader;
25
26 private $buffer;
27
28 /**
29 * Buffers a given reader.
30 *
31 * @param BundleReaderInterface $reader The reader to buffer.
32 * @param integer $bufferSize The number of entries to store
33 * in the buffer.
34 */
35 public function __construct(BundleReaderInterface $reader, $bufferSize)
36 {
37 $this->reader = $reader;
38 $this->buffer = new RingBuffer($bufferSize);
39 }
40
41 /**
42 * {@inheritdoc}
43 */
44 public function read($path, $locale)
45 {
46 $hash = $path . '//' . $locale;
47
48 if (!isset($this->buffer[$hash])) {
49 $this->buffer[$hash] = $this->reader->read($path, $locale);
50 }
51
52 return $this->buffer[$hash];
53 }
54
55 /**
56 * {@inheritdoc}
57 */
58 public function getLocales($path)
59 {
60 return $this->reader->getLocales($path);
61 }
62}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BundleReaderInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BundleReaderInterface.php
new file mode 100644
index 00000000..bc485cd5
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/BundleReaderInterface.php
@@ -0,0 +1,40 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Reader;
13
14/**
15 * Reads resource bundle files.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface BundleReaderInterface
20{
21 /**
22 * Reads a resource bundle.
23 *
24 * @param string $path The path to the resource bundle.
25 * @param string $locale The locale to read.
26 *
27 * @return mixed Returns an array or {@link \ArrayAccess} instance for
28 * complex data, a scalar value otherwise.
29 */
30 public function read($path, $locale);
31
32 /**
33 * Reads the available locales of a resource bundle.
34 *
35 * @param string $path The path to the resource bundle.
36 *
37 * @return string[] A list of supported locale codes.
38 */
39 public function getLocales($path);
40}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/PhpBundleReader.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/PhpBundleReader.php
new file mode 100644
index 00000000..663bcc9d
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/PhpBundleReader.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Reader;
13
14use Symfony\Component\Intl\Exception\InvalidArgumentException;
15use Symfony\Component\Intl\Exception\RuntimeException;
16
17/**
18 * Reads .php resource bundles.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class PhpBundleReader extends AbstractBundleReader implements BundleReaderInterface
23{
24 /**
25 * {@inheritdoc}
26 */
27 public function read($path, $locale)
28 {
29 if ('en' !== $locale) {
30 throw new InvalidArgumentException('Only the locale "en" is supported.');
31 }
32
33 $fileName = $path . '/' . $locale . '.php';
34
35 if (!file_exists($fileName)) {
36 throw new RuntimeException(sprintf(
37 'The resource bundle "%s/%s.php" does not exist.',
38 $path,
39 $locale
40 ));
41 }
42
43 if (!is_file($fileName)) {
44 throw new RuntimeException(sprintf(
45 'The resource bundle "%s/%s.php" is not a file.',
46 $path,
47 $locale
48 ));
49 }
50
51 return include $fileName;
52 }
53
54 /**
55 * {@inheritdoc}
56 */
57 protected function getFileExtension()
58 {
59 return 'php';
60 }
61}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/StructuredBundleReader.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/StructuredBundleReader.php
new file mode 100644
index 00000000..e3656fe2
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/StructuredBundleReader.php
@@ -0,0 +1,113 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Reader;
13
14use Symfony\Component\Intl\ResourceBundle\Util\RecursiveArrayAccess;
15
16/**
17 * A structured reader wrapping an existing resource bundle reader.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 *
21 * @see StructuredResourceBundleBundleReaderInterface
22 */
23class StructuredBundleReader implements StructuredBundleReaderInterface
24{
25 /**
26 * @var BundleReaderInterface
27 */
28 private $reader;
29
30 /**
31 * Creates an entry reader based on the given resource bundle reader.
32 *
33 * @param BundleReaderInterface $reader A resource bundle reader to use.
34 */
35 public function __construct(BundleReaderInterface $reader)
36 {
37 $this->reader = $reader;
38 }
39
40 /**
41 * {@inheritdoc}
42 */
43 public function read($path, $locale)
44 {
45 return $this->reader->read($path, $locale);
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 public function getLocales($path)
52 {
53 return $this->reader->getLocales($path);
54 }
55
56 /**
57 * {@inheritdoc}
58 */
59 public function readEntry($path, $locale, array $indices, $fallback = true)
60 {
61 $data = $this->reader->read($path, $locale);
62
63 $entry = RecursiveArrayAccess::get($data, $indices);
64 $multivalued = is_array($entry) || $entry instanceof \Traversable;
65
66 if (!($fallback && (null === $entry || $multivalued))) {
67 return $entry;
68 }
69
70 if (null !== ($fallbackLocale = $this->getFallbackLocale($locale))) {
71 $parentEntry = $this->readEntry($path, $fallbackLocale, $indices, true);
72
73 if ($entry || $parentEntry) {
74 $multivalued = $multivalued || is_array($parentEntry) || $parentEntry instanceof \Traversable;
75
76 if ($multivalued) {
77 if ($entry instanceof \Traversable) {
78 $entry = iterator_to_array($entry);
79 }
80
81 if ($parentEntry instanceof \Traversable) {
82 $parentEntry = iterator_to_array($parentEntry);
83 }
84
85 $entry = array_merge(
86 $parentEntry ?: array(),
87 $entry ?: array()
88 );
89 } else {
90 $entry = null === $entry ? $parentEntry : $entry;
91 }
92 }
93 }
94
95 return $entry;
96 }
97
98 /**
99 * Returns the fallback locale for a given locale, if any
100 *
101 * @param string $locale The locale to find the fallback for.
102 *
103 * @return string|null The fallback locale, or null if no parent exists
104 */
105 private function getFallbackLocale($locale)
106 {
107 if (false === $pos = strrpos($locale, '_')) {
108 return null;
109 }
110
111 return substr($locale, 0, $pos);
112 }
113}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/StructuredBundleReaderInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/StructuredBundleReaderInterface.php
new file mode 100644
index 00000000..c22ad93b
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Reader/StructuredBundleReaderInterface.php
@@ -0,0 +1,50 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Reader;
13
14/**
15 * Reads individual entries of a resource file.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface StructuredBundleReaderInterface extends BundleReaderInterface
20{
21 /**
22 * Reads an entry from a resource bundle.
23 *
24 * An entry can be selected from the resource bundle by passing the path
25 * to that entry in the bundle. For example, if the bundle is structured
26 * like this:
27 *
28 * TopLevel
29 * NestedLevel
30 * Entry: Value
31 *
32 * Then the value can be read by calling:
33 *
34 * $reader->readEntry('...', 'en', array('TopLevel', 'NestedLevel', 'Entry'));
35 *
36 * @param string $path The path to the resource bundle.
37 * @param string $locale The locale to read.
38 * @param string[] $indices The indices to read from the bundle.
39 * @param Boolean $fallback Whether to merge the value with the value from
40 * the fallback locale (e.g. "en" for "en_GB").
41 * Only applicable if the result is multivalued
42 * (i.e. array or \ArrayAccess) or cannot be found
43 * in the requested locale.
44 *
45 * @return mixed Returns an array or {@link \ArrayAccess} instance for
46 * complex data, a scalar value for simple data and NULL
47 * if the given path could not be accessed.
48 */
49 public function readEntry($path, $locale, array $indices, $fallback = true);
50}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/RegionBundle.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/RegionBundle.php
new file mode 100644
index 00000000..a3cd9bd3
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/RegionBundle.php
@@ -0,0 +1,52 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14/**
15 * Default implementation of {@link RegionBundleInterface}.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class RegionBundle extends AbstractBundle implements RegionBundleInterface
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function getCountryName($country, $locale = null)
25 {
26 if (null === $locale) {
27 $locale = \Locale::getDefault();
28 }
29
30 return $this->readEntry($locale, array('Countries', $country));
31 }
32
33 /**
34 * {@inheritdoc}
35 */
36 public function getCountryNames($locale = null)
37 {
38 if (null === $locale) {
39 $locale = \Locale::getDefault();
40 }
41
42 if (null === ($countries = $this->readEntry($locale, array('Countries')))) {
43 return array();
44 }
45
46 if ($countries instanceof \Traversable) {
47 $countries = iterator_to_array($countries);
48 }
49
50 return $countries;
51 }
52}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php
new file mode 100644
index 00000000..4e55f2dc
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14/**
15 * Gives access to region-related ICU data.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface RegionBundleInterface extends ResourceBundleInterface
20{
21 /**
22 * Returns the name of a country.
23 *
24 * @param string $country A country code (e.g. "US").
25 * @param string $locale Optional. The locale to return the name in.
26 * Defaults to {@link \Locale::getDefault()}.
27 *
28 * @return string|null The name of the country or NULL if not found.
29 */
30 public function getCountryName($country, $locale = null);
31
32 /**
33 * Returns the names of all known countries.
34 *
35 * @param string $locale Optional. The locale to return the names in.
36 * Defaults to {@link \Locale::getDefault()}.
37 *
38 * @return string[] A list of country names indexed by country codes.
39 */
40 public function getCountryNames($locale = null);
41}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php
new file mode 100644
index 00000000..497a66a3
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php
@@ -0,0 +1,27 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle;
13
14/**
15 * Gives access to ICU data.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface ResourceBundleInterface
20{
21 /**
22 * Returns the list of locales that this bundle supports.
23 *
24 * @return string[] A list of locale codes.
25 */
26 public function getLocales();
27}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/BundleTransformer.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/BundleTransformer.php
new file mode 100644
index 00000000..0692d6fe
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/BundleTransformer.php
@@ -0,0 +1,96 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer;
13
14use Symfony\Component\Intl\Exception\RuntimeException;
15use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\TransformationRuleInterface;
16use Symfony\Component\Intl\ResourceBundle\Writer\PhpBundleWriter;
17
18/**
19 * Compiles a number of resource bundles based on predefined compilation rules.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class BundleTransformer
24{
25 /**
26 * @var TransformationRuleInterface[]
27 */
28 private $rules = array();
29
30 /**
31 * Adds a new compilation rule.
32 *
33 * @param TransformationRuleInterface $rule The compilation rule.
34 */
35 public function addRule(TransformationRuleInterface $rule)
36 {
37 $this->rules[] = $rule;
38 }
39
40 /**
41 * Runs the compilation with the given compilation context.
42 *
43 * @param CompilationContextInterface $context The context storing information
44 * needed to run the compilation.
45 *
46 * @throws RuntimeException If any of the files to be compiled by the loaded
47 * compilation rules does not exist.
48 */
49 public function compileBundles(CompilationContextInterface $context)
50 {
51 $filesystem = $context->getFilesystem();
52 $compiler = $context->getCompiler();
53
54 $filesystem->remove($context->getBinaryDir());
55 $filesystem->mkdir($context->getBinaryDir());
56
57 foreach ($this->rules as $rule) {
58 $filesystem->mkdir($context->getBinaryDir() . '/' . $rule->getBundleName());
59
60 $resources = (array) $rule->beforeCompile($context);
61
62 foreach ($resources as $resource) {
63 if (!file_exists($resource)) {
64 throw new RuntimeException(sprintf(
65 'The file "%s" to be compiled by %s does not exist.',
66 $resource,
67 get_class($rule)
68 ));
69 }
70
71 $compiler->compile($resource, $context->getBinaryDir() . '/' . $rule->getBundleName());
72 }
73
74 $rule->afterCompile($context);
75 }
76 }
77
78 public function createStubs(StubbingContextInterface $context)
79 {
80 $filesystem = $context->getFilesystem();
81 $phpWriter = new PhpBundleWriter();
82
83 $filesystem->remove($context->getStubDir());
84 $filesystem->mkdir($context->getStubDir());
85
86 foreach ($this->rules as $rule) {
87 $filesystem->mkdir($context->getStubDir() . '/' . $rule->getBundleName());
88
89 $data = $rule->beforeCreateStub($context);
90
91 $phpWriter->write($context->getStubDir() . '/' . $rule->getBundleName(), 'en', $data);
92
93 $rule->afterCreateStub($context);
94 }
95 }
96}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/CompilationContext.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/CompilationContext.php
new file mode 100644
index 00000000..cdc1951b
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/CompilationContext.php
@@ -0,0 +1,97 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer;
13
14use Symfony\Component\Filesystem\Filesystem;
15use Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompilerInterface;
16
17/**
18 * Default implementation of {@link CompilationContextInterface}.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class CompilationContext implements CompilationContextInterface
23{
24 /**
25 * @var string
26 */
27 private $sourceDir;
28
29 /**
30 * @var string
31 */
32 private $binaryDir;
33
34 /**
35 * @var FileSystem
36 */
37 private $filesystem;
38
39 /**
40 * @var BundleCompilerInterface
41 */
42 private $compiler;
43
44 /**
45 * @var string
46 */
47 private $icuVersion;
48
49 public function __construct($sourceDir, $binaryDir, Filesystem $filesystem, BundleCompilerInterface $compiler, $icuVersion)
50 {
51 $this->sourceDir = $sourceDir;
52 $this->binaryDir = $binaryDir;
53 $this->filesystem = $filesystem;
54 $this->compiler = $compiler;
55 $this->icuVersion = $icuVersion;
56 }
57
58 /**
59 * {@inheritdoc}
60 */
61 public function getSourceDir()
62 {
63 return $this->sourceDir;
64 }
65
66 /**
67 * {@inheritdoc}
68 */
69 public function getBinaryDir()
70 {
71 return $this->binaryDir;
72 }
73
74 /**
75 * {@inheritdoc}
76 */
77 public function getFilesystem()
78 {
79 return $this->filesystem;
80 }
81
82 /**
83 * {@inheritdoc}
84 */
85 public function getCompiler()
86 {
87 return $this->compiler;
88 }
89
90 /**
91 * {@inheritdoc}
92 */
93 public function getIcuVersion()
94 {
95 return $this->icuVersion;
96 }
97}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/CompilationContextInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/CompilationContextInterface.php
new file mode 100644
index 00000000..f05c2807
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/CompilationContextInterface.php
@@ -0,0 +1,56 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer;
13
14/**
15 * Stores contextual information for resource bundle compilation.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface CompilationContextInterface
20{
21 /**
22 * Returns the directory where the source versions of the resource bundles
23 * are stored.
24 *
25 * @return string An absolute path to a directory.
26 */
27 public function getSourceDir();
28
29 /**
30 * Returns the directory where the binary resource bundles are stored.
31 *
32 * @return string An absolute path to a directory.
33 */
34 public function getBinaryDir();
35
36 /**
37 * Returns a tool for manipulating the filesystem.
38 *
39 * @return \Symfony\Component\Filesystem\Filesystem The filesystem manipulator.
40 */
41 public function getFilesystem();
42
43 /**
44 * Returns a resource bundle compiler.
45 *
46 * @return \Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompilerInterface The loaded resource bundle compiler.
47 */
48 public function getCompiler();
49
50 /**
51 * Returns the ICU version of the bundles being converted.
52 *
53 * @return string The ICU version string.
54 */
55 public function getIcuVersion();
56}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/CurrencyBundleTransformationRule.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/CurrencyBundleTransformationRule.php
new file mode 100644
index 00000000..95783b3b
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/CurrencyBundleTransformationRule.php
@@ -0,0 +1,94 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
13
14use Symfony\Component\Intl\Intl;
15use Symfony\Component\Intl\ResourceBundle\CurrencyBundle;
16use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
17use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
18use Symfony\Component\Intl\Util\IcuVersion;
19
20/**
21 * The rule for compiling the currency bundle.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class CurrencyBundleTransformationRule implements TransformationRuleInterface
26{
27 /**
28 * {@inheritdoc}
29 */
30 public function getBundleName()
31 {
32 return 'curr';
33 }
34
35 /**
36 * {@inheritdoc}
37 */
38 public function beforeCompile(CompilationContextInterface $context)
39 {
40 // The currency data is contained in the locales and misc bundles
41 // in ICU <= 4.2
42 if (IcuVersion::compare($context->getIcuVersion(), '4.2', '<=', 1)) {
43 return array(
44 $context->getSourceDir() . '/misc/supplementalData.txt',
45 $context->getSourceDir() . '/locales'
46 );
47 }
48
49 return $context->getSourceDir() . '/curr';
50 }
51
52 /**
53 * {@inheritdoc}
54 */
55 public function afterCompile(CompilationContextInterface $context)
56 {
57 // \ResourceBundle does not like locale names with uppercase chars, so rename
58 // the resource file
59 // See: http://bugs.php.net/bug.php?id=54025
60 $fileName = $context->getBinaryDir() . '/curr/supplementalData.res';
61 $fileNameLower = $context->getBinaryDir() . '/curr/supplementaldata.res';
62
63 $context->getFilesystem()->rename($fileName, $fileNameLower);
64 }
65
66 /**
67 * {@inheritdoc}
68 */
69 public function beforeCreateStub(StubbingContextInterface $context)
70 {
71 $currencies = array();
72 $currencyBundle = Intl::getCurrencyBundle();
73
74 foreach ($currencyBundle->getCurrencyNames('en') as $code => $name) {
75 $currencies[$code] = array(
76 CurrencyBundle::INDEX_NAME => $name,
77 CurrencyBundle::INDEX_SYMBOL => $currencyBundle->getCurrencySymbol($code, 'en'),
78 CurrencyBundle::INDEX_FRACTION_DIGITS => $currencyBundle->getFractionDigits($code),
79 CurrencyBundle::INDEX_ROUNDING_INCREMENT => $currencyBundle->getRoundingIncrement($code),
80 );
81 }
82
83 return array(
84 'Currencies' => $currencies,
85 );
86 }
87
88 /**
89 * {@inheritdoc}
90 */
91 public function afterCreateStub(StubbingContextInterface $context)
92 {
93 }
94}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/LanguageBundleTransformationRule.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/LanguageBundleTransformationRule.php
new file mode 100644
index 00000000..5e6f9018
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/LanguageBundleTransformationRule.php
@@ -0,0 +1,71 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
13
14use Symfony\Component\Intl\Intl;
15use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
16use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
17use Symfony\Component\Intl\Util\IcuVersion;
18
19/**
20 * The rule for compiling the language bundle.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class LanguageBundleTransformationRule implements TransformationRuleInterface
25{
26 /**
27 * {@inheritdoc}
28 */
29 public function getBundleName()
30 {
31 return 'lang';
32 }
33
34 /**
35 * {@inheritdoc}
36 */
37 public function beforeCompile(CompilationContextInterface $context)
38 {
39 // The language data is contained in the locales bundle in ICU <= 4.2
40 if (IcuVersion::compare($context->getIcuVersion(), '4.2', '<=', 1)) {
41 return $context->getSourceDir() . '/locales';
42 }
43
44 return $context->getSourceDir() . '/lang';
45 }
46
47 /**
48 * {@inheritdoc}
49 */
50 public function afterCompile(CompilationContextInterface $context)
51 {
52 }
53
54 /**
55 * {@inheritdoc}
56 */
57 public function beforeCreateStub(StubbingContextInterface $context)
58 {
59 return array(
60 'Languages' => Intl::getLanguageBundle()->getLanguageNames('en'),
61 'Scripts' => Intl::getLanguageBundle()->getScriptNames('en'),
62 );
63 }
64
65 /**
66 * {@inheritdoc}
67 */
68 public function afterCreateStub(StubbingContextInterface $context)
69 {
70 }
71}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/LocaleBundleTransformationRule.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/LocaleBundleTransformationRule.php
new file mode 100644
index 00000000..b2576d6e
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/LocaleBundleTransformationRule.php
@@ -0,0 +1,251 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
13
14use Symfony\Component\Intl\Exception\RuntimeException;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
17use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
18use Symfony\Component\Intl\ResourceBundle\Writer\TextBundleWriter;
19
20/**
21 * The rule for compiling the locale bundle.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class LocaleBundleTransformationRule implements TransformationRuleInterface
26{
27 /**
28 * @var \Symfony\Component\Intl\ResourceBundle\LanguageBundleInterface
29 */
30 private $languageBundle;
31
32 /**
33 * @var \Symfony\Component\Intl\ResourceBundle\RegionBundleInterface
34 */
35 private $regionBundle;
36
37 public function __construct()
38 {
39 $this->languageBundle = Intl::getLanguageBundle();
40 $this->regionBundle = Intl::getRegionBundle();
41 }
42
43 /**
44 * {@inheritdoc}
45 */
46 public function getBundleName()
47 {
48 return 'locales';
49 }
50
51 /**
52 * {@inheritdoc}
53 */
54 public function beforeCompile(CompilationContextInterface $context)
55 {
56 $tempDir = sys_get_temp_dir() . '/icu-data-locales';
57
58 $context->getFilesystem()->remove($tempDir);
59 $context->getFilesystem()->mkdir($tempDir);
60
61 $this->generateTextFiles($tempDir, $this->scanLocales($context));
62
63 return $tempDir;
64 }
65
66 /**
67 * {@inheritdoc}
68 */
69 public function afterCompile(CompilationContextInterface $context)
70 {
71 $context->getFilesystem()->remove(sys_get_temp_dir() . '/icu-data-locales');
72 }
73
74 /**
75 * {@inheritdoc}
76 */
77 public function beforeCreateStub(StubbingContextInterface $context)
78 {
79 return array(
80 'Locales' => Intl::getLocaleBundle()->getLocaleNames('en'),
81 );
82 }
83
84 /**
85 * {@inheritdoc}
86 */
87 public function afterCreateStub(StubbingContextInterface $context)
88 {
89 }
90
91 private function scanLocales(CompilationContextInterface $context)
92 {
93 $tempDir = sys_get_temp_dir() . '/icu-data-locales-source';
94
95 $context->getFilesystem()->remove($tempDir);
96 $context->getFilesystem()->mkdir($tempDir);
97
98 // Temporarily generate the resource bundles
99 $context->getCompiler()->compile($context->getSourceDir() . '/locales', $tempDir);
100
101 // Discover the list of supported locales, which are the names of the resource
102 // bundles in the "locales" directory
103 $locales = glob($tempDir . '/*.res');
104
105 // Remove file extension and sort
106 array_walk($locales, function (&$locale) { $locale = basename($locale, '.res'); });
107 sort($locales);
108
109 // Delete unneeded locales
110 foreach ($locales as $key => $locale) {
111 // Delete all aliases from the list
112 // i.e., "az_AZ" is an alias for "az_Latn_AZ"
113 $content = file_get_contents($context->getSourceDir() . '/locales/' . $locale . '.txt');
114
115 // The key "%%ALIAS" is not accessible through the \ResourceBundle class,
116 // so look in the original .txt file instead
117 if (strpos($content, '%%ALIAS') !== false) {
118 unset($locales[$key]);
119 }
120
121 // Delete locales that have no content (i.e. only "Version" key)
122 $bundle = new \ResourceBundle($locale, $tempDir);
123
124 if (null === $bundle) {
125 throw new RuntimeException('The resource bundle for locale ' . $locale . ' could not be loaded from directory ' . $tempDir);
126 }
127
128 // There seems to be no other way for identifying all keys in this specific
129 // resource bundle
130 if (array_keys(iterator_to_array($bundle)) === array('Version')) {
131 unset($locales[$key]);
132 }
133 }
134
135 $context->getFilesystem()->remove($tempDir);
136
137 return $locales;
138 }
139
140 private function generateTextFiles($targetDirectory, array $locales)
141 {
142 $displayLocales = array_unique(array_merge(
143 $this->languageBundle->getLocales(),
144 $this->regionBundle->getLocales()
145 ));
146
147 $txtWriter = new TextBundleWriter();
148
149 // Generate a list of locale names in the language of each display locale
150 // Each locale name has the form: "Language (Script, Region, Variant1, ...)
151 // Script, Region and Variants are optional. If none of them is available,
152 // the braces are not printed.
153 foreach ($displayLocales as $displayLocale) {
154 // Don't include ICU's root resource bundle
155 if ('root' === $displayLocale) {
156 continue;
157 }
158
159 $names = array();
160
161 foreach ($locales as $locale) {
162 // Don't include ICU's root resource bundle
163 if ($locale === 'root') {
164 continue;
165 }
166
167 if (null !== ($name = $this->generateLocaleName($locale, $displayLocale))) {
168 $names[$locale] = $name;
169 }
170 }
171
172 // If no names could be generated for the current locale, skip it
173 if (0 === count($names)) {
174 continue;
175 }
176
177 $txtWriter->write($targetDirectory, $displayLocale, array('Locales' => $names));
178 }
179 }
180
181 private function generateLocaleName($locale, $displayLocale)
182 {
183 $name = null;
184
185 $lang = \Locale::getPrimaryLanguage($locale);
186 $script = \Locale::getScript($locale);
187 $region = \Locale::getRegion($locale);
188 $variants = \Locale::getAllVariants($locale);
189
190 // Currently the only available variant is POSIX, which we don't want
191 // to include in the list
192 if (count($variants) > 0) {
193 return null;
194 }
195
196 // Some languages are translated together with their region,
197 // i.e. "en_GB" is translated as "British English"
198 // we don't include these languages though because they mess up
199 // the name sorting
200 // $name = $this->langBundle->getLanguageName($displayLocale, $lang, $region);
201
202 // Some languages are simply not translated
203 // Example: "az" (Azerbaijani) has no translation in "af" (Afrikaans)
204 if (null === ($name = $this->languageBundle->getLanguageName($lang, null, $displayLocale))) {
205 return null;
206 }
207
208 // "as" (Assamese) has no "Variants" block
209 //if (!$langBundle->get('Variants')) {
210 // continue;
211 //}
212
213 $extras = array();
214
215 // Discover the name of the script part of the locale
216 // i.e. in zh_Hans_MO, "Hans" is the script
217 if ($script) {
218 // Some scripts are not translated into every language
219 if (null === ($scriptName = $this->languageBundle->getScriptName($script, $lang, $displayLocale))) {
220 return null;
221 }
222
223 $extras[] = $scriptName;
224 }
225
226 // Discover the name of the region part of the locale
227 // i.e. in de_AT, "AT" is the region
228 if ($region) {
229 // Some regions are not translated into every language
230 if (null === ($regionName = $this->regionBundle->getCountryName($region, $displayLocale))) {
231 return null;
232 }
233
234 $extras[] = $regionName;
235 }
236
237 if (count($extras) > 0) {
238 // Remove any existing extras
239 // For example, in German, zh_Hans is "Chinesisch (vereinfacht)".
240 // The latter is the script part which is already included in the
241 // extras and will be appended again with the other extras.
242 if (preg_match('/^(.+)\s+\([^\)]+\)$/', $name, $matches)) {
243 $name = $matches[1];
244 }
245
246 $name .= ' ('.implode(', ', $extras).')';
247 }
248
249 return $name;
250 }
251}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/RegionBundleTransformationRule.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/RegionBundleTransformationRule.php
new file mode 100644
index 00000000..52fdbed8
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/RegionBundleTransformationRule.php
@@ -0,0 +1,70 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
13
14use Symfony\Component\Intl\Intl;
15use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
16use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
17use Symfony\Component\Intl\Util\IcuVersion;
18
19/**
20 * The rule for compiling the region bundle.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class RegionBundleTransformationRule implements TransformationRuleInterface
25{
26 /**
27 * {@inheritdoc}
28 */
29 public function getBundleName()
30 {
31 return 'region';
32 }
33
34 /**
35 * {@inheritdoc}
36 */
37 public function beforeCompile(CompilationContextInterface $context)
38 {
39 // The region data is contained in the locales bundle in ICU <= 4.2
40 if (IcuVersion::compare($context->getIcuVersion(), '4.2', '<=', 1)) {
41 return $context->getSourceDir() . '/locales';
42 }
43
44 return $context->getSourceDir() . '/region';
45 }
46
47 /**
48 * {@inheritdoc}
49 */
50 public function afterCompile(CompilationContextInterface $context)
51 {
52 }
53
54 /**
55 * {@inheritdoc}
56 */
57 public function beforeCreateStub(StubbingContextInterface $context)
58 {
59 return array(
60 'Countries' => Intl::getRegionBundle()->getCountryNames('en'),
61 );
62 }
63
64 /**
65 * {@inheritdoc}
66 */
67 public function afterCreateStub(StubbingContextInterface $context)
68 {
69 }
70}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/TransformationRuleInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/TransformationRuleInterface.php
new file mode 100644
index 00000000..3965e0d2
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/Rule/TransformationRuleInterface.php
@@ -0,0 +1,70 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
13
14use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
15use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
16
17/**
18 * Contains instruction for compiling a resource bundle.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22interface TransformationRuleInterface
23{
24 /**
25 * Returns the name of the compiled resource bundle.
26 *
27 * @return string The name of the bundle.
28 */
29 public function getBundleName();
30
31 /**
32 * Runs instructions to be executed before compiling the sources of the
33 * resource bundle.
34 *
35 * @param CompilationContextInterface $context The contextual information of
36 * the compilation.
37 *
38 * @return string[] The source directories/files of the bundle.
39 */
40 public function beforeCompile(CompilationContextInterface $context);
41
42 /**
43 * Runs instructions to be executed after compiling the sources of the
44 * resource bundle.
45 *
46 * @param CompilationContextInterface $context The contextual information of
47 * the compilation.
48 */
49 public function afterCompile(CompilationContextInterface $context);
50
51 /**
52 * Runs instructions to be executed before creating the stub version of the
53 * resource bundle.
54 *
55 * @param StubbingContextInterface $context The contextual information of
56 * the compilation.
57 *
58 * @return mixed The data to include in the stub version.
59 */
60 public function beforeCreateStub(StubbingContextInterface $context);
61
62 /**
63 * Runs instructions to be executed after creating the stub version of the
64 * resource bundle.
65 *
66 * @param StubbingContextInterface $context The contextual information of
67 * the compilation.
68 */
69 public function afterCreateStub(StubbingContextInterface $context);
70}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/StubbingContext.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/StubbingContext.php
new file mode 100644
index 00000000..25ab68db
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/StubbingContext.php
@@ -0,0 +1,80 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer;
13
14use Symfony\Component\Filesystem\Filesystem;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class StubbingContext implements StubbingContextInterface
20{
21 /**
22 * @var string
23 */
24 private $binaryDir;
25
26 /**
27 * @var string
28 */
29 private $stubDir;
30
31 /**
32 * @var Filesystem
33 */
34 private $filesystem;
35
36 /**
37 * @var string
38 */
39 private $icuVersion;
40
41 public function __construct($binaryDir, $stubDir, Filesystem $filesystem, $icuVersion)
42 {
43 $this->binaryDir = $binaryDir;
44 $this->stubDir = $stubDir;
45 $this->filesystem = $filesystem;
46 $this->icuVersion = $icuVersion;
47 }
48
49 /**
50 * {@inheritdoc}
51 */
52 public function getBinaryDir()
53 {
54 return $this->binaryDir;
55 }
56
57 /**
58 * {@inheritdoc}
59 */
60 public function getStubDir()
61 {
62 return $this->stubDir;
63 }
64
65 /**
66 * {@inheritdoc}
67 */
68 public function getFilesystem()
69 {
70 return $this->filesystem;
71 }
72
73 /**
74 * {@inheritdoc}
75 */
76 public function getIcuVersion()
77 {
78 return $this->icuVersion;
79 }
80}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/StubbingContextInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/StubbingContextInterface.php
new file mode 100644
index 00000000..dc492556
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Transformer/StubbingContextInterface.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Transformer;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17interface StubbingContextInterface
18{
19 /**
20 * Returns the directory where the binary resource bundles are stored.
21 *
22 * @return string An absolute path to a directory.
23 */
24 public function getBinaryDir();
25
26 /**
27 * Returns the directory where the stub resource bundles are stored.
28 *
29 * @return string An absolute path to a directory.
30 */
31 public function getStubDir();
32
33 /**
34 * Returns a tool for manipulating the filesystem.
35 *
36 * @return \Symfony\Component\Filesystem\Filesystem The filesystem manipulator.
37 */
38 public function getFilesystem();
39
40 /**
41 * Returns the ICU version of the bundles being converted.
42 *
43 * @return string The ICU version string.
44 */
45 public function getIcuVersion();
46}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/ArrayAccessibleResourceBundle.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/ArrayAccessibleResourceBundle.php
new file mode 100644
index 00000000..9a4cccb4
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/ArrayAccessibleResourceBundle.php
@@ -0,0 +1,79 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Util;
13
14use Symfony\Component\Intl\Exception\BadMethodCallException;
15
16/**
17 * Work-around for a bug in PHP's \ResourceBundle implementation.
18 *
19 * More information can be found on https://bugs.php.net/bug.php?id=64356.
20 * This class can be removed once that bug is fixed.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class ArrayAccessibleResourceBundle implements \ArrayAccess, \IteratorAggregate, \Countable
25{
26 private $bundleImpl;
27
28 public function __construct(\ResourceBundle $bundleImpl)
29 {
30 $this->bundleImpl = $bundleImpl;
31 }
32
33 public function get($offset, $fallback = null)
34 {
35 $value = $this->bundleImpl->get($offset, $fallback);
36
37 return $value instanceof \ResourceBundle ? new static($value) : $value;
38 }
39
40 public function offsetExists($offset)
41 {
42 return null !== $this->bundleImpl[$offset];
43 }
44
45 public function offsetGet($offset)
46 {
47 return $this->get($offset);
48 }
49
50 public function offsetSet($offset, $value)
51 {
52 throw new BadMethodCallException('Resource bundles cannot be modified.');
53 }
54
55 public function offsetUnset($offset)
56 {
57 throw new BadMethodCallException('Resource bundles cannot be modified.');
58 }
59
60 public function getIterator()
61 {
62 return $this->bundleImpl;
63 }
64
65 public function count()
66 {
67 return $this->bundleImpl->count();
68 }
69
70 public function getErrorCode()
71 {
72 return $this->bundleImpl->getErrorCode();
73 }
74
75 public function getErrorMessage()
76 {
77 return $this->bundleImpl->getErrorMessage();
78 }
79}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/RecursiveArrayAccess.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/RecursiveArrayAccess.php
new file mode 100644
index 00000000..e1feaa2c
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/RecursiveArrayAccess.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Util;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class RecursiveArrayAccess
18{
19 public static function get($array, array $indices)
20 {
21 foreach ($indices as $index) {
22 if (!$array instanceof \ArrayAccess && !is_array($array)) {
23 return null;
24 }
25
26 $array = $array[$index];
27 }
28
29 return $array;
30 }
31
32 private function __construct() {}
33}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/RingBuffer.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/RingBuffer.php
new file mode 100644
index 00000000..7ccbd1e7
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Util/RingBuffer.php
@@ -0,0 +1,88 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Util;
13
14use Symfony\Component\Intl\Exception\OutOfBoundsException;
15
16/**
17 * Implements a ring buffer.
18 *
19 * A ring buffer is an array-like structure with a fixed size. If the buffer
20 * is full, the next written element overwrites the first bucket in the buffer,
21 * then the second and so on.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class RingBuffer implements \ArrayAccess
26{
27 private $values = array();
28
29 private $indices = array();
30
31 private $cursor = 0;
32
33 private $size;
34
35 public function __construct($size)
36 {
37 $this->size = $size;
38 }
39
40 /**
41 * {@inheritdoc}
42 */
43 public function offsetExists($key)
44 {
45 return isset($this->indices[$key]);
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 public function offsetGet($key)
52 {
53 if (!isset($this->indices[$key])) {
54 throw new OutOfBoundsException(sprintf(
55 'The index "%s" does not exist.',
56 $key
57 ));
58 }
59
60 return $this->values[$this->indices[$key]];
61 }
62
63 /**
64 * {@inheritdoc}
65 */
66 public function offsetSet($key, $value)
67 {
68 if (false !== ($keyToRemove = array_search($this->cursor, $this->indices))) {
69 unset($this->indices[$keyToRemove]);
70 }
71
72 $this->values[$this->cursor] = $value;
73 $this->indices[$key] = $this->cursor;
74
75 $this->cursor = ($this->cursor + 1) % $this->size;
76 }
77
78 /**
79 * {@inheritdoc}
80 */
81 public function offsetUnset($key)
82 {
83 if (isset($this->indices[$key])) {
84 $this->values[$this->indices[$key]] = null;
85 unset($this->indices[$key]);
86 }
87 }
88}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/BundleWriterInterface.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/BundleWriterInterface.php
new file mode 100644
index 00000000..cc3b9586
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/BundleWriterInterface.php
@@ -0,0 +1,29 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Writer;
13
14/**
15 * Writes resource bundle files.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface BundleWriterInterface
20{
21 /**
22 * Writes data to a resource bundle.
23 *
24 * @param string $path The path to the resource bundle.
25 * @param string $locale The locale to (over-)write.
26 * @param mixed $data The data to write.
27 */
28 public function write($path, $locale, $data);
29}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/PhpBundleWriter.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/PhpBundleWriter.php
new file mode 100644
index 00000000..d2688b49
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/PhpBundleWriter.php
@@ -0,0 +1,50 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Writer;
13
14/**
15 * Writes .php resource bundles.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class PhpBundleWriter implements BundleWriterInterface
20{
21 /**
22 * {@inheritdoc}
23 */
24 public function write($path, $locale, $data)
25 {
26 $template = <<<TEMPLATE
27<?php
28
29/*
30 * This file is part of the Symfony package.
31 *
32 * (c) Fabien Potencier <fabien@symfony.com>
33 *
34 * For the full copyright and license information, please view the LICENSE
35 * file that was distributed with this source code.
36 */
37
38return %s;
39
40TEMPLATE;
41
42 $data = var_export($data, true);
43 $data = preg_replace('/array \(/', 'array(', $data);
44 $data = preg_replace('/\n {1,10}array\(/', 'array(', $data);
45 $data = preg_replace('/ /', ' ', $data);
46 $data = sprintf($template, $data);
47
48 file_put_contents($path.'/'.$locale.'.php', $data);
49 }
50}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/TextBundleWriter.php b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/TextBundleWriter.php
new file mode 100644
index 00000000..342ee2dc
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/ResourceBundle/Writer/TextBundleWriter.php
@@ -0,0 +1,202 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\ResourceBundle\Writer;
13
14/**
15 * Writes .txt resource bundles.
16 *
17 * The resulting files can be converted to binary .res files using the
18 * {@link \Symfony\Component\Intl\ResourceBundle\Transformer\BundleCompiler}.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 *
22 * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
23 */
24class TextBundleWriter implements BundleWriterInterface
25{
26 /**
27 * {@inheritdoc}
28 */
29 public function write($path, $locale, $data)
30 {
31 $file = fopen($path.'/'.$locale.'.txt', 'w');
32
33 $this->writeResourceBundle($file, $locale, $data);
34
35 fclose($file);
36 }
37
38 /**
39 * Writes a "resourceBundle" node.
40 *
41 * @param resource $file The file handle to write to.
42 * @param string $bundleName The name of the bundle.
43 * @param mixed $value The value of the node.
44 *
45 * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
46 */
47 private function writeResourceBundle($file, $bundleName, $value)
48 {
49 fwrite($file, $bundleName);
50
51 $this->writeTable($file, $value, 0);
52
53 fwrite($file, "\n");
54 }
55
56 /**
57 * Writes a "resource" node.
58 *
59 * @param resource $file The file handle to write to.
60 * @param mixed $value The value of the node.
61 * @param integer $indentation The number of levels to indent.
62 * @param Boolean $requireBraces Whether to require braces to be printed
63 * around the value.
64 *
65 * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
66 */
67 private function writeResource($file, $value, $indentation, $requireBraces = true)
68 {
69 if (is_int($value)) {
70 $this->writeInteger($file, $value);
71
72 return;
73 }
74
75 if (is_array($value)) {
76 if (count($value) === count(array_filter($value, 'is_int'))) {
77 $this->writeIntVector($file, $value, $indentation);
78
79 return;
80 }
81
82 $keys = array_keys($value);
83
84 if (count($keys) === count(array_filter($keys, 'is_int'))) {
85 $this->writeArray($file, $value, $indentation);
86
87 return;
88 }
89
90 $this->writeTable($file, $value, $indentation);
91
92 return;
93 }
94
95 if (is_bool($value)) {
96 $value = $value ? 'true' : 'false';
97 }
98
99 $this->writeString($file, (string) $value, $requireBraces);
100 }
101
102 /**
103 * Writes an "integer" node.
104 *
105 * @param resource $file The file handle to write to.
106 * @param integer $value The value of the node.
107 *
108 * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
109 */
110 private function writeInteger($file, $value)
111 {
112 fprintf($file, ':int{%d}', $value);
113 }
114
115 /**
116 * Writes an "intvector" node.
117 *
118 * @param resource $file The file handle to write to.
119 * @param array $value The value of the node.
120 * @param integer $indentation The number of levels to indent.
121 *
122 * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
123 */
124 private function writeIntVector($file, array $value, $indentation)
125 {
126 fwrite($file, ":intvector{\n");
127
128 foreach ($value as $int) {
129 fprintf($file, "%s%d,\n", str_repeat(' ', $indentation + 1), $int);
130 }
131
132 fprintf($file, "%s}", str_repeat(' ', $indentation));
133 }
134
135 /**
136 * Writes a "string" node.
137 *
138 * @param resource $file The file handle to write to.
139 * @param string $value The value of the node.
140 * @param Boolean $requireBraces Whether to require braces to be printed
141 * around the value.
142 *
143 * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
144 */
145 private function writeString($file, $value, $requireBraces = true)
146 {
147 if ($requireBraces) {
148 fprintf($file, '{"%s"}', $value);
149
150 return;
151 }
152
153 fprintf($file, '"%s"', $value);
154 }
155
156 /**
157 * Writes an "array" node.
158 *
159 * @param resource $file The file handle to write to.
160 * @param array $value The value of the node.
161 * @param integer $indentation The number of levels to indent.
162 *
163 * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
164 */
165 private function writeArray($file, array $value, $indentation)
166 {
167 fwrite($file, "{\n");
168
169 foreach ($value as $entry) {
170 fwrite($file, str_repeat(' ', $indentation + 1));
171
172 $this->writeResource($file, $entry, $indentation + 1, false);
173
174 fwrite($file, ",\n");
175 }
176
177 fprintf($file, '%s}', str_repeat(' ', $indentation));
178 }
179
180 /**
181 * Writes a "table" node.
182 *
183 * @param resource $file The file handle to write to.
184 * @param array $value The value of the node.
185 * @param integer $indentation The number of levels to indent.
186 */
187 private function writeTable($file, array $value, $indentation)
188 {
189 fwrite($file, "{\n");
190
191 foreach ($value as $key => $entry) {
192 fwrite($file, str_repeat(' ', $indentation + 1));
193 fwrite($file, $key);
194
195 $this->writeResource($file, $entry, $indentation + 1);
196
197 fwrite($file, "\n");
198 }
199
200 fprintf($file, '%s}', str_repeat(' ', $indentation));
201 }
202}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/autoload.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/autoload.php
new file mode 100644
index 00000000..e4500115
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/autoload.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12$autoload = __DIR__ . '/../../vendor/autoload.php';
13
14if (!file_exists($autoload)) {
15 bailout('You should run "composer install --dev" in the component before running this script.');
16}
17
18require_once realpath($autoload);
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/common.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/common.php
new file mode 100644
index 00000000..4fadbe82
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/common.php
@@ -0,0 +1,69 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12define('LINE_WIDTH', 75);
13
14define('LINE', str_repeat('-', LINE_WIDTH) . "\n");
15
16function bailout($message)
17{
18 echo wordwrap($message, LINE_WIDTH) . " Aborting.\n";
19
20 exit(1);
21}
22
23function strip_minor_versions($version)
24{
25 preg_match('/^(?P<version>[0-9]\.[0-9]|[0-9]{2,})/', $version, $matches);
26
27 return $matches['version'];
28}
29
30function centered($text)
31{
32 $padding = (int) ((LINE_WIDTH - strlen($text))/2);
33
34 return str_repeat(' ', $padding) . $text;
35}
36
37function cd($dir)
38{
39 if (false === chdir($dir)) {
40 bailout("Could not switch to directory $dir.");
41 }
42}
43
44function run($command)
45{
46 exec($command, $output, $status);
47
48 if (0 !== $status) {
49 $output = implode("\n", $output);
50 echo "Error while running:\n " . getcwd() . '$ ' . $command . "\nOutput:\n" . LINE . "$output\n" . LINE;
51
52 bailout("\"$command\" failed.");
53 }
54}
55
56function get_icu_version_from_genrb($genrb)
57{
58 exec($genrb . ' --version 2>&1', $output, $status);
59
60 if (0 !== $status) {
61 bailout($genrb . ' failed.');
62 }
63
64 if (!preg_match('/ICU version ([\d\.]+)/', implode('', $output), $matches)) {
65 return null;
66 }
67
68 return $matches[1];
69}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/copy-stubs-to-component.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/copy-stubs-to-component.php
new file mode 100644
index 00000000..e8576832
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/copy-stubs-to-component.php
@@ -0,0 +1,63 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12use Symfony\Component\Filesystem\Filesystem;
13use Symfony\Component\Icu\IcuData;
14use Symfony\Component\Intl\Intl;
15
16require_once __DIR__ . '/common.php';
17require_once __DIR__ . '/autoload.php';
18
19if (1 !== $GLOBALS['argc']) {
20 bailout(<<<MESSAGE
21Usage: php copy-stubs-to-component.php
22
23Copies stub files created with create-stubs.php to the Icu component.
24
25For running this script, the intl extension must be loaded and all vendors
26must have been installed through composer:
27
28 composer install --dev
29
30MESSAGE
31 );
32}
33
34echo LINE;
35echo centered("ICU Resource Bundle Stub Update") . "\n";
36echo LINE;
37
38if (!class_exists('\Symfony\Component\Icu\IcuData')) {
39 bailout('You must run "composer update --dev" before running this script.');
40}
41
42$stubBranch = '1.0.x';
43
44if (!IcuData::isStubbed()) {
45 bailout("Please switch to the Icu component branch $stubBranch.");
46}
47
48$filesystem = new Filesystem();
49
50$sourceDir = sys_get_temp_dir() . '/icu-stubs';
51$targetDir = IcuData::getResourceDirectory();
52
53if (!$filesystem->exists($sourceDir)) {
54 bailout("The directory $sourceDir does not exist. Please run create-stubs.php first.");
55}
56
57$filesystem->remove($targetDir);
58
59echo "Copying files from $sourceDir to $targetDir...\n";
60
61$filesystem->mirror($sourceDir, $targetDir);
62
63echo "Done.\n";
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/create-stubs.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/create-stubs.php
new file mode 100644
index 00000000..d330d6b5
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/create-stubs.php
@@ -0,0 +1,112 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12use Symfony\Component\Filesystem\Filesystem;
13use Symfony\Component\Icu\IcuData;
14use Symfony\Component\Intl\Intl;
15use Symfony\Component\Intl\ResourceBundle\Transformer\BundleTransformer;
16use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\CurrencyBundleTransformationRule;
17use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LanguageBundleTransformationRule;
18use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LocaleBundleTransformationRule;
19use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\RegionBundleTransformationRule;
20use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContext;
21
22require_once __DIR__ . '/common.php';
23require_once __DIR__ . '/autoload.php';
24
25if (1 !== $GLOBALS['argc']) {
26 bailout(<<<MESSAGE
27Usage: php create-stubs.php
28
29Creates resource bundle stubs from the resource bundles in the Icu component.
30
31For running this script, the intl extension must be loaded and all vendors
32must have been installed through composer:
33
34 composer install --dev
35
36MESSAGE
37 );
38}
39
40echo LINE;
41echo centered("ICU Resource Bundle Stub Creation") . "\n";
42echo LINE;
43
44if (!Intl::isExtensionLoaded()) {
45 bailout('The intl extension for PHP is not installed.');
46}
47
48if (!class_exists('\Symfony\Component\Icu\IcuData')) {
49 bailout('You must run "composer update --dev" before running this script.');
50}
51
52$stubBranch = '1.0.x';
53
54if (IcuData::isStubbed()) {
55 bailout("Please switch to a branch of the Icu component that contains .res files (anything but $stubBranch).");
56}
57
58$shortIcuVersionInPhp = strip_minor_versions(Intl::getIcuVersion());
59$shortIcuVersionInIntlComponent = strip_minor_versions(Intl::getIcuStubVersion());
60$shortIcuVersionInIcuComponent = strip_minor_versions(IcuData::getVersion());
61
62if ($shortIcuVersionInPhp !== $shortIcuVersionInIcuComponent) {
63 bailout("The ICU version of the component ($shortIcuVersionInIcuComponent) does not match the ICU version in the intl extension ($shortIcuVersionInPhp).");
64}
65
66if ($shortIcuVersionInIntlComponent !== $shortIcuVersionInIcuComponent) {
67 bailout("The ICU version of the component ($shortIcuVersionInIcuComponent) does not match the ICU version of the stub classes in the Intl component ($shortIcuVersionInIntlComponent).");
68}
69
70echo wordwrap("Make sure that you don't have any ICU development files " .
71 "installed. If the build fails, try to run:\n", LINE_WIDTH);
72
73echo "\n sudo apt-get remove libicu-dev\n\n";
74
75$icuVersionInIcuComponent = IcuData::getVersion();
76
77echo "Compiling stubs for ICU version $icuVersionInIcuComponent.\n";
78
79echo "Preparing stub creation...\n";
80
81$targetDir = sys_get_temp_dir() . '/icu-stubs';
82
83$context = new StubbingContext(
84 IcuData::getResourceDirectory(),
85 $targetDir,
86 new Filesystem(),
87 $icuVersionInIcuComponent
88);
89
90$transformer = new BundleTransformer();
91$transformer->addRule(new LanguageBundleTransformationRule());
92$transformer->addRule(new RegionBundleTransformationRule());
93$transformer->addRule(new CurrencyBundleTransformationRule());
94$transformer->addRule(new LocaleBundleTransformationRule());
95
96echo "Starting stub creation...\n";
97
98$transformer->createStubs($context);
99
100echo "Wrote stubs to $targetDir.\n";
101
102$versionFile = $context->getStubDir() . '/version.txt';
103
104file_put_contents($versionFile, "$icuVersionInIcuComponent\n");
105
106echo "Wrote $versionFile.\n";
107
108echo "Done.\n";
109
110echo wordwrap("Please change the Icu component to branch $stubBranch now and run:\n", LINE_WIDTH);
111
112echo "\n php copy-stubs-to-component.php\n";
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/icu-version.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/icu-version.php
new file mode 100644
index 00000000..d54916f5
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/icu-version.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12use Symfony\Component\Intl\Intl;
13
14require_once __DIR__ . '/common.php';
15require_once __DIR__ . '/autoload.php';
16
17echo "ICU version: ";
18echo Intl::getIcuVersion() . "\n";
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/icu.ini b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/icu.ini
new file mode 100644
index 00000000..902e3361
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/icu.ini
@@ -0,0 +1,9 @@
1; ICU data source URLs
2; We use always the latest release of a major version.
34.0 = http://source.icu-project.org/repos/icu/icu/tags/release-4-0-1/source
44.2 = http://source.icu-project.org/repos/icu/icu/tags/release-4-2-1/source
54.4 = http://source.icu-project.org/repos/icu/icu/tags/release-4-4-2/source
64.6 = http://source.icu-project.org/repos/icu/icu/tags/release-4-6-1/source
74.8 = http://source.icu-project.org/repos/icu/icu/tags/release-4-8-1-1/source
849 = http://source.icu-project.org/repos/icu/icu/tags/release-49-1-2/source
950 = http://source.icu-project.org/repos/icu/icu/tags/release-50-1-2/source
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/test-compat.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/test-compat.php
new file mode 100644
index 00000000..c1bf40f7
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/test-compat.php
@@ -0,0 +1,56 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12use Symfony\Component\Intl\Intl;
13
14require_once __DIR__ . '/common.php';
15require_once __DIR__ . '/autoload.php';
16
17if (1 !== $GLOBALS['argc']) {
18 bailout(<<<MESSAGE
19Usage: php test-compat.php
20
21Tests the compatibility of the current ICU version (bundled in ext/intl) with
22different versions of symfony/icu.
23
24For running this script, the intl extension must be loaded and all vendors
25must have been installed through composer:
26
27 composer install --dev
28
29MESSAGE
30 );
31}
32
33echo LINE;
34echo centered("ICU Compatibility Test") . "\n";
35echo LINE;
36
37echo "Your ICU version: " . Intl::getIcuVersion() . "\n";
38
39echo "Compatibility with symfony/icu:\n";
40
41$branches = array(
42 '1.1.x',
43 '1.2.x',
44);
45
46cd(__DIR__ . '/../../vendor/symfony/icu/Symfony/Component/Icu');
47
48foreach ($branches as $branch) {
49 run('git checkout ' . $branch . ' 2>&1');
50
51 exec('php ' . __DIR__ . '/util/test-compat-helper.php > /dev/null 2> /dev/null', $output, $status);
52
53 echo "$branch: " . (0 === $status ? "YES" : "NO") . "\n";
54}
55
56echo "Done.\n";
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/update-icu-component.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/update-icu-component.php
new file mode 100644
index 00000000..2b94fe41
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/update-icu-component.php
@@ -0,0 +1,212 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12use Symfony\Component\Icu\IcuData;
13use Symfony\Component\Intl\Intl;
14use Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompiler;
15use Symfony\Component\Intl\ResourceBundle\Transformer\BundleTransformer;
16use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContext;
17use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\CurrencyBundleTransformationRule;
18use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LanguageBundleTransformationRule;
19use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LocaleBundleTransformationRule;
20use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\RegionBundleTransformationRule;
21use Symfony\Component\Intl\Util\SvnRepository;
22use Symfony\Component\Filesystem\Filesystem;
23
24require_once __DIR__ . '/common.php';
25require_once __DIR__ . '/autoload.php';
26
27if ($GLOBALS['argc'] > 3 || 2 === $GLOBALS['argc'] && '-h' === $GLOBALS['argv'][1]) {
28 bailout(<<<MESSAGE
29Usage: php update-icu-component.php <path/to/icu/source> <path/to/icu/build>
30
31Updates the ICU data for Symfony2 to the latest version of the ICU version
32included in the intl extension. For example, if your intl extension includes
33ICU 4.8, the script will download the latest data available for ICU 4.8.
34
35If you downloaded the SVN repository before, you can pass the path to the
36repository source in the first optional argument.
37
38If you also built the repository before, you can pass the directory where that
39build is stored in the second parameter. The build directory needs to contain
40the subdirectories bin/ and lib/.
41
42For running this script, the intl extension must be loaded and all vendors
43must have been installed through composer:
44
45 composer install --dev
46
47MESSAGE
48 );
49}
50
51echo LINE;
52echo centered("ICU Resource Bundle Compilation") . "\n";
53echo LINE;
54
55if (!Intl::isExtensionLoaded()) {
56 bailout('The intl extension for PHP is not installed.');
57}
58
59if (!class_exists('\Symfony\Component\Icu\IcuData')) {
60 bailout('You must run "composer update --dev" before running this script.');
61}
62
63$filesystem = new Filesystem();
64
65$icuVersionInPhp = Intl::getIcuVersion();
66
67echo "Found intl extension with ICU version $icuVersionInPhp.\n";
68
69$shortIcuVersion = strip_minor_versions($icuVersionInPhp);
70$urls = parse_ini_file(__DIR__ . '/icu.ini');
71
72if (!isset($urls[$shortIcuVersion])) {
73 bailout('The version ' . $shortIcuVersion . ' is not available in the icu.ini file.');
74}
75
76echo "icu.ini parsed. Available versions:\n";
77
78foreach ($urls as $urlVersion => $url) {
79 echo " $urlVersion\n";
80}
81
82if ($GLOBALS['argc'] >= 2) {
83 $sourceDir = $GLOBALS['argv'][1];
84 $svn = new SvnRepository($sourceDir);
85
86 echo "Using existing SVN repository at {$sourceDir}.\n";
87} else {
88 echo "Starting SVN checkout for version $shortIcuVersion. This may take a while...\n";
89
90 $sourceDir = sys_get_temp_dir() . '/icu-data/' . $shortIcuVersion . '/source';
91 $svn = SvnRepository::download($urls[$shortIcuVersion], $sourceDir);
92
93 echo "SVN checkout to {$sourceDir} complete.\n";
94}
95
96if ($GLOBALS['argc'] >= 3) {
97 $buildDir = $GLOBALS['argv'][2];
98} else {
99 // Always build genrb so that we can determine the ICU version of the
100 // download by running genrb --version
101 echo "Building genrb.\n";
102
103 cd($sourceDir);
104
105 echo "Running configure...\n";
106
107 $buildDir = sys_get_temp_dir() . '/icu-data/' . $shortIcuVersion . '/build';
108
109 $filesystem->remove($buildDir);
110 $filesystem->mkdir($buildDir);
111
112 run('./configure --prefix=' . $buildDir . ' 2>&1');
113
114 echo "Running make...\n";
115
116 // If the directory "lib" does not exist in the download, create it or we
117 // will run into problems when building libicuuc.so.
118 $filesystem->mkdir($sourceDir . '/lib');
119
120 // If the directory "bin" does not exist in the download, create it or we
121 // will run into problems when building genrb.
122 $filesystem->mkdir($sourceDir . '/bin');
123
124 echo "[1/5] libicudata.so...";
125
126 cd($sourceDir . '/stubdata');
127 run('make 2>&1 && make install 2>&1');
128
129 echo " ok.\n";
130
131 echo "[2/5] libicuuc.so...";
132
133 cd($sourceDir . '/common');
134 run('make 2>&1 && make install 2>&1');
135
136 echo " ok.\n";
137
138 echo "[3/5] libicui18n.so...";
139
140 cd($sourceDir . '/i18n');
141 run('make 2>&1 && make install 2>&1');
142
143 echo " ok.\n";
144
145 echo "[4/5] libicutu.so...";
146
147 cd($sourceDir . '/tools/toolutil');
148 run('make 2>&1 && make install 2>&1');
149
150 echo " ok.\n";
151
152 echo "[5/5] genrb...";
153
154 cd($sourceDir . '/tools/genrb');
155 run('make 2>&1 && make install 2>&1');
156
157 echo " ok.\n";
158}
159
160$genrb = $buildDir . '/bin/genrb';
161$genrbEnv = 'LD_LIBRARY_PATH=' . $buildDir . '/lib ';
162
163echo "Using $genrb.\n";
164
165$icuVersionInDownload = get_icu_version_from_genrb($genrbEnv . ' ' . $genrb);
166
167echo "Preparing resource bundle compilation (version $icuVersionInDownload)...\n";
168
169$context = new CompilationContext(
170 $sourceDir . '/data',
171 IcuData::getResourceDirectory(),
172 $filesystem,
173 new BundleCompiler($genrb, $genrbEnv),
174 $icuVersionInDownload
175);
176
177$transformer = new BundleTransformer();
178$transformer->addRule(new LanguageBundleTransformationRule());
179$transformer->addRule(new RegionBundleTransformationRule());
180$transformer->addRule(new CurrencyBundleTransformationRule());
181$transformer->addRule(new LocaleBundleTransformationRule());
182
183echo "Starting resource bundle compilation. This may take a while...\n";
184
185$transformer->compileBundles($context);
186
187echo "Resource bundle compilation complete.\n";
188
189$svnInfo = <<<SVN_INFO
190SVN information
191===============
192
193URL: {$svn->getUrl()}
194Revision: {$svn->getLastCommit()->getRevision()}
195Author: {$svn->getLastCommit()->getAuthor()}
196Date: {$svn->getLastCommit()->getDate()}
197
198SVN_INFO;
199
200$svnInfoFile = $context->getBinaryDir() . '/svn-info.txt';
201
202file_put_contents($svnInfoFile, $svnInfo);
203
204echo "Wrote $svnInfoFile.\n";
205
206$versionFile = $context->getBinaryDir() . '/version.txt';
207
208file_put_contents($versionFile, "$icuVersionInDownload\n");
209
210echo "Wrote $versionFile.\n";
211
212echo "Done.\n";
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/util/test-compat-helper.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/util/test-compat-helper.php
new file mode 100644
index 00000000..2734895c
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/bin/util/test-compat-helper.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12use Symfony\Component\Icu\IcuData;
13use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader;
14
15require_once __DIR__ . '/../common.php';
16require_once __DIR__ . '/../autoload.php';
17
18$reader = new BinaryBundleReader();
19
20$reader->read(IcuData::getResourceDirectory() . '/curr', 'en');
21$reader->read(IcuData::getResourceDirectory() . '/lang', 'en');
22$reader->read(IcuData::getResourceDirectory() . '/locales', 'en');
23$reader->read(IcuData::getResourceDirectory() . '/region', 'en');
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/Collator.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/Collator.php
new file mode 100644
index 00000000..4c373d86
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/Collator.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12/**
13 * Stub implementation for the Collator class of the intl extension
14 *
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 *
17 * @see \Symfony\Component\Intl\Collator\StubCollator
18 */
19class Collator extends \Symfony\Component\Intl\Collator\Collator
20{
21}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/IntlDateFormatter.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/IntlDateFormatter.php
new file mode 100644
index 00000000..52a07e95
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/IntlDateFormatter.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12/**
13 * Stub implementation for the IntlDateFormatter class of the intl extension
14 *
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 *
17 * @see \Symfony\Component\Intl\DateFormatter\IntlDateFormatter
18 */
19class IntlDateFormatter extends \Symfony\Component\Intl\DateFormatter\IntlDateFormatter
20{
21}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/Locale.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/Locale.php
new file mode 100644
index 00000000..045db40c
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/Locale.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12/**
13 * Stub implementation for the Locale class of the intl extension
14 *
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 *
17 * @see \Symfony\Component\Intl\Locale\Locale
18 */
19class Locale extends \Symfony\Component\Intl\Locale\Locale
20{
21}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/NumberFormatter.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/NumberFormatter.php
new file mode 100644
index 00000000..318efb49
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/NumberFormatter.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12/**
13 * Stub implementation for the NumberFormatter class of the intl extension
14 *
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 *
17 * @see \Symfony\Component\Intl\NumberFormatter\NumberFormatter
18 */
19class NumberFormatter extends \Symfony\Component\Intl\NumberFormatter\NumberFormatter
20{
21}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/functions.php b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/functions.php
new file mode 100644
index 00000000..7a2d4b67
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Resources/stubs/functions.php
@@ -0,0 +1,80 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12use Symfony\Component\Intl\Globals\IntlGlobals;
13
14if (!function_exists('intl_is_failure')) {
15
16 /**
17 * Stub implementation for the {@link intl_is_failure()} function of the intl
18 * extension.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 *
22 * @param integer $errorCode The error code returned by intl_get_error_code().
23 *
24 * @return Boolean Whether the error code indicates an error.
25 *
26 * @see \Symfony\Component\Intl\Globals\StubIntlGlobals::isFailure
27 */
28 function intl_is_failure($errorCode)
29 {
30 return IntlGlobals::isFailure($errorCode);
31 }
32
33 /**
34 * Stub implementation for the {@link intl_get_error_code()} function of the
35 * intl extension.
36 *
37 * @author Bernhard Schussek <bschussek@gmail.com>
38 *
39 * @return Boolean The error code of the last intl function call or
40 * IntlGlobals::U_ZERO_ERROR if no error occurred.
41 *
42 * @see \Symfony\Component\Intl\Globals\StubIntlGlobals::getErrorCode
43 */
44 function intl_get_error_code()
45 {
46 return IntlGlobals::getErrorCode();
47 }
48
49 /**
50 * Stub implementation for the {@link intl_get_error_code()} function of the
51 * intl extension.
52 *
53 * @author Bernhard Schussek <bschussek@gmail.com>
54 *
55 * @return Boolean The error message of the last intl function call or
56 * "U_ZERO_ERROR" if no error occurred.
57 *
58 * @see \Symfony\Component\Intl\Globals\StubIntlGlobals::getErrorMessage
59 */
60 function intl_get_error_message()
61 {
62 return IntlGlobals::getErrorMessage();
63 }
64
65 /**
66 * Stub implementation for the {@link intl_error_name()} function of the intl
67 * extension.
68 *
69 * @param integer $errorCode The error code.
70 *
71 * @return string The name of the error code constant.
72 *
73 * @see \Symfony\Component\Intl\Globals\StubIntlGlobals::getErrorName
74 */
75 function intl_error_name($errorCode)
76 {
77 return IntlGlobals::getErrorName($errorCode);
78 }
79
80}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/AbstractCollatorTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/AbstractCollatorTest.php
new file mode 100644
index 00000000..08f3a566
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/AbstractCollatorTest.php
@@ -0,0 +1,62 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Collator;
13
14use Symfony\Component\Intl\Collator\Collator;
15use Symfony\Component\Intl\Locale;
16
17/**
18 * Test case for Collator implementations.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22abstract class AbstractCollatorTest extends \PHPUnit_Framework_TestCase
23{
24 /**
25 * @dataProvider asortProvider
26 */
27 public function testAsort($array, $sortFlag, $expected)
28 {
29 $collator = $this->getCollator('en');
30 $collator->asort($array, $sortFlag);
31 $this->assertSame($expected, $array);
32 }
33
34 public function asortProvider()
35 {
36 return array(
37 /* array, sortFlag, expected */
38 array(
39 array('a', 'b', 'c'),
40 Collator::SORT_REGULAR,
41 array('a', 'b', 'c'),
42 ),
43 array(
44 array('c', 'b', 'a'),
45 Collator::SORT_REGULAR,
46 array(2 => 'a', 1 => 'b', 0 => 'c'),
47 ),
48 array(
49 array('b', 'c', 'a'),
50 Collator::SORT_REGULAR,
51 array(2 => 'a', 0 => 'b', 1 => 'c'),
52 ),
53 );
54 }
55
56 /**
57 * @param string $locale
58 *
59 * @return \Collator
60 */
61 abstract protected function getCollator($locale);
62}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/CollatorTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/CollatorTest.php
new file mode 100644
index 00000000..a4e4e56b
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/CollatorTest.php
@@ -0,0 +1,109 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Collator;
13
14use Symfony\Component\Intl\Collator\Collator;
15use Symfony\Component\Intl\Globals\IntlGlobals;
16
17class CollatorTest extends AbstractCollatorTest
18{
19 /**
20 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
21 */
22 public function testConstructorWithUnsupportedLocale()
23 {
24 new Collator('pt_BR');
25 }
26
27 /**
28 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
29 */
30 public function testCompare()
31 {
32 $collator = $this->getCollator('en');
33 $collator->compare('a', 'b');
34 }
35
36 /**
37 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
38 */
39 public function testGetAttribute()
40 {
41 $collator = $this->getCollator('en');
42 $collator->getAttribute(Collator::NUMERIC_COLLATION);
43 }
44
45 public function testGetErrorCode()
46 {
47 $collator = $this->getCollator('en');
48 $this->assertEquals(IntlGlobals::U_ZERO_ERROR, $collator->getErrorCode());
49 }
50
51 public function testGetErrorMessage()
52 {
53 $collator = $this->getCollator('en');
54 $this->assertEquals('U_ZERO_ERROR', $collator->getErrorMessage());
55 }
56
57 public function testGetLocale()
58 {
59 $collator = $this->getCollator('en');
60 $this->assertEquals('en', $collator->getLocale());
61 }
62
63 /**
64 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
65 */
66 public function testGetSortKey()
67 {
68 $collator = $this->getCollator('en');
69 $collator->getSortKey('Hello');
70 }
71
72 /**
73 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
74 */
75 public function testGetStrength()
76 {
77 $collator = $this->getCollator('en');
78 $collator->getStrength();
79 }
80
81 /**
82 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
83 */
84 public function testSetAttribute()
85 {
86 $collator = $this->getCollator('en');
87 $collator->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
88 }
89
90 /**
91 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
92 */
93 public function testSetStrength()
94 {
95 $collator = $this->getCollator('en');
96 $collator->setStrength(Collator::PRIMARY);
97 }
98
99 public function testStaticCreate()
100 {
101 $collator = Collator::create('en');
102 $this->assertInstanceOf('\Symfony\Component\Intl\Collator\Collator', $collator);
103 }
104
105 protected function getCollator($locale)
106 {
107 return new Collator($locale);
108 }
109}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/Verification/CollatorTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/Verification/CollatorTest.php
new file mode 100644
index 00000000..c8dbc131
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Collator/Verification/CollatorTest.php
@@ -0,0 +1,37 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Collator\Verification;
13
14use Symfony\Component\Intl\Locale;
15use Symfony\Component\Intl\Tests\Collator\AbstractCollatorTest;
16use Symfony\Component\Intl\Util\IntlTestHelper;
17
18/**
19 * Verifies that {@link AbstractCollatorTest} matches the behavior of the
20 * {@link \Collator} class in a specific version of ICU.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class CollatorTest extends AbstractCollatorTest
25{
26 protected function setUp()
27 {
28 IntlTestHelper::requireFullIntl($this);
29
30 parent::setUp();
31 }
32
33 protected function getCollator($locale)
34 {
35 return new \Collator($locale);
36 }
37}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php
new file mode 100644
index 00000000..3ffb4909
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php
@@ -0,0 +1,932 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\DateFormatter;
13
14use Symfony\Component\Intl\DateFormatter\IntlDateFormatter;
15use Symfony\Component\Intl\Globals\IntlGlobals;
16use Symfony\Component\Intl\Intl;
17
18/**
19 * Test case for IntlDateFormatter implementations.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase
24{
25 /**
26 * When a time zone is not specified, it uses the system default however it returns null in the getter method
27 * @covers Symfony\Component\Intl\DateFormatter\IntlDateFormatter::getTimeZoneId
28 * @see StubIntlDateFormatterTest::testDefaultTimeZoneIntl()
29 */
30 public function testConstructorDefaultTimeZone()
31 {
32 $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
33
34 // In PHP 5.5 default timezone depends on `date_default_timezone_get()` method
35 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
36 $this->assertEquals(date_default_timezone_get(), $formatter->getTimeZoneId());
37 } else {
38 $this->assertNull($formatter->getTimeZoneId());
39 }
40 }
41
42 /**
43 * @dataProvider formatProvider
44 */
45 public function testFormat($pattern, $timestamp, $expected)
46 {
47 $errorCode = IntlGlobals::U_ZERO_ERROR;
48 $errorMessage = 'U_ZERO_ERROR';
49
50 $formatter = $this->getDefaultDateFormatter($pattern);
51 $this->assertSame($expected, $formatter->format($timestamp));
52 $this->assertIsIntlSuccess($formatter, $errorMessage, $errorCode);
53 }
54
55 public function formatProvider()
56 {
57 $formatData = array(
58 /* general */
59 array('y-M-d', 0, '1970-1-1'),
60 array("EEE, MMM d, ''yy", 0, "Thu, Jan 1, '70"),
61 array('h:mm a', 0, '12:00 AM'),
62 array('yyyyy.MMMM.dd hh:mm aaa', 0, '01970.January.01 12:00 AM'),
63
64 /* escaping */
65 array("'M'", 0, 'M'),
66 array("'yy'", 0, 'yy'),
67 array("'''yy'", 0, "'yy"),
68 array("''y", 0, "'1970"),
69 array("''yy", 0, "'70"),
70 array("H 'o'' clock'", 0, "0 o' clock"),
71
72 /* month */
73 array('M', 0, '1'),
74 array('MM', 0, '01'),
75 array('MMM', 0, 'Jan'),
76 array('MMMM', 0, 'January'),
77 array('MMMMM', 0, 'J'),
78 array('MMMMMM', 0, '000001'),
79
80 array('L', 0, '1'),
81 array('LL', 0, '01'),
82 array('LLL', 0, 'Jan'),
83 array('LLLL', 0, 'January'),
84 array('LLLLL', 0, 'J'),
85 array('LLLLLL', 0, '000001'),
86
87 /* year */
88 array('y', 0, '1970'),
89 array('yy', 0, '70'),
90 array('yyy', 0, '1970'),
91 array('yyyy', 0, '1970'),
92 array('yyyyy', 0, '01970'),
93 array('yyyyyy', 0, '001970'),
94
95 /* day */
96 array('d', 0, '1'),
97 array('dd', 0, '01'),
98 array('ddd', 0, '001'),
99
100 /* quarter */
101 array('Q', 0, '1'),
102 array('QQ', 0, '01'),
103 array('QQQ', 0, 'Q1'),
104 array('QQQQ', 0, '1st quarter'),
105 array('QQQQQ', 0, '1st quarter'),
106
107 array('q', 0, '1'),
108 array('qq', 0, '01'),
109 array('qqq', 0, 'Q1'),
110 array('qqqq', 0, '1st quarter'),
111 array('qqqqq', 0, '1st quarter'),
112
113 // 4 months
114 array('Q', 7776000, '2'),
115 array('QQ', 7776000, '02'),
116 array('QQQ', 7776000, 'Q2'),
117 array('QQQQ', 7776000, '2nd quarter'),
118
119 // 7 months
120 array('QQQQ', 15638400, '3rd quarter'),
121
122 // 10 months
123 array('QQQQ', 23587200, '4th quarter'),
124
125 /* 12-hour (1-12) */
126 array('h', 0, '12'),
127 array('hh', 0, '12'),
128 array('hhh', 0, '012'),
129
130 array('h', 1, '12'),
131 array('h', 3600, '1'),
132 array('h', 43200, '12'), // 12 hours
133
134 /* day of year */
135 array('D', 0, '1'),
136 array('D', 86400, '2'), // 1 day
137 array('D', 31536000, '1'), // 1 year
138 array('D', 31622400, '2'), // 1 year + 1 day
139
140 /* day of week */
141 array('E', 0, 'Thu'),
142 array('EE', 0, 'Thu'),
143 array('EEE', 0, 'Thu'),
144 array('EEEE', 0, 'Thursday'),
145 array('EEEEE', 0, 'T'),
146 array('EEEEEE', 0, 'Thu'),
147
148 array('E', 1296540000, 'Tue'), // 2011-02-01
149 array('E', 1296950400, 'Sun'), // 2011-02-06
150
151 /* am/pm marker */
152 array('a', 0, 'AM'),
153 array('aa', 0, 'AM'),
154 array('aaa', 0, 'AM'),
155 array('aaaa', 0, 'AM'),
156
157 // 12 hours
158 array('a', 43200, 'PM'),
159 array('aa', 43200, 'PM'),
160 array('aaa', 43200, 'PM'),
161 array('aaaa', 43200, 'PM'),
162
163 /* 24-hour (0-23) */
164 array('H', 0, '0'),
165 array('HH', 0, '00'),
166 array('HHH', 0, '000'),
167
168 array('H', 1, '0'),
169 array('H', 3600, '1'),
170 array('H', 43200, '12'),
171 array('H', 46800, '13'),
172
173 /* 24-hour (1-24) */
174 array('k', 0, '24'),
175 array('kk', 0, '24'),
176 array('kkk', 0, '024'),
177
178 array('k', 1, '24'),
179 array('k', 3600, '1'),
180 array('k', 43200, '12'),
181 array('k', 46800, '13'),
182
183 /* 12-hour (0-11) */
184 array('K', 0, '0'),
185 array('KK', 0, '00'),
186 array('KKK', 0, '000'),
187
188 array('K', 1, '0'),
189 array('K', 3600, '1'),
190 array('K', 43200, '0'), // 12 hours
191
192 /* minute */
193 array('m', 0, '0'),
194 array('mm', 0, '00'),
195 array('mmm', 0, '000'),
196
197 array('m', 1, '0'),
198 array('m', 60, '1'),
199 array('m', 120, '2'),
200 array('m', 180, '3'),
201 array('m', 3600, '0'),
202 array('m', 3660, '1'),
203 array('m', 43200, '0'), // 12 hours
204
205 /* second */
206 array('s', 0, '0'),
207 array('ss', 0, '00'),
208 array('sss', 0, '000'),
209
210 array('s', 1, '1'),
211 array('s', 2, '2'),
212 array('s', 5, '5'),
213 array('s', 30, '30'),
214 array('s', 59, '59'),
215 array('s', 60, '0'),
216 array('s', 120, '0'),
217 array('s', 180, '0'),
218 array('s', 3600, '0'),
219 array('s', 3601, '1'),
220 array('s', 3630, '30'),
221 array('s', 43200, '0'), // 12 hours
222
223 // general
224 array("yyyy.MM.dd 'at' HH:mm:ss zzz", 0, '1970.01.01 at 00:00:00 GMT'),
225 array('K:mm a, z', 0, '0:00 AM, GMT'),
226
227 // timezone
228 array('z', 0, 'GMT'),
229 array('zz', 0, 'GMT'),
230 array('zzz', 0, 'GMT'),
231 array('zzzz', 0, 'GMT'),
232 array('zzzzz', 0, 'GMT'),
233 );
234
235 // As of PHP 5.3.4, IntlDateFormatter::format() accepts DateTime instances
236 if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
237 $dateTime = new \DateTime('@0');
238
239 /* general, DateTime */
240 $formatData[] = array('y-M-d', $dateTime, '1970-1-1');
241 $formatData[] = array("EEE, MMM d, ''yy", $dateTime, "Thu, Jan 1, '70");
242 $formatData[] = array('h:mm a', $dateTime, '12:00 AM');
243 $formatData[] = array('yyyyy.MMMM.dd hh:mm aaa', $dateTime, '01970.January.01 12:00 AM');
244
245 $formatData[] = array("yyyy.MM.dd 'at' HH:mm:ss zzz", $dateTime, '1970.01.01 at 00:00:00 GMT');
246 $formatData[] = array('K:mm a, z', $dateTime, '0:00 AM, GMT');
247 }
248
249 return $formatData;
250 }
251
252 /**
253 * @dataProvider formatErrorProvider
254 */
255 public function testFormatIllegalArgumentError($pattern, $timestamp, $errorMessage)
256 {
257 $errorCode = IntlGlobals::U_ILLEGAL_ARGUMENT_ERROR;
258
259 $formatter = $this->getDefaultDateFormatter($pattern);
260 $this->assertFalse($formatter->format($timestamp));
261 $this->assertIsIntlFailure($formatter, $errorMessage, $errorCode);
262 }
263
264 public function formatErrorProvider()
265 {
266 // With PHP 5.5 IntlDateFormatter accepts empty values ('0')
267 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
268 return array(
269 array('y-M-d', 'foobar', 'datefmt_format: string \'foobar\' is not numeric, which would be required for it to be a valid date: U_ILLEGAL_ARGUMENT_ERROR')
270 );
271 }
272
273 $message = 'datefmt_format: takes either an array or an integer timestamp value : U_ILLEGAL_ARGUMENT_ERROR';
274
275 if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
276 $message = 'datefmt_format: takes either an array or an integer timestamp value or a DateTime object: U_ILLEGAL_ARGUMENT_ERROR';
277 }
278
279 return array(
280 array('y-M-d', '0', $message),
281 array('y-M-d', 'foobar', $message),
282 );
283 }
284
285 /**
286 * @dataProvider formatWithTimezoneProvider
287 */
288 public function testFormatWithTimezone($timestamp, $timezone, $expected)
289 {
290 $pattern = 'yyyy-MM-dd HH:mm:ss';
291 $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, $timezone, IntlDateFormatter::GREGORIAN, $pattern);
292 $this->assertSame($expected, $formatter->format($timestamp));
293 }
294
295 public function formatWithTimezoneProvider()
296 {
297 $data = array(
298 array(0, 'UTC', '1970-01-01 00:00:00'),
299 array(0, 'GMT', '1970-01-01 00:00:00'),
300 array(0, 'GMT-03:00', '1969-12-31 21:00:00'),
301 array(0, 'GMT+03:00', '1970-01-01 03:00:00'),
302 array(0, 'Europe/Zurich', '1970-01-01 01:00:00'),
303 array(0, 'Europe/Paris', '1970-01-01 01:00:00'),
304 array(0, 'Africa/Cairo', '1970-01-01 02:00:00'),
305 array(0, 'Africa/Casablanca', '1970-01-01 00:00:00'),
306 array(0, 'Africa/Djibouti', '1970-01-01 03:00:00'),
307 array(0, 'Africa/Johannesburg', '1970-01-01 02:00:00'),
308 array(0, 'America/Antigua', '1969-12-31 20:00:00'),
309 array(0, 'America/Toronto', '1969-12-31 19:00:00'),
310 array(0, 'America/Vancouver', '1969-12-31 16:00:00'),
311 array(0, 'Asia/Aqtau', '1970-01-01 05:00:00'),
312 array(0, 'Asia/Bangkok', '1970-01-01 07:00:00'),
313 array(0, 'Asia/Dubai', '1970-01-01 04:00:00'),
314 array(0, 'Australia/Brisbane', '1970-01-01 10:00:00'),
315 array(0, 'Australia/Eucla', '1970-01-01 08:45:00'),
316 array(0, 'Australia/Melbourne', '1970-01-01 10:00:00'),
317 array(0, 'Europe/Berlin', '1970-01-01 01:00:00'),
318 array(0, 'Europe/Dublin', '1970-01-01 01:00:00'),
319 array(0, 'Europe/Warsaw', '1970-01-01 01:00:00'),
320 array(0, 'Pacific/Fiji', '1970-01-01 12:00:00'),
321 );
322
323 // As of PHP 5.5, intl ext no longer fallbacks invalid time zones to UTC
324 if (!version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
325 // When time zone not exists, uses UTC by default
326 $data[] = array(0, 'Foo/Bar', '1970-01-01 00:00:00');
327 $data[] = array(0, 'UTC+04:30', '1970-01-01 00:00:00');
328 $data[] = array(0, 'UTC+04:AA', '1970-01-01 00:00:00');
329 }
330
331 return $data;
332 }
333
334 public function testFormatWithGmtTimezone()
335 {
336 $formatter = $this->getDefaultDateFormatter('zzzz');
337
338 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
339 $formatter->setTimeZone('GMT+03:00');
340 } else {
341 $formatter->setTimeZoneId('GMT+03:00');
342 }
343
344 $this->assertEquals('GMT+03:00', $formatter->format(0));
345 }
346
347 public function testFormatWithGmtTimeZoneAndMinutesOffset()
348 {
349 $formatter = $this->getDefaultDateFormatter('zzzz');
350
351 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
352 $formatter->setTimeZone('GMT+00:30');
353 } else {
354 $formatter->setTimeZoneId('GMT+00:30');
355 }
356
357 $this->assertEquals('GMT+00:30', $formatter->format(0));
358 }
359
360 public function testFormatWithNonStandardTimezone()
361 {
362 $formatter = $this->getDefaultDateFormatter('zzzz');
363
364 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
365 $formatter->setTimeZone('Pacific/Fiji');
366 } else {
367 $formatter->setTimeZoneId('Pacific/Fiji');
368 }
369
370 $this->assertEquals('Fiji Standard Time', $formatter->format(0));
371 }
372
373 public function testFormatWithConstructorTimezone()
374 {
375 $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC');
376 $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
377
378 $this->assertEquals(
379 $this->getDateTime(0)->format('Y-m-d H:i:s'),
380 $formatter->format(0)
381 );
382 }
383
384 public function testFormatWithTimezoneFromEnvironmentVariable()
385 {
386 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
387 $this->markTestSkipped('IntlDateFormatter in PHP 5.5 no longer depends on TZ environment.');
388 }
389
390 $tz = getenv('TZ');
391 putenv('TZ=Europe/London');
392
393 $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
394 $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
395
396 $this->assertEquals(
397 $this->getDateTime(0)->format('Y-m-d H:i:s'),
398 $formatter->format(0)
399 );
400
401 $this->assertEquals('Europe/London', getenv('TZ'));
402
403 // Restores TZ.
404 putenv('TZ='.$tz);
405 }
406
407 public function testFormatWithTimezoneFromPhp()
408 {
409 if (!version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
410 $this->markTestSkipped('Only in PHP 5.5 IntlDateFormatter depends on default timezone (`date_default_timezone_get()`).');
411 }
412
413 $tz = date_default_timezone_get();
414 date_default_timezone_set('Europe/London');
415
416 $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
417 $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
418
419 $this->assertEquals(
420 $this->getDateTime(0)->format('Y-m-d H:i:s'),
421 $formatter->format(0)
422 );
423
424 $this->assertEquals('Europe/London', date_default_timezone_get());
425
426 // Restores TZ.
427 date_default_timezone_set($tz);
428 }
429
430 /**
431 * @dataProvider dateAndTimeTypeProvider
432 */
433 public function testDateAndTimeType($timestamp, $datetype, $timetype, $expected)
434 {
435 $formatter = $this->getDateFormatter('en', $datetype, $timetype, 'UTC');
436 $this->assertSame($expected, $formatter->format($timestamp));
437 }
438
439 public function dateAndTimeTypeProvider()
440 {
441 return array(
442 array(0, IntlDateFormatter::FULL, IntlDateFormatter::NONE, 'Thursday, January 1, 1970'),
443 array(0, IntlDateFormatter::LONG, IntlDateFormatter::NONE, 'January 1, 1970'),
444 array(0, IntlDateFormatter::MEDIUM, IntlDateFormatter::NONE, 'Jan 1, 1970'),
445 array(0, IntlDateFormatter::SHORT, IntlDateFormatter::NONE, '1/1/70'),
446 array(0, IntlDateFormatter::NONE, IntlDateFormatter::FULL, '12:00:00 AM GMT'),
447 array(0, IntlDateFormatter::NONE, IntlDateFormatter::LONG, '12:00:00 AM GMT'),
448 array(0, IntlDateFormatter::NONE, IntlDateFormatter::MEDIUM, '12:00:00 AM'),
449 array(0, IntlDateFormatter::NONE, IntlDateFormatter::SHORT, '12:00 AM'),
450 );
451 }
452
453 public function testGetCalendar()
454 {
455 $formatter = $this->getDefaultDateFormatter();
456 $this->assertEquals(IntlDateFormatter::GREGORIAN, $formatter->getCalendar());
457 }
458
459 public function testGetDateType()
460 {
461 $formatter = $this->getDateFormatter('en', IntlDateFormatter::FULL, IntlDateFormatter::NONE);
462 $this->assertEquals(IntlDateFormatter::FULL, $formatter->getDateType());
463 }
464
465 public function testGetLocale()
466 {
467 $formatter = $this->getDefaultDateFormatter();
468 $this->assertEquals('en', $formatter->getLocale());
469 }
470
471 public function testGetPattern()
472 {
473 $formatter = $this->getDateFormatter('en', IntlDateFormatter::FULL, IntlDateFormatter::NONE, 'UTC', IntlDateFormatter::GREGORIAN, 'yyyy-MM-dd');
474 $this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
475 }
476
477 public function testGetTimeType()
478 {
479 $formatter = $this->getDateFormatter('en', IntlDateFormatter::NONE, IntlDateFormatter::FULL);
480 $this->assertEquals(IntlDateFormatter::FULL, $formatter->getTimeType());
481 }
482
483 /**
484 * @dataProvider parseProvider
485 */
486 public function testParse($pattern, $value, $expected)
487 {
488 $errorCode = IntlGlobals::U_ZERO_ERROR;
489 $errorMessage = 'U_ZERO_ERROR';
490
491 $formatter = $this->getDefaultDateFormatter($pattern);
492 $this->assertSame($expected, $formatter->parse($value));
493 $this->assertIsIntlSuccess($formatter, $errorMessage, $errorCode);
494 }
495
496 public function parseProvider()
497 {
498 return array_merge(
499 $this->parseYearProvider(),
500 $this->parseQuarterProvider(),
501 $this->parseMonthProvider(),
502 $this->parseStandaloneMonthProvider(),
503 $this->parseDayProvider(),
504 $this->parseDayOfWeekProvider(),
505 $this->parseDayOfYearProvider(),
506 $this->parseHour12ClockOneBasedProvider(),
507 $this->parseHour12ClockZeroBasedProvider(),
508 $this->parseHour24ClockOneBasedProvider(),
509 $this->parseHour24ClockZeroBasedProvider(),
510 $this->parseMinuteProvider(),
511 $this->parseSecondProvider(),
512 $this->parseTimezoneProvider(),
513 $this->parseAmPmProvider(),
514 $this->parseStandaloneAmPmProvider(),
515 $this->parseRegexMetaCharsProvider(),
516 $this->parseQuoteCharsProvider(),
517 $this->parseDashSlashProvider()
518 );
519 }
520
521 public function parseYearProvider()
522 {
523 return array(
524 array('y-M-d', '1970-1-1', 0),
525 array('yy-M-d', '70-1-1', 0),
526 );
527 }
528
529 public function parseQuarterProvider()
530 {
531 return array(
532 array('Q', '1', 0),
533 array('QQ', '01', 0),
534 array('QQQ', 'Q1', 0),
535 array('QQQQ', '1st quarter', 0),
536 array('QQQQQ', '1st quarter', 0),
537
538 array('Q', '2', 7776000),
539 array('QQ', '02', 7776000),
540 array('QQQ', 'Q2', 7776000),
541 array('QQQQ', '2nd quarter', 7776000),
542 array('QQQQQ', '2nd quarter', 7776000),
543
544 array('q', '1', 0),
545 array('qq', '01', 0),
546 array('qqq', 'Q1', 0),
547 array('qqqq', '1st quarter', 0),
548 array('qqqqq', '1st quarter', 0),
549 );
550 }
551
552 public function parseMonthProvider()
553 {
554 return array(
555 array('y-M-d', '1970-1-1', 0),
556 array('y-MMM-d', '1970-Jan-1', 0),
557 array('y-MMMM-d', '1970-January-1', 0),
558 );
559 }
560
561 public function parseStandaloneMonthProvider()
562 {
563 return array(
564 array('y-L-d', '1970-1-1', 0),
565 array('y-LLL-d', '1970-Jan-1', 0),
566 array('y-LLLL-d', '1970-January-1', 0),
567 );
568 }
569
570 public function parseDayProvider()
571 {
572 return array(
573 array('y-M-d', '1970-1-1', 0),
574 array('y-M-dd', '1970-1-01', 0),
575 array('y-M-ddd', '1970-1-001', 0),
576 );
577 }
578
579 public function parseDayOfWeekProvider()
580 {
581 return array(
582 array('E', 'Thu', 0),
583 array('EE', 'Thu', 0),
584 array('EEE', 'Thu', 0),
585 array('EEEE', 'Thursday', 0),
586 array('EEEEE', 'T', 432000),
587 array('EEEEEE', 'Thu', 0),
588 );
589 }
590
591 public function parseDayOfYearProvider()
592 {
593 return array(
594 array('D', '1', 0),
595 array('D', '2', 86400),
596 );
597 }
598
599 public function parseHour12ClockOneBasedProvider()
600 {
601 return array(
602 // 12 hours (1-12)
603 array('y-M-d h', '1970-1-1 1', 3600),
604 array('y-M-d h', '1970-1-1 10', 36000),
605 array('y-M-d hh', '1970-1-1 11', 39600),
606 array('y-M-d hh', '1970-1-1 12', 0),
607 array('y-M-d hh a', '1970-1-1 0 AM', 0),
608 array('y-M-d hh a', '1970-1-1 1 AM', 3600),
609 array('y-M-d hh a', '1970-1-1 10 AM', 36000),
610 array('y-M-d hh a', '1970-1-1 11 AM', 39600),
611 array('y-M-d hh a', '1970-1-1 12 AM', 0),
612 array('y-M-d hh a', '1970-1-1 23 AM', 82800),
613 array('y-M-d hh a', '1970-1-1 24 AM', 86400),
614 array('y-M-d hh a', '1970-1-1 0 PM', 43200),
615 array('y-M-d hh a', '1970-1-1 1 PM', 46800),
616 array('y-M-d hh a', '1970-1-1 10 PM', 79200),
617 array('y-M-d hh a', '1970-1-1 11 PM', 82800),
618 array('y-M-d hh a', '1970-1-1 12 PM', 43200),
619 array('y-M-d hh a', '1970-1-1 23 PM', 126000),
620 array('y-M-d hh a', '1970-1-1 24 PM', 129600),
621 );
622 }
623
624 public function parseHour12ClockZeroBasedProvider()
625 {
626 return array(
627 // 12 hours (0-11)
628 array('y-M-d K', '1970-1-1 1', 3600),
629 array('y-M-d K', '1970-1-1 10', 36000),
630 array('y-M-d KK', '1970-1-1 11', 39600),
631 array('y-M-d KK', '1970-1-1 12', 43200),
632 array('y-M-d KK a', '1970-1-1 0 AM', 0),
633 array('y-M-d KK a', '1970-1-1 1 AM', 3600),
634 array('y-M-d KK a', '1970-1-1 10 AM', 36000),
635 array('y-M-d KK a', '1970-1-1 11 AM', 39600),
636 array('y-M-d KK a', '1970-1-1 12 AM', 43200),
637 array('y-M-d KK a', '1970-1-1 23 AM', 82800),
638 array('y-M-d KK a', '1970-1-1 24 AM', 86400),
639 array('y-M-d KK a', '1970-1-1 0 PM', 43200),
640 array('y-M-d KK a', '1970-1-1 1 PM', 46800),
641 array('y-M-d KK a', '1970-1-1 10 PM', 79200),
642 array('y-M-d KK a', '1970-1-1 11 PM', 82800),
643 array('y-M-d KK a', '1970-1-1 12 PM', 86400),
644 array('y-M-d KK a', '1970-1-1 23 PM', 126000),
645 array('y-M-d KK a', '1970-1-1 24 PM', 129600),
646 );
647 }
648
649 public function parseHour24ClockOneBasedProvider()
650 {
651 return array(
652 // 24 hours (1-24)
653 array('y-M-d k', '1970-1-1 1', 3600),
654 array('y-M-d k', '1970-1-1 10', 36000),
655 array('y-M-d kk', '1970-1-1 11', 39600),
656 array('y-M-d kk', '1970-1-1 12', 43200),
657 array('y-M-d kk', '1970-1-1 23', 82800),
658 array('y-M-d kk', '1970-1-1 24', 0),
659 array('y-M-d kk a', '1970-1-1 0 AM', 0),
660 array('y-M-d kk a', '1970-1-1 1 AM', 0),
661 array('y-M-d kk a', '1970-1-1 10 AM', 0),
662 array('y-M-d kk a', '1970-1-1 11 AM', 0),
663 array('y-M-d kk a', '1970-1-1 12 AM', 0),
664 array('y-M-d kk a', '1970-1-1 23 AM', 0),
665 array('y-M-d kk a', '1970-1-1 24 AM', 0),
666 array('y-M-d kk a', '1970-1-1 0 PM', 43200),
667 array('y-M-d kk a', '1970-1-1 1 PM', 43200),
668 array('y-M-d kk a', '1970-1-1 10 PM', 43200),
669 array('y-M-d kk a', '1970-1-1 11 PM', 43200),
670 array('y-M-d kk a', '1970-1-1 12 PM', 43200),
671 array('y-M-d kk a', '1970-1-1 23 PM', 43200),
672 array('y-M-d kk a', '1970-1-1 24 PM', 43200),
673 );
674 }
675
676 public function parseHour24ClockZeroBasedProvider()
677 {
678 return array(
679 // 24 hours (0-23)
680 array('y-M-d H', '1970-1-1 0', 0),
681 array('y-M-d H', '1970-1-1 1', 3600),
682 array('y-M-d H', '1970-1-1 10', 36000),
683 array('y-M-d HH', '1970-1-1 11', 39600),
684 array('y-M-d HH', '1970-1-1 12', 43200),
685 array('y-M-d HH', '1970-1-1 23', 82800),
686 array('y-M-d HH a', '1970-1-1 0 AM', 0),
687 array('y-M-d HH a', '1970-1-1 1 AM', 0),
688 array('y-M-d HH a', '1970-1-1 10 AM', 0),
689 array('y-M-d HH a', '1970-1-1 11 AM', 0),
690 array('y-M-d HH a', '1970-1-1 12 AM', 0),
691 array('y-M-d HH a', '1970-1-1 23 AM', 0),
692 array('y-M-d HH a', '1970-1-1 24 AM', 0),
693 array('y-M-d HH a', '1970-1-1 0 PM', 43200),
694 array('y-M-d HH a', '1970-1-1 1 PM', 43200),
695 array('y-M-d HH a', '1970-1-1 10 PM', 43200),
696 array('y-M-d HH a', '1970-1-1 11 PM', 43200),
697 array('y-M-d HH a', '1970-1-1 12 PM', 43200),
698 array('y-M-d HH a', '1970-1-1 23 PM', 43200),
699 array('y-M-d HH a', '1970-1-1 24 PM', 43200),
700 );
701 }
702
703 public function parseMinuteProvider()
704 {
705 return array(
706 array('y-M-d HH:m', '1970-1-1 0:1', 60),
707 array('y-M-d HH:mm', '1970-1-1 0:10', 600),
708 );
709 }
710
711 public function parseSecondProvider()
712 {
713 return array(
714 array('y-M-d HH:mm:s', '1970-1-1 00:01:1', 61),
715 array('y-M-d HH:mm:ss', '1970-1-1 00:01:10', 70),
716 );
717 }
718
719 public function parseTimezoneProvider()
720 {
721 return array(
722 array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-03:00', 10800),
723 array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-04:00', 14400),
724 array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-00:00', 0),
725 array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+03:00', -10800),
726 array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+04:00', -14400),
727 array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-0300', 10800),
728 array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+0300', -10800),
729
730 // a previous timezone parsing should not change the timezone for the next parsing
731 array('y-M-d HH:mm:ss', '1970-1-1 00:00:00', 0),
732 );
733 }
734
735 public function parseAmPmProvider()
736 {
737 return array(
738 // AM/PM (already covered by hours tests)
739 array('y-M-d HH:mm:ss a', '1970-1-1 00:00:00 AM', 0),
740 array('y-M-d HH:mm:ss a', '1970-1-1 00:00:00 PM', 43200),
741 );
742 }
743
744 public function parseStandaloneAmPmProvider()
745 {
746 return array(
747 array('a', 'AM', 0),
748 array('a', 'PM', 43200),
749 );
750 }
751
752 public function parseRegexMetaCharsProvider()
753 {
754 return array(
755 // regexp meta chars in the pattern string
756 array('y[M-d', '1970[1-1', 0),
757 array('y[M/d', '1970[1/1', 0),
758 );
759 }
760
761 public function parseQuoteCharsProvider()
762 {
763 return array(
764 array("'M'", 'M', 0),
765 array("'yy'", 'yy', 0),
766 array("'''yy'", "'yy", 0),
767 array("''y", "'1970", 0),
768 array("H 'o'' clock'", "0 o' clock", 0),
769 );
770 }
771
772 public function parseDashSlashProvider()
773 {
774 return array(
775 array('y-M-d', '1970/1/1', 0),
776 array('yy-M-d', '70/1/1', 0),
777 array('y/M/d', '1970-1-1', 0),
778 array('yy/M/d', '70-1-1', 0),
779 );
780 }
781
782 /**
783 * @dataProvider parseErrorProvider
784 */
785 public function testParseError($pattern, $value)
786 {
787 $errorCode = IntlGlobals::U_PARSE_ERROR;
788 $errorMessage = 'Date parsing failed: U_PARSE_ERROR';
789
790 $formatter = $this->getDefaultDateFormatter($pattern);
791 $this->assertFalse($formatter->parse($value));
792 $this->assertIsIntlFailure($formatter, $errorMessage, $errorCode);
793 }
794
795 public function parseErrorProvider()
796 {
797 return array(
798 // 1 char month
799 array('y-MMMMM-d', '1970-J-1'),
800 array('y-MMMMM-d', '1970-S-1'),
801
802 // standalone 1 char month
803 array('y-LLLLL-d', '1970-J-1'),
804 array('y-LLLLL-d', '1970-S-1'),
805 );
806 }
807
808 /*
809 * https://github.com/symfony/symfony/issues/4242
810 */
811 public function testParseAfterError()
812 {
813 $this->testParseError('y-MMMMM-d', '1970-J-1');
814 $this->testParse('y-M-d', '1970-1-1', 0);
815 }
816
817 public function testParseWithNullPositionValue()
818 {
819 $position = null;
820 $formatter = $this->getDefaultDateFormatter('y');
821 $this->assertSame(0, $formatter->parse('1970', $position));
822 $this->assertNull($position);
823 }
824
825 public function testSetPattern()
826 {
827 $formatter = $this->getDefaultDateFormatter();
828 $formatter->setPattern('yyyy-MM-dd');
829 $this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
830 }
831
832 /**
833 * @covers Symfony\Component\Intl\DateFormatter\IntlDateFormatter::getTimeZoneId
834 * @dataProvider setTimeZoneIdProvider
835 */
836 public function testSetTimeZoneId($timeZoneId, $expectedTimeZoneId)
837 {
838 $formatter = $this->getDefaultDateFormatter();
839
840 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
841 $formatter->setTimeZone($timeZoneId);
842 } else {
843 $formatter->setTimeZoneId($timeZoneId);
844 }
845
846 $this->assertEquals($expectedTimeZoneId, $formatter->getTimeZoneId());
847 }
848
849 public function setTimeZoneIdProvider()
850 {
851 return array(
852 array('UTC', 'UTC'),
853 array('GMT', 'GMT'),
854 array('GMT-03:00', 'GMT-03:00'),
855 array('Europe/Zurich', 'Europe/Zurich'),
856 array('GMT-0300', 'GMT-0300'),
857 array('Foo/Bar', 'Foo/Bar'),
858 array('GMT+00:AA', 'GMT+00:AA'),
859 array('GMT+00AA', 'GMT+00AA'),
860 );
861 }
862
863 protected function getDefaultDateFormatter($pattern = null)
864 {
865 return $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN, $pattern);
866 }
867
868 protected function getDateTime($timestamp = null)
869 {
870 if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
871 $timeZone = date_default_timezone_get();
872 } else {
873 $timeZone = getenv('TZ') ?: 'UTC';
874 }
875
876 $dateTime = new \DateTime();
877 $dateTime->setTimestamp(null === $timestamp ? time() : $timestamp);
878 $dateTime->setTimeZone(new \DateTimeZone($timeZone));
879
880 return $dateTime;
881 }
882
883 protected function assertIsIntlFailure($formatter, $errorMessage, $errorCode)
884 {
885 $this->assertSame($errorMessage, $this->getIntlErrorMessage());
886 $this->assertSame($errorCode, $this->getIntlErrorCode());
887 $this->assertTrue($this->isIntlFailure($this->getIntlErrorCode()));
888 $this->assertSame($errorMessage, $formatter->getErrorMessage());
889 $this->assertSame($errorCode, $formatter->getErrorCode());
890 $this->assertTrue($this->isIntlFailure($formatter->getErrorCode()));
891 }
892
893 protected function assertIsIntlSuccess($formatter, $errorMessage, $errorCode)
894 {
895 /* @var IntlDateFormatter $formatter */
896 $this->assertSame($errorMessage, $this->getIntlErrorMessage());
897 $this->assertSame($errorCode, $this->getIntlErrorCode());
898 $this->assertFalse($this->isIntlFailure($this->getIntlErrorCode()));
899 $this->assertSame($errorMessage, $formatter->getErrorMessage());
900 $this->assertSame($errorCode, $formatter->getErrorCode());
901 $this->assertFalse($this->isIntlFailure($formatter->getErrorCode()));
902 }
903
904 /**
905 * @param $locale
906 * @param $datetype
907 * @param $timetype
908 * @param null $timezone
909 * @param int $calendar
910 * @param null $pattern
911 *
912 * @return mixed
913 */
914 abstract protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = IntlDateFormatter::GREGORIAN, $pattern = null);
915
916 /**
917 * @return string
918 */
919 abstract protected function getIntlErrorMessage();
920
921 /**
922 * @return integer
923 */
924 abstract protected function getIntlErrorCode();
925
926 /**
927 * @param integer $errorCode
928 *
929 * @return Boolean
930 */
931 abstract protected function isIntlFailure($errorCode);
932}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php
new file mode 100644
index 00000000..d7227aeb
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php
@@ -0,0 +1,220 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\DateFormatter;
13
14use Symfony\Component\Intl\DateFormatter\IntlDateFormatter;
15use Symfony\Component\Intl\Globals\IntlGlobals;
16
17class IntlDateFormatterTest extends AbstractIntlDateFormatterTest
18{
19 public function testConstructor()
20 {
21 $formatter = new IntlDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN, 'y-M-d');
22 $this->assertEquals('y-M-d', $formatter->getPattern());
23 }
24
25 /**
26 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
27 */
28 public function testConstructorWithUnsupportedLocale()
29 {
30 new IntlDateFormatter('pt_BR', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
31 }
32
33 public function testStaticCreate()
34 {
35 $formatter = IntlDateFormatter::create('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
36 $this->assertInstanceOf('\Symfony\Component\Intl\DateFormatter\IntlDateFormatter', $formatter);
37 }
38
39 public function testFormatWithUnsupportedTimestampArgument()
40 {
41 $formatter = $this->getDefaultDateFormatter();
42
43 $localtime = array(
44 'tm_sec' => 59,
45 'tm_min' => 3,
46 'tm_hour' => 15,
47 'tm_mday' => 15,
48 'tm_mon' => 3,
49 'tm_year' => 112,
50 'tm_wday' => 0,
51 'tm_yday' => 105,
52 'tm_isdst' => 0
53 );
54
55 try {
56 $formatter->format($localtime);
57 } catch (\Exception $e) {
58 $this->assertInstanceOf('Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException', $e);
59
60 if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
61 $this->assertStringEndsWith('Only integer unix timestamps and DateTime objects are supported. Please install the "intl" extension for full localization capabilities.', $e->getMessage());
62 } else {
63 $this->assertStringEndsWith('Only integer unix timestamps are supported. Please install the "intl" extension for full localization capabilities.', $e->getMessage());
64 }
65 }
66 }
67
68 /**
69 * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
70 */
71 public function testFormatWithUnimplementedChars()
72 {
73 $pattern = 'Y';
74 $formatter = new IntlDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN, $pattern);
75 $formatter->format(0);
76 }
77
78 /**
79 * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
80 */
81 public function testFormatWithNonIntegerTimestamp()
82 {
83 $formatter = $this->getDefaultDateFormatter();
84 $formatter->format(array());
85 }
86
87 public function testGetErrorCode()
88 {
89 $formatter = $this->getDefaultDateFormatter();
90 $this->assertEquals(IntlGlobals::getErrorCode(), $formatter->getErrorCode());
91 }
92
93 public function testGetErrorMessage()
94 {
95 $formatter = $this->getDefaultDateFormatter();
96 $this->assertEquals(IntlGlobals::getErrorMessage(), $formatter->getErrorMessage());
97 }
98
99 public function testIsLenient()
100 {
101 $formatter = $this->getDefaultDateFormatter();
102 $this->assertFalse($formatter->isLenient());
103 }
104
105 /**
106 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
107 */
108 public function testLocaltime()
109 {
110 $formatter = $this->getDefaultDateFormatter();
111 $formatter->localtime('Wednesday, December 31, 1969 4:00:00 PM PT');
112 }
113
114 /**
115 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException
116 */
117 public function testParseWithNotNullPositionValue()
118 {
119 $position = 0;
120 $formatter = $this->getDefaultDateFormatter('y');
121 $this->assertSame(0, $formatter->parse('1970', $position));
122 }
123
124 /**
125 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
126 */
127 public function testSetCalendar()
128 {
129 $formatter = $this->getDefaultDateFormatter();
130 $formatter->setCalendar(IntlDateFormatter::GREGORIAN);
131 }
132
133 /**
134 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
135 */
136 public function testSetLenient()
137 {
138 $formatter = $this->getDefaultDateFormatter();
139 $formatter->setLenient(true);
140 }
141
142 /**
143 * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
144 */
145 public function testFormatWithGmtTimeZoneAndMinutesOffset()
146 {
147 parent::testFormatWithGmtTimeZoneAndMinutesOffset();
148 }
149
150 /**
151 * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
152 */
153 public function testFormatWithNonStandardTimezone()
154 {
155 parent::testFormatWithNonStandardTimezone();
156 }
157
158 public function parseStandaloneAmPmProvider()
159 {
160 return $this->notImplemented(parent::parseStandaloneAmPmProvider());
161 }
162
163 public function parseDayOfWeekProvider()
164 {
165 return $this->notImplemented(parent::parseDayOfWeekProvider());
166 }
167
168 public function parseDayOfYearProvider()
169 {
170 return $this->notImplemented(parent::parseDayOfYearProvider());
171 }
172
173 public function parseQuarterProvider()
174 {
175 return $this->notImplemented(parent::parseQuarterProvider());
176 }
177
178 protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = IntlDateFormatter::GREGORIAN, $pattern = null)
179 {
180 return new IntlDateFormatter($locale, $datetype, $timetype, $timezone, $calendar, $pattern);
181 }
182
183 protected function getIntlErrorMessage()
184 {
185 return IntlGlobals::getErrorMessage();
186 }
187
188 protected function getIntlErrorCode()
189 {
190 return IntlGlobals::getErrorCode();
191 }
192
193 protected function isIntlFailure($errorCode)
194 {
195 return IntlGlobals::isFailure($errorCode);
196 }
197
198 /**
199 * Just to document the differences between the stub and the intl
200 * implementations. The intl can parse any of the tested formats alone. The
201 * stub does not implement them as it would be needed to add more
202 * abstraction, passing more context to the transformers objects. Any of the
203 * formats are ignored alone or with date/time data (years, months, days,
204 * hours, minutes and seconds).
205 *
206 * Also in intl, format like 'ss E' for '10 2' (2nd day of year
207 * + 10 seconds) are added, then we have 86,400 seconds (24h * 60min * 60s)
208 * + 10 seconds
209 *
210 * @param array $dataSets
211 *
212 * @return array
213 */
214 private function notImplemented(array $dataSets)
215 {
216 return array_map(function ($row) {
217 return array($row[0], $row[1], 0);
218 }, $dataSets);
219 }
220}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/Verification/IntlDateFormatterTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/Verification/IntlDateFormatterTest.php
new file mode 100644
index 00000000..7fbf854f
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/DateFormatter/Verification/IntlDateFormatterTest.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\DateFormatter\Verification;
13
14use Symfony\Component\Intl\DateFormatter\IntlDateFormatter;
15use Symfony\Component\Intl\Tests\DateFormatter\AbstractIntlDateFormatterTest;
16use Symfony\Component\Intl\Util\IntlTestHelper;
17
18/**
19 * Verifies that {@link AbstractIntlDateFormatterTest} matches the behavior of
20 * the {@link \IntlDateFormatter} class in a specific version of ICU.
21 *
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class IntlDateFormatterTest extends AbstractIntlDateFormatterTest
25{
26 protected function setUp()
27 {
28 IntlTestHelper::requireFullIntl($this);
29
30 parent::setUp();
31 }
32
33 /**
34 * It seems IntlDateFormatter caches the timezone id when not explicitly set via constructor or by the
35 * setTimeZoneId() method. Since testFormatWithDefaultTimezoneIntl() runs using the default environment
36 * time zone, this test would use it too if not running in a separated process.
37 *
38 * @runInSeparateProcess
39 */
40 public function testFormatWithTimezoneFromEnvironmentVariable()
41 {
42 parent::testFormatWithTimezoneFromEnvironmentVariable();
43 }
44
45 protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = IntlDateFormatter::GREGORIAN, $pattern = null)
46 {
47 return new \IntlDateFormatter($locale, $datetype, $timetype, $timezone, $calendar, $pattern);
48 }
49
50 protected function getIntlErrorMessage()
51 {
52 return intl_get_error_message();
53 }
54
55 protected function getIntlErrorCode()
56 {
57 return intl_get_error_code();
58 }
59
60 protected function isIntlFailure($errorCode)
61 {
62 return intl_is_failure($errorCode);
63 }
64}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/AbstractIntlGlobalsTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/AbstractIntlGlobalsTest.php
new file mode 100644
index 00000000..0a937d5e
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/AbstractIntlGlobalsTest.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Globals;
13
14/**
15 * Test case for intl function implementations.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19abstract class AbstractIntlGlobalsTest extends \PHPUnit_Framework_TestCase
20{
21 public function errorNameProvider()
22 {
23 return array (
24 array(-129, '[BOGUS UErrorCode]'),
25 array(0, 'U_ZERO_ERROR'),
26 array(1, 'U_ILLEGAL_ARGUMENT_ERROR'),
27 array(9, 'U_PARSE_ERROR'),
28 array(129, '[BOGUS UErrorCode]'),
29 );
30 }
31
32 /**
33 * @dataProvider errorNameProvider
34 */
35 public function testGetErrorName($errorCode, $errorName)
36 {
37 $this->assertSame($errorName, $this->getIntlErrorName($errorCode));
38 }
39
40 abstract protected function getIntlErrorName($errorCode);
41}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/IntlGlobalsTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/IntlGlobalsTest.php
new file mode 100644
index 00000000..34e3a6a3
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/IntlGlobalsTest.php
@@ -0,0 +1,22 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Globals;
13
14use Symfony\Component\Intl\Globals\IntlGlobals;
15
16class IntlGlobalsTest extends AbstractIntlGlobalsTest
17{
18 protected function getIntlErrorName($errorCode)
19 {
20 return IntlGlobals::getErrorName($errorCode);
21 }
22}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/Verification/IntlGlobalsTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/Verification/IntlGlobalsTest.php
new file mode 100644
index 00000000..c46033d8
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Globals/Verification/IntlGlobalsTest.php
@@ -0,0 +1,36 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Globals\Verification;
13
14use Symfony\Component\Intl\Tests\Globals\AbstractIntlGlobalsTest;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17/**
18 * Verifies that {@link AbstractIntlGlobalsTest} matches the behavior of the
19 * intl functions with a specific version of ICU.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class IntlGlobalsTest extends AbstractIntlGlobalsTest
24{
25 protected function setUp()
26 {
27 IntlTestHelper::requireFullIntl($this);
28
29 parent::setUp();
30 }
31
32 protected function getIntlErrorName($errorCode)
33 {
34 return intl_error_name($errorCode);
35 }
36}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/AbstractLocaleTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/AbstractLocaleTest.php
new file mode 100644
index 00000000..08569fad
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/AbstractLocaleTest.php
@@ -0,0 +1,29 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Locale;
13
14/**
15 * Test case for Locale implementations.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19abstract class AbstractLocaleTest extends \PHPUnit_Framework_TestCase
20{
21 public function testSetDefault()
22 {
23 $this->call('setDefault', 'en_GB');
24
25 $this->assertSame('en_GB', $this->call('getDefault'));
26 }
27
28 abstract protected function call($methodName);
29}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/LocaleTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/LocaleTest.php
new file mode 100644
index 00000000..7e957187
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/LocaleTest.php
@@ -0,0 +1,159 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Locale;
13
14class LocaleTest extends AbstractLocaleTest
15{
16 /**
17 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
18 */
19 public function testAcceptFromHttp()
20 {
21 $this->call('acceptFromHttp', 'pt-br,en-us;q=0.7,en;q=0.5');
22 }
23
24 /**
25 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
26 */
27 public function testComposeLocale()
28 {
29 $subtags = array(
30 'language' => 'pt',
31 'script' => 'Latn',
32 'region' => 'BR'
33 );
34 $this->call('composeLocale', $subtags);
35 }
36
37 /**
38 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
39 */
40 public function testFilterMatches()
41 {
42 $this->call('filterMatches', 'pt-BR', 'pt-BR');
43 }
44
45 /**
46 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
47 */
48 public function testGetAllVariants()
49 {
50 $this->call('getAllVariants', 'pt_BR_Latn');
51 }
52
53 /**
54 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
55 */
56 public function testGetDisplayLanguage()
57 {
58 $this->call('getDisplayLanguage', 'pt-Latn-BR', 'en');
59 }
60
61 /**
62 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
63 */
64 public function testGetDisplayName()
65 {
66 $this->call('getDisplayName', 'pt-Latn-BR', 'en');
67 }
68
69 /**
70 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
71 */
72 public function testGetDisplayRegion()
73 {
74 $this->call('getDisplayRegion', 'pt-Latn-BR', 'en');
75 }
76
77 /**
78 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
79 */
80 public function testGetDisplayScript()
81 {
82 $this->call('getDisplayScript', 'pt-Latn-BR', 'en');
83 }
84
85 /**
86 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
87 */
88 public function testGetDisplayVariant()
89 {
90 $this->call('getDisplayVariant', 'pt-Latn-BR', 'en');
91 }
92
93 /**
94 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
95 */
96 public function testGetKeywords()
97 {
98 $this->call('getKeywords', 'pt-BR@currency=BRL');
99 }
100
101 /**
102 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
103 */
104 public function testGetPrimaryLanguage()
105 {
106 $this->call('getPrimaryLanguage', 'pt-Latn-BR');
107 }
108
109 /**
110 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
111 */
112 public function testGetRegion()
113 {
114 $this->call('getRegion', 'pt-Latn-BR');
115 }
116
117 /**
118 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
119 */
120 public function testGetScript()
121 {
122 $this->call('getScript', 'pt-Latn-BR');
123 }
124
125 /**
126 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
127 */
128 public function testLookup()
129 {
130 $langtag = array(
131 'pt-Latn-BR',
132 'pt-BR'
133 );
134 $this->call('lookup', $langtag, 'pt-BR-x-priv1');
135 }
136
137 /**
138 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
139 */
140 public function testParseLocale()
141 {
142 $this->call('parseLocale', 'pt-Latn-BR');
143 }
144
145 /**
146 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
147 */
148 public function testSetDefault()
149 {
150 $this->call('setDefault', 'pt_BR');
151 }
152
153 protected function call($methodName)
154 {
155 $args = array_slice(func_get_args(), 1);
156
157 return call_user_func_array(array('Symfony\Component\Intl\Locale\Locale', $methodName), $args);
158 }
159}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/Verification/LocaleTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/Verification/LocaleTest.php
new file mode 100644
index 00000000..39d4f3cb
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Locale/Verification/LocaleTest.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Locale\Verification;
13
14use Symfony\Component\Intl\Tests\Locale\AbstractLocaleTest;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17/**
18 * Verifies that {@link AbstractLocaleTest} matches the behavior of the
19 * {@link Locale} class with a specific version of ICU.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class LocaleTest extends AbstractLocaleTest
24{
25 protected function setUp()
26 {
27 IntlTestHelper::requireFullIntl($this);
28
29 parent::setUp();
30 }
31
32 protected function call($methodName)
33 {
34 $args = array_slice(func_get_args(), 1);
35
36 return call_user_func_array(array('Locale', $methodName), $args);
37 }
38}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php
new file mode 100644
index 00000000..ad5581b4
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php
@@ -0,0 +1,707 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\NumberFormatter;
13
14use Symfony\Component\Intl\Globals\IntlGlobals;
15use Symfony\Component\Intl\Intl;
16use Symfony\Component\Intl\Locale;
17use Symfony\Component\Intl\NumberFormatter\NumberFormatter;
18use Symfony\Component\Intl\Util\IntlTestHelper;
19
20/**
21 * Note that there are some values written like -2147483647 - 1. This is the lower 32bit int max and is a known
22 * behavior of PHP.
23 */
24abstract class AbstractNumberFormatterTest extends \PHPUnit_Framework_TestCase
25{
26 /**
27 * @dataProvider formatCurrencyWithDecimalStyleProvider
28 */
29 public function testFormatCurrencyWithDecimalStyle($value, $currency, $expected)
30 {
31 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
32 $this->assertEquals($expected, $formatter->formatCurrency($value, $currency));
33 }
34
35 public function formatCurrencyWithDecimalStyleProvider()
36 {
37 return array(
38 array(100, 'ALL', '100'),
39 array(100, 'BRL', '100.00'),
40 array(100, 'CRC', '100'),
41 array(100, 'JPY', '100'),
42 array(100, 'CHF', '100'),
43 array(-100, 'ALL', '-100'),
44 array(-100, 'BRL', '-100'),
45 array(-100, 'CRC', '-100'),
46 array(-100, 'JPY', '-100'),
47 array(-100, 'CHF', '-100'),
48 array(1000.12, 'ALL', '1,000.12'),
49 array(1000.12, 'BRL', '1,000.12'),
50 array(1000.12, 'CRC', '1,000.12'),
51 array(1000.12, 'JPY', '1,000.12'),
52 array(1000.12, 'CHF', '1,000.12')
53 );
54 }
55
56 /**
57 * @dataProvider formatCurrencyWithCurrencyStyleProvider
58 */
59 public function testFormatCurrencyWithCurrencyStyle($value, $currency, $expected)
60 {
61 $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
62 $this->assertEquals($expected, $formatter->formatCurrency($value, $currency));
63 }
64
65 public function formatCurrencyWithCurrencyStyleProvider()
66 {
67 return array(
68 array(100, 'ALL', 'ALL100'),
69 array(-100, 'ALL', '(ALL100)'),
70 array(1000.12, 'ALL', 'ALL1,000'),
71
72 array(100, 'JPY', 'Â¥100'),
73 array(-100, 'JPY', '(Â¥100)'),
74 array(1000.12, 'JPY', 'Â¥1,000'),
75
76 array(100, 'EUR', '€100.00'),
77 array(-100, 'EUR', '(€100.00)'),
78 array(1000.12, 'EUR', '€1,000.12'),
79 );
80 }
81
82 /**
83 * @dataProvider formatCurrencyWithCurrencyStyleCostaRicanColonsRoundingProvider
84 */
85 public function testFormatCurrencyWithCurrencyStyleCostaRicanColonsRounding($value, $currency, $symbol, $expected)
86 {
87 $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
88 $this->assertEquals(sprintf($expected, $symbol), $formatter->formatCurrency($value, $currency));
89 }
90
91 public function formatCurrencyWithCurrencyStyleCostaRicanColonsRoundingProvider()
92 {
93 return array(
94 array(100, 'CRC', 'CRC', '%s100'),
95 array(-100, 'CRC', 'CRC', '(%s100)'),
96 array(1000.12, 'CRC', 'CRC', '%s1,000'),
97 );
98 }
99
100 /**
101 * @dataProvider formatCurrencyWithCurrencyStyleBrazilianRealRoundingProvider
102 */
103 public function testFormatCurrencyWithCurrencyStyleBrazilianRealRounding($value, $currency, $symbol, $expected)
104 {
105 $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
106 $this->assertEquals(sprintf($expected, $symbol), $formatter->formatCurrency($value, $currency));
107 }
108
109 public function formatCurrencyWithCurrencyStyleBrazilianRealRoundingProvider()
110 {
111 return array(
112 array(100, 'BRL', 'R', '%s$100.00'),
113 array(-100, 'BRL', 'R', '(%s$100.00)'),
114 array(1000.12, 'BRL', 'R', '%s$1,000.12'),
115
116 // Rounding checks
117 array(1000.121, 'BRL', 'R', '%s$1,000.12'),
118 array(1000.123, 'BRL', 'R', '%s$1,000.12'),
119 array(1000.125, 'BRL', 'R', '%s$1,000.12'),
120 array(1000.127, 'BRL', 'R', '%s$1,000.13'),
121 array(1000.129, 'BRL', 'R', '%s$1,000.13'),
122 array(11.50999, 'BRL', 'R', '%s$11.51'),
123 array(11.9999464, 'BRL', 'R', '%s$12.00')
124 );
125 }
126
127 /**
128 * @dataProvider formatCurrencyWithCurrencyStyleSwissRoundingProvider
129 */
130 public function testFormatCurrencyWithCurrencyStyleSwissRounding($value, $currency, $symbol, $expected)
131 {
132 $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
133 $this->assertEquals(sprintf($expected, $symbol), $formatter->formatCurrency($value, $currency));
134 }
135
136 public function formatCurrencyWithCurrencyStyleSwissRoundingProvider()
137 {
138 return array(
139 array(100, 'CHF', 'CHF', '%s100.00'),
140 array(-100, 'CHF', 'CHF', '(%s100.00)'),
141 array(1000.12, 'CHF', 'CHF', '%s1,000.10'),
142 array('1000.12', 'CHF', 'CHF', '%s1,000.10'),
143
144 // Rounding checks
145 array(1000.121, 'CHF', 'CHF', '%s1,000.10'),
146 array(1000.123, 'CHF', 'CHF', '%s1,000.10'),
147 array(1000.125, 'CHF', 'CHF', '%s1,000.10'),
148 array(1000.127, 'CHF', 'CHF', '%s1,000.15'),
149 array(1000.129, 'CHF', 'CHF', '%s1,000.15'),
150
151 array(1200000.00, 'CHF', 'CHF', '%s1,200,000.00'),
152 array(1200000.1, 'CHF', 'CHF', '%s1,200,000.10'),
153 array(1200000.10, 'CHF', 'CHF', '%s1,200,000.10'),
154 array(1200000.101, 'CHF', 'CHF', '%s1,200,000.10')
155 );
156 }
157
158 public function testFormat()
159 {
160 $errorCode = IntlGlobals::U_ZERO_ERROR;
161 $errorMessage = 'U_ZERO_ERROR';
162
163 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
164 $this->assertSame('9.555', $formatter->format(9.555));
165
166 $this->assertSame($errorMessage, $this->getIntlErrorMessage());
167 $this->assertSame($errorCode, $this->getIntlErrorCode());
168 $this->assertFalse($this->isIntlFailure($this->getIntlErrorCode()));
169 $this->assertSame($errorMessage, $formatter->getErrorMessage());
170 $this->assertSame($errorCode, $formatter->getErrorCode());
171 $this->assertFalse($this->isIntlFailure($formatter->getErrorCode()));
172 }
173
174 public function testFormatWithCurrencyStyle()
175 {
176 $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
177 $this->assertEquals('¤1.00', $formatter->format(1));
178 }
179
180 /**
181 * @dataProvider formatTypeInt32Provider
182 */
183 public function testFormatTypeInt32($formatter, $value, $expected, $message = '')
184 {
185 $formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT32);
186 $this->assertEquals($expected, $formattedValue, $message);
187 }
188
189 public function formatTypeInt32Provider()
190 {
191 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
192
193 $message = '->format() TYPE_INT32 formats inconsistently an integer if out of the 32 bit range.';
194
195 return array(
196 array($formatter, 1, '1'),
197 array($formatter, 1.1, '1'),
198 array($formatter, 2147483648, '-2,147,483,648', $message),
199 array($formatter, -2147483649, '2,147,483,647', $message),
200 );
201 }
202
203 /**
204 * @dataProvider formatTypeInt32WithCurrencyStyleProvider
205 */
206 public function testFormatTypeInt32WithCurrencyStyle($formatter, $value, $expected, $message = '')
207 {
208 $formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT32);
209 $this->assertEquals($expected, $formattedValue, $message);
210 }
211
212 public function formatTypeInt32WithCurrencyStyleProvider()
213 {
214 $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
215
216 $message = '->format() TYPE_INT32 formats inconsistently an integer if out of the 32 bit range.';
217
218 return array(
219 array($formatter, 1, '¤1.00'),
220 array($formatter, 1.1, '¤1.00'),
221 array($formatter, 2147483648, '(¤2,147,483,648.00)', $message),
222 array($formatter, -2147483649, '¤2,147,483,647.00', $message)
223 );
224 }
225
226 /**
227 * The parse() method works differently with integer out of the 32 bit range. format() works fine.
228 * @dataProvider formatTypeInt64Provider
229 */
230 public function testFormatTypeInt64($formatter, $value, $expected)
231 {
232 $formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT64);
233 $this->assertEquals($expected, $formattedValue);
234 }
235
236 public function formatTypeInt64Provider()
237 {
238 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
239
240 return array(
241 array($formatter, 1, '1'),
242 array($formatter, 1.1, '1'),
243 array($formatter, 2147483648, '2,147,483,648'),
244 array($formatter, -2147483649, '-2,147,483,649'),
245 );
246 }
247
248 /**
249 * @dataProvider formatTypeInt64WithCurrencyStyleProvider
250 */
251 public function testFormatTypeInt64WithCurrencyStyle($formatter, $value, $expected)
252 {
253 $formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT64);
254 $this->assertEquals($expected, $formattedValue);
255 }
256
257 public function formatTypeInt64WithCurrencyStyleProvider()
258 {
259 $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
260
261 return array(
262 array($formatter, 1, '¤1.00'),
263 array($formatter, 1.1, '¤1.00'),
264 array($formatter, 2147483648, '¤2,147,483,648.00'),
265 array($formatter, -2147483649, '(¤2,147,483,649.00)')
266 );
267 }
268
269 /**
270 * @dataProvider formatTypeDoubleProvider
271 */
272 public function testFormatTypeDouble($formatter, $value, $expected)
273 {
274 $formattedValue = $formatter->format($value, NumberFormatter::TYPE_DOUBLE);
275 $this->assertEquals($expected, $formattedValue);
276 }
277
278 public function formatTypeDoubleProvider()
279 {
280 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
281
282 return array(
283 array($formatter, 1, '1'),
284 array($formatter, 1.1, '1.1'),
285 );
286 }
287
288 /**
289 * @dataProvider formatTypeDoubleWithCurrencyStyleProvider
290 */
291 public function testFormatTypeDoubleWithCurrencyStyle($formatter, $value, $expected)
292 {
293 $formattedValue = $formatter->format($value, NumberFormatter::TYPE_DOUBLE);
294 $this->assertEquals($expected, $formattedValue);
295 }
296
297 public function formatTypeDoubleWithCurrencyStyleProvider()
298 {
299 $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
300
301 return array(
302 array($formatter, 1, '¤1.00'),
303 array($formatter, 1.1, '¤1.10'),
304 );
305 }
306
307 /**
308 * @dataProvider formatTypeCurrencyProvider
309 * @expectedException \PHPUnit_Framework_Error_Warning
310 */
311 public function testFormatTypeCurrency($formatter, $value)
312 {
313 $formatter->format($value, NumberFormatter::TYPE_CURRENCY);
314 }
315
316 /**
317 * @dataProvider formatTypeCurrencyProvider
318 */
319 public function testFormatTypeCurrencyReturn($formatter, $value)
320 {
321 $this->assertFalse(@$formatter->format($value, NumberFormatter::TYPE_CURRENCY));
322 }
323
324 public function formatTypeCurrencyProvider()
325 {
326 $df = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
327 $cf = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
328
329 return array(
330 array($df, 1),
331 array($cf, 1),
332 );
333 }
334
335 /**
336 * @dataProvider formatFractionDigitsProvider
337 */
338 public function testFormatFractionDigits($value, $expected, $fractionDigits = null, $expectedFractionDigits = 1)
339 {
340 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
341
342 if (null !== $fractionDigits) {
343 $attributeRet = $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $fractionDigits);
344 }
345
346 $formattedValue = $formatter->format($value);
347 $this->assertSame($expected, $formattedValue);
348 $this->assertSame($expectedFractionDigits, $formatter->getAttribute(NumberFormatter::FRACTION_DIGITS));
349
350 if (isset($attributeRet)) {
351 $this->assertTrue($attributeRet);
352 }
353 }
354
355 public function formatFractionDigitsProvider()
356 {
357 return array(
358 array(1.123, '1.123', null, 0),
359 array(1.123, '1', 0, 0),
360 array(1.123, '1.1', 1, 1),
361 array(1.123, '1.12', 2, 2),
362 array(1.123, '1', -1, 0),
363 array(1.123, '1', 'abc', 0)
364 );
365 }
366
367 /**
368 * @dataProvider formatGroupingUsedProvider
369 */
370 public function testFormatGroupingUsed($value, $expected, $groupingUsed = null, $expectedGroupingUsed = 1)
371 {
372 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
373
374 if (null !== $groupingUsed) {
375 $attributeRet = $formatter->setAttribute(NumberFormatter::GROUPING_USED, $groupingUsed);
376 }
377
378 $formattedValue = $formatter->format($value);
379 $this->assertSame($expected, $formattedValue);
380 $this->assertSame($expectedGroupingUsed, $formatter->getAttribute(NumberFormatter::GROUPING_USED));
381
382 if (isset($attributeRet)) {
383 $this->assertTrue($attributeRet);
384 }
385 }
386
387 public function formatGroupingUsedProvider()
388 {
389 return array(
390 array(1000, '1,000', null, 1),
391 array(1000, '1000', 0, 0),
392 array(1000, '1,000', 1, 1),
393 array(1000, '1,000', 2, 1),
394 array(1000, '1000', 'abc', 0),
395 array(1000, '1,000', -1, 1),
396 );
397 }
398
399 /**
400 * @dataProvider formatRoundingModeRoundHalfUpProvider
401 */
402 public function testFormatRoundingModeHalfUp($value, $expected)
403 {
404 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
405 $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
406
407 $formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFUP);
408 $this->assertSame($expected, $formatter->format($value), '->format() with ROUND_HALFUP rounding mode.');
409 }
410
411 public function formatRoundingModeRoundHalfUpProvider()
412 {
413 // The commented value is differently rounded by intl's NumberFormatter in 32 and 64 bit architectures
414 return array(
415 array(1.121, '1.12'),
416 array(1.123, '1.12'),
417 // array(1.125, '1.13'),
418 array(1.127, '1.13'),
419 array(1.129, '1.13'),
420 );
421 }
422
423 /**
424 * @dataProvider formatRoundingModeRoundHalfDownProvider
425 */
426 public function testFormatRoundingModeHalfDown($value, $expected)
427 {
428 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
429 $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
430
431 $formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFDOWN);
432 $this->assertSame($expected, $formatter->format($value), '->format() with ROUND_HALFDOWN rounding mode.');
433 }
434
435 public function formatRoundingModeRoundHalfDownProvider()
436 {
437 return array(
438 array(1.121, '1.12'),
439 array(1.123, '1.12'),
440 array(1.125, '1.12'),
441 array(1.127, '1.13'),
442 array(1.129, '1.13'),
443 );
444 }
445
446 /**
447 * @dataProvider formatRoundingModeRoundHalfEvenProvider
448 */
449 public function testFormatRoundingModeHalfEven($value, $expected)
450 {
451 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
452 $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
453
454 $formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFEVEN);
455 $this->assertSame($expected, $formatter->format($value), '->format() with ROUND_HALFEVEN rounding mode.');
456 }
457
458 public function formatRoundingModeRoundHalfEvenProvider()
459 {
460 return array(
461 array(1.121, '1.12'),
462 array(1.123, '1.12'),
463 array(1.125, '1.12'),
464 array(1.127, '1.13'),
465 array(1.129, '1.13'),
466 );
467 }
468
469 public function testGetLocale()
470 {
471 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
472 $this->assertEquals('en', $formatter->getLocale());
473 }
474
475 /**
476 * @dataProvider parseProvider
477 */
478 public function testParse($value, $expected, $message = '')
479 {
480 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
481 $parsedValue = $formatter->parse($value, NumberFormatter::TYPE_DOUBLE);
482 $this->assertSame($expected, $parsedValue, $message);
483
484 if ($expected === false) {
485 $errorCode = IntlGlobals::U_PARSE_ERROR;
486 $errorMessage = 'Number parsing failed: U_PARSE_ERROR';
487 } else {
488 $errorCode = IntlGlobals::U_ZERO_ERROR;
489 $errorMessage = 'U_ZERO_ERROR';
490 }
491
492 $this->assertSame($errorMessage, $this->getIntlErrorMessage());
493 $this->assertSame($errorCode, $this->getIntlErrorCode());
494 $this->assertSame($errorCode !== 0, $this->isIntlFailure($this->getIntlErrorCode()));
495 $this->assertSame($errorMessage, $formatter->getErrorMessage());
496 $this->assertSame($errorCode, $formatter->getErrorCode());
497 $this->assertSame($errorCode !== 0, $this->isIntlFailure($formatter->getErrorCode()));
498 }
499
500 public function parseProvider()
501 {
502 return array(
503 array('prefix1', false, '->parse() does not parse a number with a string prefix.'),
504 array('1suffix', (float) 1, '->parse() parses a number with a string suffix.'),
505 );
506 }
507
508 /**
509 * @expectedException \PHPUnit_Framework_Error_Warning
510 */
511 public function testParseTypeDefault()
512 {
513 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
514 $formatter->parse('1', NumberFormatter::TYPE_DEFAULT);
515 }
516
517 /**
518 * @dataProvider parseTypeInt32Provider
519 */
520 public function testParseTypeInt32($value, $expected, $message = '')
521 {
522 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
523 $parsedValue = $formatter->parse($value, NumberFormatter::TYPE_INT32);
524 $this->assertSame($expected, $parsedValue);
525 }
526
527 public function parseTypeInt32Provider()
528 {
529 return array(
530 array('1', 1),
531 array('1.1', 1),
532 array('2,147,483,647', 2147483647),
533 array('-2,147,483,648', -2147483647 - 1),
534 array('2,147,483,648', false, '->parse() TYPE_INT32 returns false when the number is greater than the integer positive range.'),
535 array('-2,147,483,649', false, '->parse() TYPE_INT32 returns false when the number is greater than the integer negative range.')
536 );
537 }
538
539 public function testParseTypeInt64With32BitIntegerInPhp32Bit()
540 {
541 IntlTestHelper::require32Bit($this);
542
543 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
544
545 $parsedValue = $formatter->parse('2,147,483,647', NumberFormatter::TYPE_INT64);
546 $this->assertInternalType('integer', $parsedValue);
547 $this->assertEquals(2147483647, $parsedValue);
548
549 $parsedValue = $formatter->parse('-2,147,483,648', NumberFormatter::TYPE_INT64);
550
551 // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
552 // The negative PHP_INT_MAX was being converted to float
553 if (
554 (version_compare(PHP_VERSION, '5.4.0', '<') && version_compare(PHP_VERSION, '5.3.14', '>=')) ||
555 version_compare(PHP_VERSION, '5.4.4', '>=')
556 ) {
557 $this->assertInternalType('int', $parsedValue);
558 } else {
559 $this->assertInternalType('float', $parsedValue);
560 }
561
562 $this->assertEquals(-2147483648, $parsedValue);
563 }
564
565 public function testParseTypeInt64With32BitIntegerInPhp64Bit()
566 {
567 IntlTestHelper::require64Bit($this);
568
569 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
570
571 $parsedValue = $formatter->parse('2,147,483,647', NumberFormatter::TYPE_INT64);
572 $this->assertInternalType('integer', $parsedValue);
573 $this->assertEquals(2147483647, $parsedValue);
574
575 $parsedValue = $formatter->parse('-2,147,483,648', NumberFormatter::TYPE_INT64);
576 $this->assertInternalType('integer', $parsedValue);
577 $this->assertEquals(-2147483647 - 1, $parsedValue);
578 }
579
580 /**
581 * If PHP is compiled in 32bit mode, the returned value for a 64bit integer are float numbers.
582 */
583 public function testParseTypeInt64With64BitIntegerInPhp32Bit()
584 {
585 IntlTestHelper::require32Bit($this);
586
587 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
588
589 // int 64 using only 32 bit range strangeness
590 $parsedValue = $formatter->parse('2,147,483,648', NumberFormatter::TYPE_INT64);
591 $this->assertInternalType('float', $parsedValue);
592 $this->assertEquals(2147483648, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range.');
593
594 $parsedValue = $formatter->parse('-2,147,483,649', NumberFormatter::TYPE_INT64);
595 $this->assertInternalType('float', $parsedValue);
596 $this->assertEquals(-2147483649, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range.');
597 }
598
599 /**
600 * If PHP is compiled in 64bit mode, the returned value for a 64bit integer are 32bit integer numbers.
601 */
602 public function testParseTypeInt64With64BitIntegerInPhp64Bit()
603 {
604 IntlTestHelper::require64Bit($this);
605
606 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
607
608 $parsedValue = $formatter->parse('2,147,483,648', NumberFormatter::TYPE_INT64);
609 $this->assertInternalType('integer', $parsedValue);
610
611 // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
612 // A 32 bit integer was being generated instead of a 64 bit integer
613 if (
614 (version_compare(PHP_VERSION, '5.3.14', '<')) ||
615 (version_compare(PHP_VERSION, '5.4.0', '>=') && version_compare(PHP_VERSION, '5.4.4', '<'))
616 ) {
617 $this->assertEquals(-2147483648, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range (PHP < 5.3.14 and PHP < 5.4.4).');
618 } else {
619 $this->assertEquals(2147483648, $parsedValue, '->parse() TYPE_INT64 uses true 64 bit integers (PHP >= 5.3.14 and PHP >= 5.4.4).');
620 }
621
622 $parsedValue = $formatter->parse('-2,147,483,649', NumberFormatter::TYPE_INT64);
623 $this->assertInternalType('integer', $parsedValue);
624
625 // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
626 // A 32 bit integer was being generated instead of a 64 bit integer
627 if (
628 (version_compare(PHP_VERSION, '5.3.14', '<')) ||
629 (version_compare(PHP_VERSION, '5.4.0', '>=') && version_compare(PHP_VERSION, '5.4.4', '<'))
630 ) {
631 $this->assertEquals(2147483647, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range (PHP < 5.3.14 and PHP < 5.4.4).');
632 } else {
633 $this->assertEquals(-2147483649, $parsedValue, '->parse() TYPE_INT64 uses true 64 bit integers (PHP >= 5.3.14 and PHP >= 5.4.4).');
634 }
635 }
636
637 /**
638 * @dataProvider parseTypeDoubleProvider
639 */
640 public function testParseTypeDouble($value, $expectedValue)
641 {
642 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
643 $parsedValue = $formatter->parse($value, NumberFormatter::TYPE_DOUBLE);
644 $this->assertSame($expectedValue, $parsedValue);
645 }
646
647 public function parseTypeDoubleProvider()
648 {
649 return array(
650 array('1', (float) 1),
651 array('1.1', 1.1),
652 array('9,223,372,036,854,775,808', 9223372036854775808),
653 array('-9,223,372,036,854,775,809', -9223372036854775809),
654 );
655 }
656
657 /**
658 * @expectedException \PHPUnit_Framework_Error_Warning
659 */
660 public function testParseTypeCurrency()
661 {
662 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
663 $formatter->parse('1', NumberFormatter::TYPE_CURRENCY);
664 }
665
666 public function testParseWithNullPositionValue()
667 {
668 $position = null;
669 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
670 $formatter->parse('123', NumberFormatter::TYPE_INT32, $position);
671 $this->assertNull($position);
672 }
673
674 public function testParseWithNotNullPositionValue()
675 {
676 $position = 1;
677 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
678 $formatter->parse('123', NumberFormatter::TYPE_DOUBLE, $position);
679 $this->assertEquals(3, $position);
680 }
681
682 /**
683 * @param string $locale
684 * @param null $style
685 * @param null $pattern
686 *
687 * @return \NumberFormatter
688 */
689 abstract protected function getNumberFormatter($locale = 'en', $style = null, $pattern = null);
690
691 /**
692 * @return string
693 */
694 abstract protected function getIntlErrorMessage();
695
696 /**
697 * @return integer
698 */
699 abstract protected function getIntlErrorCode();
700
701 /**
702 * @param integer $errorCode
703 *
704 * @return Boolean
705 */
706 abstract protected function isIntlFailure($errorCode);
707}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/NumberFormatterTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/NumberFormatterTest.php
new file mode 100644
index 00000000..36e89149
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/NumberFormatterTest.php
@@ -0,0 +1,239 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\NumberFormatter;
13
14use Symfony\Component\Intl\Globals\IntlGlobals;
15use Symfony\Component\Intl\NumberFormatter\NumberFormatter;
16use Symfony\Component\Intl\Util\IntlTestHelper;
17
18/**
19 * Note that there are some values written like -2147483647 - 1. This is the lower 32bit int max and is a known
20 * behavior of PHP.
21 */
22class NumberFormatterTest extends AbstractNumberFormatterTest
23{
24 protected function setUp()
25 {
26 IntlTestHelper::requireIntl($this);
27
28 parent::setUp();
29 }
30
31 /**
32 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
33 */
34 public function testConstructorWithUnsupportedLocale()
35 {
36 new NumberFormatter('pt_BR');
37 }
38
39 /**
40 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
41 */
42 public function testConstructorWithUnsupportedStyle()
43 {
44 new NumberFormatter('en', NumberFormatter::PATTERN_DECIMAL);
45 }
46
47 /**
48 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException
49 */
50 public function testConstructorWithPatternDifferentThanNull()
51 {
52 new NumberFormatter('en', NumberFormatter::DECIMAL, '');
53 }
54
55 /**
56 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
57 */
58 public function testSetAttributeWithUnsupportedAttribute()
59 {
60 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
61 $formatter->setAttribute(NumberFormatter::LENIENT_PARSE, null);
62 }
63
64 /**
65 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
66 */
67 public function testSetAttributeInvalidRoundingMode()
68 {
69 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
70 $formatter->setAttribute(NumberFormatter::ROUNDING_MODE, null);
71 }
72
73 public function testCreate()
74 {
75 $this->assertInstanceOf(
76 '\Symfony\Component\Intl\NumberFormatter\NumberFormatter',
77 NumberFormatter::create('en', NumberFormatter::DECIMAL)
78 );
79 }
80
81 /**
82 * @expectedException \RuntimeException
83 */
84 public function testFormatWithCurrencyStyle()
85 {
86 parent::testFormatWithCurrencyStyle();
87 }
88
89 /**
90 * @dataProvider formatTypeInt32Provider
91 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
92 */
93 public function testFormatTypeInt32($formatter, $value, $expected, $message = '')
94 {
95 parent::testFormatTypeInt32($formatter, $value, $expected, $message);
96 }
97
98 /**
99 * @dataProvider formatTypeInt32WithCurrencyStyleProvider
100 * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
101 */
102 public function testFormatTypeInt32WithCurrencyStyle($formatter, $value, $expected, $message = '')
103 {
104 parent::testFormatTypeInt32WithCurrencyStyle($formatter, $value, $expected, $message);
105 }
106
107 /**
108 * @dataProvider formatTypeInt64Provider
109 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
110 */
111 public function testFormatTypeInt64($formatter, $value, $expected)
112 {
113 parent::testFormatTypeInt64($formatter, $value, $expected);
114 }
115
116 /**
117 * @dataProvider formatTypeInt64WithCurrencyStyleProvider
118 * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
119 */
120 public function testFormatTypeInt64WithCurrencyStyle($formatter, $value, $expected)
121 {
122 parent::testFormatTypeInt64WithCurrencyStyle($formatter, $value, $expected);
123 }
124
125 /**
126 * @dataProvider formatTypeDoubleProvider
127 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
128 */
129 public function testFormatTypeDouble($formatter, $value, $expected)
130 {
131 parent::testFormatTypeDouble($formatter, $value, $expected);
132 }
133
134 /**
135 * @dataProvider formatTypeDoubleWithCurrencyStyleProvider
136 * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
137 */
138 public function testFormatTypeDoubleWithCurrencyStyle($formatter, $value, $expected)
139 {
140 parent::testFormatTypeDoubleWithCurrencyStyle($formatter, $value, $expected);
141 }
142
143 /**
144 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
145 */
146 public function testGetPattern()
147 {
148 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
149 $formatter->getPattern();
150 }
151
152 /**
153 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
154 */
155 public function testGetSymbol()
156 {
157 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
158 $formatter->getSymbol(null);
159 }
160
161 /**
162 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
163 */
164 public function testGetTextAttribute()
165 {
166 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
167 $formatter->getTextAttribute(null);
168 }
169
170 public function testGetErrorCode()
171 {
172 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
173 $this->assertEquals(IntlGlobals::U_ZERO_ERROR, $formatter->getErrorCode());
174 }
175
176 /**
177 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
178 */
179 public function testParseCurrency()
180 {
181 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
182 $formatter->parseCurrency(null, $currency);
183 }
184
185 /**
186 * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException
187 */
188 public function testParseWithNotNullPositionValue()
189 {
190 parent::testParseWithNotNullPositionValue();
191 }
192
193 /**
194 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
195 */
196 public function testSetPattern()
197 {
198 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
199 $formatter->setPattern(null);
200 }
201
202 /**
203 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
204 */
205 public function testSetSymbol()
206 {
207 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
208 $formatter->setSymbol(null, null);
209 }
210
211 /**
212 * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
213 */
214 public function testSetTextAttribute()
215 {
216 $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
217 $formatter->setTextAttribute(null, null);
218 }
219
220 protected function getNumberFormatter($locale = 'en', $style = null, $pattern = null)
221 {
222 return new NumberFormatter($locale, $style, $pattern);
223 }
224
225 protected function getIntlErrorMessage()
226 {
227 return IntlGlobals::getErrorMessage();
228 }
229
230 protected function getIntlErrorCode()
231 {
232 return IntlGlobals::getErrorCode();
233 }
234
235 protected function isIntlFailure($errorCode)
236 {
237 return IntlGlobals::isFailure($errorCode);
238 }
239}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/Verification/NumberFormatterTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/Verification/NumberFormatterTest.php
new file mode 100644
index 00000000..28e6fe90
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/NumberFormatter/Verification/NumberFormatterTest.php
@@ -0,0 +1,54 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\NumberFormatter\Verification;
13
14use Symfony\Component\Intl\Tests\NumberFormatter\AbstractNumberFormatterTest;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17/**
18 * Note that there are some values written like -2147483647 - 1. This is the lower 32bit int max and is a known
19 * behavior of PHP.
20 */
21class NumberFormatterTest extends AbstractNumberFormatterTest
22{
23 protected function setUp()
24 {
25 IntlTestHelper::requireFullIntl($this);
26
27 parent::setUp();
28 }
29
30 public function testCreate()
31 {
32 $this->assertInstanceOf('\NumberFormatter', \NumberFormatter::create('en', \NumberFormatter::DECIMAL));
33 }
34
35 protected function getNumberFormatter($locale = 'en', $style = null, $pattern = null)
36 {
37 return new \NumberFormatter($locale, $style, $pattern);
38 }
39
40 protected function getIntlErrorMessage()
41 {
42 return intl_get_error_message();
43 }
44
45 protected function getIntlErrorCode()
46 {
47 return intl_get_error_code();
48 }
49
50 protected function isIntlFailure($errorCode)
51 {
52 return intl_is_failure($errorCode);
53 }
54}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/AbstractBundleTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/AbstractBundleTest.php
new file mode 100644
index 00000000..6b075865
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/AbstractBundleTest.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class AbstractBundleTest extends \PHPUnit_Framework_TestCase
18{
19 const RES_DIR = '/base/dirName';
20
21 /**
22 * @var \Symfony\Component\Intl\ResourceBundle\AbstractBundle
23 */
24 private $bundle;
25
26 /**
27 * @var \PHPUnit_Framework_MockObject_MockObject
28 */
29 private $reader;
30
31 protected function setUp()
32 {
33 $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
34 $this->bundle = $this->getMockForAbstractClass(
35 'Symfony\Component\Intl\ResourceBundle\AbstractBundle',
36 array(self::RES_DIR, $this->reader)
37 );
38
39 $this->bundle->expects($this->any())
40 ->method('getDirectoryName')
41 ->will($this->returnValue('dirName'));
42 }
43
44 public function testGetLocales()
45 {
46 $locales = array('de', 'en', 'fr');
47
48 $this->reader->expects($this->once())
49 ->method('getLocales')
50 ->with(self::RES_DIR)
51 ->will($this->returnValue($locales));
52
53 $this->assertSame($locales, $this->bundle->getLocales());
54 }
55}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/CurrencyBundleTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/CurrencyBundleTest.php
new file mode 100644
index 00000000..b66a6727
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/CurrencyBundleTest.php
@@ -0,0 +1,98 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle;
13
14use Symfony\Component\Intl\ResourceBundle\CurrencyBundle;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class CurrencyBundleTest extends \PHPUnit_Framework_TestCase
20{
21 const RES_DIR = '/base/curr';
22
23 /**
24 * @var CurrencyBundle
25 */
26 private $bundle;
27
28 /**
29 * @var \PHPUnit_Framework_MockObject_MockObject
30 */
31 private $reader;
32
33 protected function setUp()
34 {
35 $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
36 $this->bundle = new CurrencyBundle(self::RES_DIR, $this->reader);
37 }
38
39 public function testGetCurrencySymbol()
40 {
41 $this->reader->expects($this->once())
42 ->method('readEntry')
43 ->with(self::RES_DIR, 'en', array('Currencies', 'EUR', 1))
44 ->will($this->returnValue('€'));
45
46 $this->assertSame('€', $this->bundle->getCurrencySymbol('EUR', 'en'));
47 }
48
49 public function testGetCurrencyName()
50 {
51 $this->reader->expects($this->once())
52 ->method('readEntry')
53 ->with(self::RES_DIR, 'en', array('Currencies', 'EUR', 0))
54 ->will($this->returnValue('Euro'));
55
56 $this->assertSame('Euro', $this->bundle->getCurrencyName('EUR', 'en'));
57 }
58
59 public function testGetCurrencyNames()
60 {
61 $sortedCurrencies = array(
62 'USD' => array(0 => 'Dollar'),
63 'EUR' => array(0 => 'Euro'),
64 );
65
66 $this->reader->expects($this->once())
67 ->method('readEntry')
68 ->with(self::RES_DIR, 'en', array('Currencies'))
69 ->will($this->returnValue($sortedCurrencies));
70
71 $sortedNames = array(
72 'USD' => 'Dollar',
73 'EUR' => 'Euro',
74 );
75
76 $this->assertSame($sortedNames, $this->bundle->getCurrencyNames('en'));
77 }
78
79 public function testGetFractionDigits()
80 {
81 $this->reader->expects($this->once())
82 ->method('readEntry')
83 ->with(self::RES_DIR, 'en', array('Currencies', 'EUR', 2))
84 ->will($this->returnValue(123));
85
86 $this->assertSame(123, $this->bundle->getFractionDigits('EUR'));
87 }
88
89 public function testGetRoundingIncrement()
90 {
91 $this->reader->expects($this->once())
92 ->method('readEntry')
93 ->with(self::RES_DIR, 'en', array('Currencies', 'EUR', 3))
94 ->will($this->returnValue(123));
95
96 $this->assertSame(123, $this->bundle->getRoundingIncrement('EUR'));
97 }
98}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/LanguageBundleTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/LanguageBundleTest.php
new file mode 100644
index 00000000..96031fc7
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/LanguageBundleTest.php
@@ -0,0 +1,197 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle;
13
14use Symfony\Component\Intl\ResourceBundle\LanguageBundle;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class LanguageBundleTest extends \PHPUnit_Framework_TestCase
20{
21 const RES_DIR = '/base/lang';
22
23 /**
24 * @var LanguageBundle
25 */
26 private $bundle;
27
28 /**
29 * @var \PHPUnit_Framework_MockObject_MockObject
30 */
31 private $reader;
32
33 protected function setUp()
34 {
35 $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
36 $this->bundle = new LanguageBundle(self::RES_DIR, $this->reader);
37 }
38
39 public function testGetLanguageName()
40 {
41 $languages = array(
42 'de' => 'German',
43 'en' => 'English',
44 );
45
46 $this->reader->expects($this->once())
47 ->method('readEntry')
48 ->with(self::RES_DIR, 'en', array('Languages'))
49 ->will($this->returnValue($languages));
50
51 $this->assertSame('German', $this->bundle->getLanguageName('de', null, 'en'));
52 }
53
54 public function testGetLanguageNameWithRegion()
55 {
56 $languages = array(
57 'de' => 'German',
58 'en' => 'English',
59 'en_GB' => 'British English',
60 );
61
62 $this->reader->expects($this->once())
63 ->method('readEntry')
64 ->with(self::RES_DIR, 'en', array('Languages'))
65 ->will($this->returnValue($languages));
66
67 $this->assertSame('British English', $this->bundle->getLanguageName('en', 'GB', 'en'));
68 }
69
70 public function testGetLanguageNameWithUntranslatedRegion()
71 {
72 $languages = array(
73 'de' => 'German',
74 'en' => 'English',
75 );
76
77 $this->reader->expects($this->once())
78 ->method('readEntry')
79 ->with(self::RES_DIR, 'en', array('Languages'))
80 ->will($this->returnValue($languages));
81
82 $this->assertSame('English', $this->bundle->getLanguageName('en', 'US', 'en'));
83 }
84
85 public function testGetLanguageNames()
86 {
87 $sortedLanguages = array(
88 'en' => 'English',
89 'de' => 'German',
90 );
91
92 $this->reader->expects($this->once())
93 ->method('readEntry')
94 ->with(self::RES_DIR, 'en', array('Languages'))
95 ->will($this->returnValue($sortedLanguages));
96
97 $this->assertSame($sortedLanguages, $this->bundle->getLanguageNames('en'));
98 }
99
100 public function testGetScriptName()
101 {
102 $data = array(
103 'Languages' => array(
104 'de' => 'German',
105 'en' => 'English',
106 ),
107 'Scripts' => array(
108 'Latn' => 'latin',
109 'Cyrl' => 'cyrillique',
110 ),
111 );
112
113 $this->reader->expects($this->once())
114 ->method('read')
115 ->with(self::RES_DIR, 'en')
116 ->will($this->returnValue($data));
117
118 $this->assertSame('latin', $this->bundle->getScriptName('Latn', null, 'en'));
119 }
120
121 public function testGetScriptNameIncludedInLanguage()
122 {
123 $data = array(
124 'Languages' => array(
125 'de' => 'German',
126 'en' => 'English',
127 'zh_Hans' => 'Simplified Chinese',
128 ),
129 'Scripts' => array(
130 'Latn' => 'latin',
131 'Cyrl' => 'cyrillique',
132 ),
133 );
134
135 $this->reader->expects($this->once())
136 ->method('read')
137 ->with(self::RES_DIR, 'en')
138 ->will($this->returnValue($data));
139
140 // Null because the script is included in the language anyway
141 $this->assertNull($this->bundle->getScriptName('Hans', 'zh', 'en'));
142 }
143
144 public function testGetScriptNameIncludedInLanguageInBraces()
145 {
146 $data = array(
147 'Languages' => array(
148 'de' => 'German',
149 'en' => 'English',
150 'zh_Hans' => 'Chinese (simplified)',
151 ),
152 'Scripts' => array(
153 'Latn' => 'latin',
154 'Cyrl' => 'cyrillique',
155 ),
156 );
157
158 $this->reader->expects($this->once())
159 ->method('read')
160 ->with(self::RES_DIR, 'en')
161 ->will($this->returnValue($data));
162
163 $this->assertSame('simplified', $this->bundle->getScriptName('Hans', 'zh', 'en'));
164 }
165
166 public function testGetScriptNameNoScriptsBlock()
167 {
168 $data = array(
169 'Languages' => array(
170 'de' => 'German',
171 'en' => 'English',
172 ),
173 );
174
175 $this->reader->expects($this->once())
176 ->method('read')
177 ->with(self::RES_DIR, 'en')
178 ->will($this->returnValue($data));
179
180 $this->assertNull($this->bundle->getScriptName('Latn', null, 'en'));
181 }
182
183 public function testGetScriptNames()
184 {
185 $sortedScripts = array(
186 'Cyrl' => 'cyrillique',
187 'Latn' => 'latin',
188 );
189
190 $this->reader->expects($this->once())
191 ->method('readEntry')
192 ->with(self::RES_DIR, 'en', array('Scripts'))
193 ->will($this->returnValue($sortedScripts));
194
195 $this->assertSame($sortedScripts, $this->bundle->getScriptNames('en'));
196 }
197}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/LocaleBundleTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/LocaleBundleTest.php
new file mode 100644
index 00000000..ddfdc3d2
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/LocaleBundleTest.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle;
13
14use Symfony\Component\Intl\ResourceBundle\LocaleBundle;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class LocaleBundleTest extends \PHPUnit_Framework_TestCase
20{
21 const RES_DIR = '/base/locales';
22
23 /**
24 * @var LocaleBundle
25 */
26 private $bundle;
27
28 /**
29 * @var \PHPUnit_Framework_MockObject_MockObject
30 */
31 private $reader;
32
33 protected function setUp()
34 {
35 $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
36 $this->bundle = new LocaleBundle(self::RES_DIR, $this->reader);
37 }
38
39 public function testGetLocaleName()
40 {
41 $this->reader->expects($this->once())
42 ->method('readEntry')
43 ->with(self::RES_DIR, 'en', array('Locales', 'de_AT'))
44 ->will($this->returnValue('German (Austria)'));
45
46 $this->assertSame('German (Austria)', $this->bundle->getLocaleName('de_AT', 'en'));
47 }
48
49 public function testGetLocaleNames()
50 {
51 $sortedLocales = array(
52 'en_IE' => 'English (Ireland)',
53 'en_GB' => 'English (United Kingdom)',
54 'en_US' => 'English (United States)',
55 );
56
57 $this->reader->expects($this->once())
58 ->method('readEntry')
59 ->with(self::RES_DIR, 'en', array('Locales'))
60 ->will($this->returnValue($sortedLocales));
61
62 $this->assertSame($sortedLocales, $this->bundle->getLocaleNames('en'));
63 }
64}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/AbstractBundleReaderTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/AbstractBundleReaderTest.php
new file mode 100644
index 00000000..2da7f90d
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/AbstractBundleReaderTest.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle\Reader;
13
14use Symfony\Component\Filesystem\Filesystem;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class AbstractBundleReaderTest extends \PHPUnit_Framework_TestCase
20{
21 private $directory;
22
23 /**
24 * @var Filesystem
25 */
26 private $filesystem;
27
28 /**
29 * @var \PHPUnit_Framework_MockObject_MockObject
30 */
31 private $reader;
32
33 protected function setUp()
34 {
35 $this->directory = sys_get_temp_dir() . '/AbstractBundleReaderTest/' . rand(1000, 9999);
36 $this->filesystem = new Filesystem();
37 $this->reader = $this->getMockForAbstractClass('Symfony\Component\Intl\ResourceBundle\Reader\AbstractBundleReader');
38
39 $this->filesystem->mkdir($this->directory);
40 }
41
42 protected function tearDown()
43 {
44 $this->filesystem->remove($this->directory);
45 }
46
47 public function testGetLocales()
48 {
49 $this->filesystem->touch($this->directory . '/en.foo');
50 $this->filesystem->touch($this->directory . '/de.foo');
51 $this->filesystem->touch($this->directory . '/fr.foo');
52 $this->filesystem->touch($this->directory . '/bo.txt');
53 $this->filesystem->touch($this->directory . '/gu.bin');
54 $this->filesystem->touch($this->directory . '/s.lol');
55
56 $this->reader->expects($this->any())
57 ->method('getFileExtension')
58 ->will($this->returnValue('foo'));
59
60 $sortedLocales = array('de', 'en', 'fr');
61
62 $this->assertSame($sortedLocales, $this->reader->getLocales($this->directory));
63 }
64}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/BinaryBundleReaderTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/BinaryBundleReaderTest.php
new file mode 100644
index 00000000..3aefbae7
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/BinaryBundleReaderTest.php
@@ -0,0 +1,58 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle\Reader;
13
14use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader;
15use Symfony\Component\Intl\Util\IntlTestHelper;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class BinaryBundleReaderTest extends \PHPUnit_Framework_TestCase
21{
22 /**
23 * @var BinaryBundleReader
24 */
25 private $reader;
26
27 protected function setUp()
28 {
29 IntlTestHelper::requireFullIntl($this);
30
31 $this->reader = new BinaryBundleReader();
32 }
33
34 public function testReadReturnsArrayAccess()
35 {
36 $data = $this->reader->read(__DIR__ . '/Fixtures', 'en');
37
38 $this->assertInstanceOf('\ArrayAccess', $data);
39 $this->assertSame('Bar', $data['Foo']);
40 $this->assertFalse(isset($data['ExistsNot']));
41 }
42
43 /**
44 * @expectedException \Symfony\Component\Intl\Exception\RuntimeException
45 */
46 public function testReadFailsIfNonExistingLocale()
47 {
48 $this->reader->read(__DIR__ . '/Fixtures', 'foo');
49 }
50
51 /**
52 * @expectedException \Symfony\Component\Intl\Exception\RuntimeException
53 */
54 public function testReadFailsIfNonExistingDirectory()
55 {
56 $this->reader->read(__DIR__ . '/foo', 'en');
57 }
58}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/NotAFile/en.php/.gitkeep b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/NotAFile/en.php/.gitkeep
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/NotAFile/en.php/.gitkeep
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.php
new file mode 100644
index 00000000..f2b06a91
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.php
@@ -0,0 +1,14 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12return array(
13 'Foo' => 'Bar',
14);
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.res b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.res
new file mode 100644
index 00000000..c78e9045
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.res
Binary files differ
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.txt b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.txt
new file mode 100644
index 00000000..c788e996
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/Fixtures/en.txt
@@ -0,0 +1,3 @@
1en{
2 Foo{"Bar"}
3}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/PhpBundleReaderTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/PhpBundleReaderTest.php
new file mode 100644
index 00000000..2fee3559
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/PhpBundleReaderTest.php
@@ -0,0 +1,63 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle\Reader;
13
14use Symfony\Component\Intl\ResourceBundle\Reader\PhpBundleReader;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class PhpBundleReaderTest extends \PHPUnit_Framework_TestCase
20{
21 /**
22 * @var PhpBundleReader
23 */
24 private $reader;
25
26 protected function setUp()
27 {
28 $this->reader = new PhpBundleReader();
29 }
30
31 public function testReadReturnsArray()
32 {
33 $data = $this->reader->read(__DIR__ . '/Fixtures', 'en');
34
35 $this->assertTrue(is_array($data));
36 $this->assertSame('Bar', $data['Foo']);
37 $this->assertFalse(isset($data['ExistsNot']));
38 }
39
40 /**
41 * @expectedException \Symfony\Component\Intl\Exception\InvalidArgumentException
42 */
43 public function testReadFailsIfLocaleOtherThanEn()
44 {
45 $this->reader->read(__DIR__ . '/Fixtures', 'foo');
46 }
47
48 /**
49 * @expectedException \Symfony\Component\Intl\Exception\RuntimeException
50 */
51 public function testReadFailsIfNonExistingDirectory()
52 {
53 $this->reader->read(__DIR__ . '/foo', 'en');
54 }
55
56 /**
57 * @expectedException \Symfony\Component\Intl\Exception\RuntimeException
58 */
59 public function testReadFailsIfNotAFile()
60 {
61 $this->reader->read(__DIR__ . '/Fixtures/NotAFile', 'en');
62 }
63}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/StructuredBundleReaderTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/StructuredBundleReaderTest.php
new file mode 100644
index 00000000..600236eb
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Reader/StructuredBundleReaderTest.php
@@ -0,0 +1,223 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle\Reader;
13
14use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReader;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class StructuredBundleReaderTest extends \PHPUnit_Framework_TestCase
20{
21 const RES_DIR = '/res/dir';
22
23 /**
24 * @var StructuredBundleReader
25 */
26 private $reader;
27
28 /**
29 * @var \PHPUnit_Framework_MockObject_MockObject
30 */
31 private $readerImpl;
32
33 protected function setUp()
34 {
35 $this->readerImpl = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
36 $this->reader = new StructuredBundleReader($this->readerImpl);
37 }
38
39 public function testGetLocales()
40 {
41 $locales = array('en', 'de', 'fr');
42
43 $this->readerImpl->expects($this->once())
44 ->method('getLocales')
45 ->with(self::RES_DIR)
46 ->will($this->returnValue($locales));
47
48 $this->assertSame($locales, $this->reader->getLocales(self::RES_DIR));
49 }
50
51 public function testRead()
52 {
53 $data = array('foo', 'bar');
54
55 $this->readerImpl->expects($this->once())
56 ->method('read')
57 ->with(self::RES_DIR, 'en')
58 ->will($this->returnValue($data));
59
60 $this->assertSame($data, $this->reader->read(self::RES_DIR, 'en'));
61 }
62
63 public function testReadEntryNoParams()
64 {
65 $data = array('foo', 'bar');
66
67 $this->readerImpl->expects($this->once())
68 ->method('read')
69 ->with(self::RES_DIR, 'en')
70 ->will($this->returnValue($data));
71
72 $this->assertSame($data, $this->reader->readEntry(self::RES_DIR, 'en', array()));
73 }
74
75 public function testReadEntryWithParam()
76 {
77 $data = array('Foo' => array('Bar' => 'Baz'));
78
79 $this->readerImpl->expects($this->once())
80 ->method('read')
81 ->with(self::RES_DIR, 'en')
82 ->will($this->returnValue($data));
83
84 $this->assertSame('Baz', $this->reader->readEntry(self::RES_DIR, 'en', array('Foo', 'Bar')));
85 }
86
87 public function testReadEntryWithUnresolvablePath()
88 {
89 $data = array('Foo' => 'Baz');
90
91 $this->readerImpl->expects($this->once())
92 ->method('read')
93 ->with(self::RES_DIR, 'en')
94 ->will($this->returnValue($data));
95
96 $this->assertNull($this->reader->readEntry(self::RES_DIR, 'en', array('Foo', 'Bar')));
97 }
98
99 public function readMergedEntryProvider()
100 {
101 return array(
102 array('foo', null, 'foo'),
103 array(null, 'foo', 'foo'),
104 array(array('foo', 'bar'), null, array('foo', 'bar')),
105 array(array('foo', 'bar'), array(), array('foo', 'bar')),
106 array(null, array('baz'), array('baz')),
107 array(array(), array('baz'), array('baz')),
108 array(array('foo', 'bar'), array('baz'), array('baz', 'foo', 'bar')),
109 );
110 }
111
112 /**
113 * @dataProvider readMergedEntryProvider
114 */
115 public function testReadMergedEntryNoParams($childData, $parentData, $result)
116 {
117 $this->readerImpl->expects($this->at(0))
118 ->method('read')
119 ->with(self::RES_DIR, 'en_GB')
120 ->will($this->returnValue($childData));
121
122 if (null === $childData || is_array($childData)) {
123 $this->readerImpl->expects($this->at(1))
124 ->method('read')
125 ->with(self::RES_DIR, 'en')
126 ->will($this->returnValue($parentData));
127 }
128
129 $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array(), true));
130 }
131
132 /**
133 * @dataProvider readMergedEntryProvider
134 */
135 public function testReadMergedEntryWithParams($childData, $parentData, $result)
136 {
137 $this->readerImpl->expects($this->at(0))
138 ->method('read')
139 ->with(self::RES_DIR, 'en_GB')
140 ->will($this->returnValue(array('Foo' => array('Bar' => $childData))));
141
142 if (null === $childData || is_array($childData)) {
143 $this->readerImpl->expects($this->at(1))
144 ->method('read')
145 ->with(self::RES_DIR, 'en')
146 ->will($this->returnValue(array('Foo' => array('Bar' => $parentData))));
147 }
148
149 $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
150 }
151
152 public function testReadMergedEntryWithUnresolvablePath()
153 {
154 $this->readerImpl->expects($this->at(0))
155 ->method('read')
156 ->with(self::RES_DIR, 'en_GB')
157 ->will($this->returnValue(array('Foo' => 'Baz')));
158
159 $this->readerImpl->expects($this->at(1))
160 ->method('read')
161 ->with(self::RES_DIR, 'en')
162 ->will($this->returnValue(array('Foo' => 'Bar')));
163
164 $this->assertNull($this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
165 }
166
167 public function testReadMergedEntryWithUnresolvablePathInParent()
168 {
169 $this->readerImpl->expects($this->at(0))
170 ->method('read')
171 ->with(self::RES_DIR, 'en_GB')
172 ->will($this->returnValue(array('Foo' => array('Bar' => array('three')))));
173
174 $this->readerImpl->expects($this->at(1))
175 ->method('read')
176 ->with(self::RES_DIR, 'en')
177 ->will($this->returnValue(array('Foo' => 'Bar')));
178
179 $result = array('three');
180
181 $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
182 }
183
184 public function testReadMergedEntryWithUnresolvablePathInChild()
185 {
186 $this->readerImpl->expects($this->at(0))
187 ->method('read')
188 ->with(self::RES_DIR, 'en_GB')
189 ->will($this->returnValue(array('Foo' => 'Baz')));
190
191 $this->readerImpl->expects($this->at(1))
192 ->method('read')
193 ->with(self::RES_DIR, 'en')
194 ->will($this->returnValue(array('Foo' => array('Bar' => array('one', 'two')))));
195
196 $result = array('one', 'two');
197
198 $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
199 }
200
201 /**
202 * @dataProvider readMergedEntryProvider
203 */
204 public function testReadMergedEntryWithTraversables($childData, $parentData, $result)
205 {
206 $parentData = is_array($parentData) ? new \ArrayObject($parentData) : $parentData;
207 $childData = is_array($childData) ? new \ArrayObject($childData) : $childData;
208
209 $this->readerImpl->expects($this->at(0))
210 ->method('read')
211 ->with(self::RES_DIR, 'en_GB')
212 ->will($this->returnValue(array('Foo' => array('Bar' => $childData))));
213
214 if (null === $childData || $childData instanceof \ArrayObject) {
215 $this->readerImpl->expects($this->at(1))
216 ->method('read')
217 ->with(self::RES_DIR, 'en')
218 ->will($this->returnValue(array('Foo' => array('Bar' => $parentData))));
219 }
220
221 $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
222 }
223}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/RegionBundleTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/RegionBundleTest.php
new file mode 100644
index 00000000..ccdf904c
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/RegionBundleTest.php
@@ -0,0 +1,63 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle;
13
14use Symfony\Component\Intl\ResourceBundle\RegionBundle;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class RegionBundleTest extends \PHPUnit_Framework_TestCase
20{
21 const RES_DIR = '/base/region';
22
23 /**
24 * @var RegionBundle
25 */
26 private $bundle;
27
28 /**
29 * @var \PHPUnit_Framework_MockObject_MockObject
30 */
31 private $reader;
32
33 protected function setUp()
34 {
35 $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
36 $this->bundle = new RegionBundle(self::RES_DIR, $this->reader);
37 }
38
39 public function testGetCountryName()
40 {
41 $this->reader->expects($this->once())
42 ->method('readEntry')
43 ->with(self::RES_DIR, 'en', array('Countries', 'AT'))
44 ->will($this->returnValue('Austria'));
45
46 $this->assertSame('Austria', $this->bundle->getCountryName('AT', 'en'));
47 }
48
49 public function testGetCountryNames()
50 {
51 $sortedCountries = array(
52 'AT' => 'Austria',
53 'DE' => 'Germany',
54 );
55
56 $this->reader->expects($this->once())
57 ->method('readEntry')
58 ->with(self::RES_DIR, 'en', array('Countries'))
59 ->will($this->returnValue($sortedCountries));
60
61 $this->assertSame($sortedCountries, $this->bundle->getCountryNames('en'));
62 }
63}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Util/RingBufferTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Util/RingBufferTest.php
new file mode 100644
index 00000000..d6f7d8a0
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Util/RingBufferTest.php
@@ -0,0 +1,101 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle\Util;
13
14use Symfony\Component\Intl\ResourceBundle\Util\RingBuffer;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class RingBufferTest extends \PHPUnit_Framework_TestCase
20{
21 /**
22 * @var RingBuffer
23 */
24 private $buffer;
25
26 protected function setUp()
27 {
28 $this->buffer = new RingBuffer(2);
29 }
30
31 public function testWriteWithinBuffer()
32 {
33 $this->buffer[0] = 'foo';
34 $this->buffer['bar'] = 'baz';
35
36 $this->assertTrue(isset($this->buffer[0]));
37 $this->assertTrue(isset($this->buffer['bar']));
38 $this->assertSame('foo', $this->buffer[0]);
39 $this->assertSame('baz', $this->buffer['bar']);
40 }
41
42 public function testWritePastBuffer()
43 {
44 $this->buffer[0] = 'foo';
45 $this->buffer['bar'] = 'baz';
46 $this->buffer[2] = 'bam';
47
48 $this->assertTrue(isset($this->buffer['bar']));
49 $this->assertTrue(isset($this->buffer[2]));
50 $this->assertSame('baz', $this->buffer['bar']);
51 $this->assertSame('bam', $this->buffer[2]);
52 }
53
54 /**
55 * @expectedException \Symfony\Component\Intl\Exception\OutOfBoundsException
56 */
57 public function testReadNonExistingFails()
58 {
59 $this->buffer['foo'];
60 }
61
62 public function testQueryNonExisting()
63 {
64 $this->assertFalse(isset($this->buffer['foo']));
65 }
66
67 public function testUnsetNonExistingSucceeds()
68 {
69 unset($this->buffer['foo']);
70
71 $this->assertFalse(isset($this->buffer['foo']));
72 }
73
74 /**
75 * @expectedException \Symfony\Component\Intl\Exception\OutOfBoundsException
76 */
77 public function testReadOverwrittenFails()
78 {
79 $this->buffer[0] = 'foo';
80 $this->buffer['bar'] = 'baz';
81 $this->buffer[2] = 'bam';
82
83 $this->buffer[0];
84 }
85
86 public function testQueryOverwritten()
87 {
88 $this->assertFalse(isset($this->buffer[0]));
89 }
90
91 public function testUnsetOverwrittenSucceeds()
92 {
93 $this->buffer[0] = 'foo';
94 $this->buffer['bar'] = 'baz';
95 $this->buffer[2] = 'bam';
96
97 unset($this->buffer[0]);
98
99 $this->assertFalse(isset($this->buffer[0]));
100 }
101}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.php
new file mode 100644
index 00000000..1ded57a7
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12return array(
13 'Entry1' => array(
14 'Array' => array(
15 0 => 'foo',
16 1 => 'bar',
17 ),
18 'Integer' => 5,
19 'Boolean' => false,
20 'Float' => 1.23,
21 ),
22 'Entry2' => 'String',
23);
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.res b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.res
new file mode 100644
index 00000000..7c1f71eb
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.res
Binary files differ
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.txt b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.txt
new file mode 100644
index 00000000..0ee0d7f2
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/Fixtures/en.txt
@@ -0,0 +1,23 @@
1en{
2 Entry1{
3 Array{
4 "foo",
5 "bar",
6 {
7 Key{"value"}
8 },
9 }
10 Integer:int{5}
11 IntVector:intvector{
12 0,
13 1,
14 2,
15 3,
16 }
17 FalseBoolean{"false"}
18 TrueBoolean{"true"}
19 Null{""}
20 Float{"1.23"}
21 }
22 Entry2{"String"}
23}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/PhpBundleWriterTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/PhpBundleWriterTest.php
new file mode 100644
index 00000000..03302834
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/PhpBundleWriterTest.php
@@ -0,0 +1,62 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle\Writer;
13
14use Symfony\Component\Filesystem\Filesystem;
15use Symfony\Component\Intl\ResourceBundle\Writer\PhpBundleWriter;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class PhpBundleWriterTest extends \PHPUnit_Framework_TestCase
21{
22 /**
23 * @var PhpBundleWriter
24 */
25 private $writer;
26
27 private $directory;
28
29 /**
30 * @var Filesystem
31 */
32 private $filesystem;
33
34 protected function setUp()
35 {
36 $this->writer = new PhpBundleWriter();
37 $this->directory = sys_get_temp_dir() . '/PhpBundleWriterTest/' . rand(1000, 9999);
38 $this->filesystem = new Filesystem();
39
40 $this->filesystem->mkdir($this->directory);
41 }
42
43 protected function tearDown()
44 {
45 $this->filesystem->remove($this->directory);
46 }
47
48 public function testWrite()
49 {
50 $this->writer->write($this->directory, 'en', array(
51 'Entry1' => array(
52 'Array' => array('foo', 'bar'),
53 'Integer' => 5,
54 'Boolean' => false,
55 'Float' => 1.23,
56 ),
57 'Entry2' => 'String',
58 ));
59
60 $this->assertFileEquals(__DIR__ . '/Fixtures/en.php', $this->directory . '/en.php');
61 }
62}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/TextBundleWriterTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/TextBundleWriterTest.php
new file mode 100644
index 00000000..cbe0c8d8
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/ResourceBundle/Writer/TextBundleWriterTest.php
@@ -0,0 +1,67 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\ResourceBundle\Writer;
13
14use Symfony\Component\Filesystem\Filesystem;
15use Symfony\Component\Intl\ResourceBundle\Writer\TextBundleWriter;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 *
20 * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
21 */
22class TextBundleWriterTest extends \PHPUnit_Framework_TestCase
23{
24 /**
25 * @var TextBundleWriter
26 */
27 private $writer;
28
29 private $directory;
30
31 /**
32 * @var Filesystem
33 */
34 private $filesystem;
35
36 protected function setUp()
37 {
38 $this->writer = new TextBundleWriter();
39 $this->directory = sys_get_temp_dir() . '/TextBundleWriterTest/' . rand(1000, 9999);
40 $this->filesystem = new Filesystem();
41
42 $this->filesystem->mkdir($this->directory);
43 }
44
45 protected function tearDown()
46 {
47 $this->filesystem->remove($this->directory);
48 }
49
50 public function testWrite()
51 {
52 $this->writer->write($this->directory, 'en', array(
53 'Entry1' => array(
54 'Array' => array('foo', 'bar', array('Key' => 'value')),
55 'Integer' => 5,
56 'IntVector' => array(0, 1, 2, 3),
57 'FalseBoolean' => false,
58 'TrueBoolean' => true,
59 'Null' => null,
60 'Float' => 1.23,
61 ),
62 'Entry2' => 'String',
63 ));
64
65 $this->assertFileEquals(__DIR__ . '/Fixtures/en.txt', $this->directory . '/en.txt');
66 }
67}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Util/IcuVersionTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Util/IcuVersionTest.php
new file mode 100644
index 00000000..d1a7e8c1
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Util/IcuVersionTest.php
@@ -0,0 +1,111 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Util;
13
14use Symfony\Component\Intl\Util\IcuVersion;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class IcuVersionTest extends \PHPUnit_Framework_TestCase
20{
21 public function normalizeProvider()
22 {
23 return array(
24 array(null, '1', '10'),
25 array(null, '1.2', '12'),
26 array(null, '1.2.3', '12.3'),
27 array(null, '1.2.3.4', '12.3.4'),
28 array(1, '1', '10'),
29 array(1, '1.2', '12'),
30 array(1, '1.2.3', '12'),
31 array(1, '1.2.3.4', '12'),
32 array(2, '1', '10'),
33 array(2, '1.2', '12'),
34 array(2, '1.2.3', '12.3'),
35 array(2, '1.2.3.4', '12.3'),
36 array(3, '1', '10'),
37 array(3, '1.2', '12'),
38 array(3, '1.2.3', '12.3'),
39 array(3, '1.2.3.4', '12.3.4'),
40 );
41 }
42
43 /**
44 * @dataProvider normalizeProvider
45 */
46 public function testNormalize($precision, $version, $result)
47 {
48 $this->assertSame($result, IcuVersion::normalize($version, $precision));
49 }
50
51 public function compareProvider()
52 {
53 return array(
54 array(null, '1', '==', '1', true),
55 array(null, '1.0', '==', '1.1', false),
56 array(null, '1.0.0', '==', '1.0.1', false),
57 array(null, '1.0.0.0', '==', '1.0.0.1', false),
58 array(null, '1.0.0.0.0', '==', '1.0.0.0.1', false),
59
60 array(null, '1', '==', '10', true),
61 array(null, '1.0', '==', '11', false),
62 array(null, '1.0.0', '==', '10.1', false),
63 array(null, '1.0.0.0', '==', '10.0.1', false),
64 array(null, '1.0.0.0.0', '==', '10.0.0.1', false),
65
66 array(1, '1', '==', '1', true),
67 array(1, '1.0', '==', '1.1', false),
68 array(1, '1.0.0', '==', '1.0.1', true),
69 array(1, '1.0.0.0', '==', '1.0.0.1', true),
70 array(1, '1.0.0.0.0', '==', '1.0.0.0.1', true),
71
72 array(1, '1', '==', '10', true),
73 array(1, '1.0', '==', '11', false),
74 array(1, '1.0.0', '==', '10.1', true),
75 array(1, '1.0.0.0', '==', '10.0.1', true),
76 array(1, '1.0.0.0.0', '==', '10.0.0.1', true),
77
78 array(2, '1', '==', '1', true),
79 array(2, '1.0', '==', '1.1', false),
80 array(2, '1.0.0', '==', '1.0.1', false),
81 array(2, '1.0.0.0', '==', '1.0.0.1', true),
82 array(2, '1.0.0.0.0', '==', '1.0.0.0.1', true),
83
84 array(2, '1', '==', '10', true),
85 array(2, '1.0', '==', '11', false),
86 array(2, '1.0.0', '==', '10.1', false),
87 array(2, '1.0.0.0', '==', '10.0.1', true),
88 array(2, '1.0.0.0.0', '==', '10.0.0.1', true),
89
90 array(3, '1', '==', '1', true),
91 array(3, '1.0', '==', '1.1', false),
92 array(3, '1.0.0', '==', '1.0.1', false),
93 array(3, '1.0.0.0', '==', '1.0.0.1', false),
94 array(3, '1.0.0.0.0', '==', '1.0.0.0.1', true),
95
96 array(3, '1', '==', '10', true),
97 array(3, '1.0', '==', '11', false),
98 array(3, '1.0.0', '==', '10.1', false),
99 array(3, '1.0.0.0', '==', '10.0.1', false),
100 array(3, '1.0.0.0.0', '==', '10.0.0.1', true),
101 );
102 }
103
104 /**
105 * @dataProvider compareProvider
106 */
107 public function testCompare($precision, $version1, $operator, $version2, $result)
108 {
109 $this->assertSame($result, IcuVersion::compare($version1, $version2, $operator, $precision));
110 }
111}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Tests/Util/VersionTest.php b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Util/VersionTest.php
new file mode 100644
index 00000000..60cec6c0
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Tests/Util/VersionTest.php
@@ -0,0 +1,87 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Tests\Util;
13
14use Symfony\Component\Intl\Util\Version;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class VersionTest extends \PHPUnit_Framework_TestCase
20{
21 public function normalizeProvider()
22 {
23 return array(
24 array(null, '1', '1'),
25 array(null, '1.2', '1.2'),
26 array(null, '1.2.3', '1.2.3'),
27 array(null, '1.2.3.4', '1.2.3.4'),
28 array(1, '1', '1'),
29 array(1, '1.2', '1'),
30 array(1, '1.2.3', '1'),
31 array(1, '1.2.3.4', '1'),
32 array(2, '1', '1'),
33 array(2, '1.2', '1.2'),
34 array(2, '1.2.3', '1.2'),
35 array(2, '1.2.3.4', '1.2'),
36 array(3, '1', '1'),
37 array(3, '1.2', '1.2'),
38 array(3, '1.2.3', '1.2.3'),
39 array(3, '1.2.3.4', '1.2.3'),
40 array(4, '1', '1'),
41 array(4, '1.2', '1.2'),
42 array(4, '1.2.3', '1.2.3'),
43 array(4, '1.2.3.4', '1.2.3.4'),
44 );
45 }
46
47 /**
48 * @dataProvider normalizeProvider
49 */
50 public function testNormalize($precision, $version, $result)
51 {
52 $this->assertSame($result, Version::normalize($version, $precision));
53 }
54
55 public function compareProvider()
56 {
57 return array(
58 array(null, '1', '==', '1', true),
59 array(null, '1.0', '==', '1.1', false),
60 array(null, '1.0.0', '==', '1.0.1', false),
61 array(null, '1.0.0.0', '==', '1.0.0.1', false),
62
63 array(1, '1', '==', '1', true),
64 array(1, '1.0', '==', '1.1', true),
65 array(1, '1.0.0', '==', '1.0.1', true),
66 array(1, '1.0.0.0', '==', '1.0.0.1', true),
67
68 array(2, '1', '==', '1', true),
69 array(2, '1.0', '==', '1.1', false),
70 array(2, '1.0.0', '==', '1.0.1', true),
71 array(2, '1.0.0.0', '==', '1.0.0.1', true),
72
73 array(3, '1', '==', '1', true),
74 array(3, '1.0', '==', '1.1', false),
75 array(3, '1.0.0', '==', '1.0.1', false),
76 array(3, '1.0.0.0', '==', '1.0.0.1', true),
77 );
78 }
79
80 /**
81 * @dataProvider compareProvider
82 */
83 public function testCompare($precision, $version1, $operator, $version2, $result)
84 {
85 $this->assertSame($result, Version::compare($version1, $version2, $operator, $precision));
86 }
87}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Util/IcuVersion.php b/vendor/symfony/intl/Symfony/Component/Intl/Util/IcuVersion.php
new file mode 100644
index 00000000..e305a075
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Util/IcuVersion.php
@@ -0,0 +1,105 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Util;
13
14/**
15 * Facilitates the comparison of ICU version strings.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class IcuVersion
20{
21 /**
22 * Compares two ICU versions with an operator.
23 *
24 * This method is identical to {@link version_compare()}, except that you
25 * can pass the number of regarded version components in the last argument
26 * $precision.
27 *
28 * Also, a single digit release version and a single digit major version
29 * are contracted to a two digit release version. If no major version
30 * is given, it is substituted by zero.
31 *
32 * Examples:
33 *
34 * IcuVersion::compare('1.2.3', '1.2.4', '==')
35 * // => false
36 *
37 * IcuVersion::compare('1.2.3', '1.2.4', '==', 2)
38 * // => true
39 *
40 * IcuVersion::compare('1.2.3', '12.3', '==')
41 * // => true
42 *
43 * IcuVersion::compare('1', '10', '==')
44 * // => true
45 *
46 * @param string $version1 A version string.
47 * @param string $version2 A version string to compare.
48 * @param string $operator The comparison operator.
49 * @param integer|null $precision The number of components to compare. Pass
50 * NULL to compare the versions unchanged.
51 *
52 * @return Boolean Whether the comparison succeeded.
53 *
54 * @see normalize()
55 */
56 public static function compare($version1, $version2, $operator, $precision = null)
57 {
58 $version1 = self::normalize($version1, $precision);
59 $version2 = self::normalize($version2, $precision);
60
61 return version_compare($version1, $version2, $operator);
62 }
63
64 /**
65 * Normalizes a version string to the number of components given in the
66 * parameter $precision.
67 *
68 * A single digit release version and a single digit major version are
69 * contracted to a two digit release version. If no major version is given,
70 * it is substituted by zero.
71 *
72 * Examples:
73 *
74 * IcuVersion::normalize('1.2.3.4');
75 * // => '12.3.4'
76 *
77 * IcuVersion::normalize('1.2.3.4', 1);
78 * // => '12'
79 *
80 * IcuVersion::normalize('1.2.3.4', 2);
81 * // => '12.3'
82 *
83 * @param string $version An ICU version string.
84 * @param integer|null $precision The number of components to include. Pass
85 * NULL to return the version unchanged.
86 *
87 * @return string|null The normalized ICU version or NULL if it couldn't be
88 * normalized.
89 */
90 public static function normalize($version, $precision)
91 {
92 $version = preg_replace('/^(\d)\.(\d)/', '$1$2', $version);
93
94 if (1 === strlen($version)) {
95 $version .= '0';
96 }
97
98 return Version::normalize($version, $precision);
99 }
100
101 /**
102 * Must not be instantiated.
103 */
104 private function __construct() {}
105}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Util/IntlTestHelper.php b/vendor/symfony/intl/Symfony/Component/Intl/Util/IntlTestHelper.php
new file mode 100644
index 00000000..cace36c6
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Util/IntlTestHelper.php
@@ -0,0 +1,128 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Util;
13
14use Symfony\Component\Intl\Intl;
15
16/**
17 * Helper class for preparing test cases that rely on the Intl component.
18 *
19 * Any test that tests functionality relying on either the intl classes or
20 * the resource bundle data should call either of the methods
21 * {@link requireIntl()} or {@link requireFullIntl()}. Calling
22 * {@link requireFullIntl()} is only necessary if you use functionality in the
23 * test that is not provided by the stub intl implementation.
24 *
25 * @author Bernhard Schussek <bschussek@gmail.com>
26 */
27class IntlTestHelper
28{
29 /**
30 * Should be called before tests that work fine with the stub implementation.
31 *
32 * @param \PhpUnit_Framework_TestCase $testCase
33 */
34 public static function requireIntl(\PhpUnit_Framework_TestCase $testCase)
35 {
36 // We only run tests if the version is *one specific version*.
37 // This condition is satisfied if
38 //
39 // * the intl extension is loaded with version Intl::getIcuStubVersion()
40 // * the intl extension is not loaded
41
42 if (IcuVersion::compare(Intl::getIcuVersion(), Intl::getIcuStubVersion(), '!=', 1)) {
43 $testCase->markTestSkipped('Please change ICU version to ' . Intl::getIcuStubVersion());
44 }
45
46 if (IcuVersion::compare(Intl::getIcuDataVersion(), Intl::getIcuStubVersion(), '!=', 1)) {
47 $testCase->markTestSkipped('Please change the Icu component to version 1.0.x or 1.' . IcuVersion::normalize(Intl::getIcuStubVersion(), 1) . '.x');
48 }
49
50 // Normalize the default locale in case this is not done explicitly
51 // in the test
52 \Locale::setDefault('en');
53
54 // Consequently, tests will
55 //
56 // * run only for one ICU version (see Intl::getIcuStubVersion())
57 // there is no need to add control structures to your tests that
58 // change the test depending on the ICU version.
59 //
60 // Tests should only rely on functionality that is implemented in the
61 // stub classes.
62 }
63
64 /**
65 * Should be called before tests that require a feature-complete intl
66 * implementation.
67 *
68 * @param \PhpUnit_Framework_TestCase $testCase
69 */
70 public static function requireFullIntl(\PhpUnit_Framework_TestCase $testCase)
71 {
72 // We only run tests if the intl extension is loaded...
73 if (!Intl::isExtensionLoaded()) {
74 $testCase->markTestSkipped('The intl extension is not available.');
75 }
76
77 // ... and only if the version is *one specific version* ...
78 if (IcuVersion::compare(Intl::getIcuVersion(), Intl::getIcuStubVersion(), '!=', 1)) {
79 $testCase->markTestSkipped('Please change ICU version to ' . Intl::getIcuStubVersion());
80 }
81
82 // ... and only if the data in the Icu component matches that version.
83 if (IcuVersion::compare(Intl::getIcuDataVersion(), Intl::getIcuStubVersion(), '!=', 1)) {
84 $testCase->markTestSkipped('Please change the Icu component to version 1.0.x or 1.' . IcuVersion::normalize(Intl::getIcuStubVersion(), 1) . '.x');
85 }
86
87 // Normalize the default locale in case this is not done explicitly
88 // in the test
89 \Locale::setDefault('en');
90
91 // Consequently, tests will
92 //
93 // * run only for one ICU version (see Intl::getIcuStubVersion())
94 // there is no need to add control structures to your tests that
95 // change the test depending on the ICU version.
96 // * always use the C intl classes
97 // * always use the binary resource bundles (any locale is allowed)
98 }
99
100 /**
101 * Skips the test unless the current system has a 32bit architecture.
102 *
103 * @param \PhpUnit_Framework_TestCase $testCase
104 */
105 public static function require32Bit(\PhpUnit_Framework_TestCase $testCase)
106 {
107 if (4 !== PHP_INT_SIZE) {
108 $testCase->markTestSkipped('PHP must be compiled in 32 bit mode to run this test');
109 }
110 }
111
112 /**
113 * Skips the test unless the current system has a 64bit architecture.
114 *
115 * @param \PhpUnit_Framework_TestCase $testCase
116 */
117 public static function require64Bit(\PhpUnit_Framework_TestCase $testCase)
118 {
119 if (8 !== PHP_INT_SIZE) {
120 $testCase->markTestSkipped('PHP must be compiled in 64 bit mode to run this test');
121 }
122 }
123
124 /**
125 * Must not be instantiated.
126 */
127 private function __construct() {}
128}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Util/SvnCommit.php b/vendor/symfony/intl/Symfony/Component/Intl/Util/SvnCommit.php
new file mode 100644
index 00000000..483d92bc
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Util/SvnCommit.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Util;
13
14/**
15 * An SVN commit.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class SvnCommit
20{
21 /**
22 * @var \SimpleXMLElement
23 */
24 private $svnInfo;
25
26 /**
27 * Creates a commit from the given "svn info" data.
28 *
29 * @param \SimpleXMLElement $svnInfo The XML result from the "svn info"
30 * command.
31 */
32 public function __construct(\SimpleXMLElement $svnInfo)
33 {
34 $this->svnInfo = $svnInfo;
35 }
36
37 /**
38 * Returns the revision of the commit.
39 *
40 * @return string The revision of the commit.
41 */
42 public function getRevision()
43 {
44 return (string) $this->svnInfo['revision'];
45 }
46
47 /**
48 * Returns the author of the commit.
49 *
50 * @return string The author name.
51 */
52 public function getAuthor()
53 {
54 return (string) $this->svnInfo->author;
55 }
56
57 /**
58 * Returns the date of the commit.
59 *
60 * @return string The commit date.
61 */
62 public function getDate()
63 {
64 return (string) $this->svnInfo->date;
65 }
66}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Util/SvnRepository.php b/vendor/symfony/intl/Symfony/Component/Intl/Util/SvnRepository.php
new file mode 100644
index 00000000..fb44e3c6
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Util/SvnRepository.php
@@ -0,0 +1,141 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Util;
13
14use Symfony\Component\Filesystem\Filesystem;
15use Symfony\Component\Intl\Exception\RuntimeException;
16
17/**
18 * A SVN repository containing ICU data.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class SvnRepository
23{
24 /**
25 * @var string The path to the repository.
26 */
27 private $path;
28
29 /**
30 * @var \SimpleXMLElement
31 */
32 private $svnInfo;
33
34 /**
35 * @var SvnCommit
36 */
37 private $lastCommit;
38
39 /**
40 * Downloads the ICU data for the given version.
41 *
42 * @param string $url The URL to download from.
43 * @param string $targetDir The directory in which to store the repository.
44 *
45 * @return SvnRepository The directory where the data is stored.
46 *
47 * @throws RuntimeException If an error occurs during the download.
48 */
49 public static function download($url, $targetDir)
50 {
51 exec('which svn', $output, $result);
52
53 if ($result !== 0) {
54 throw new RuntimeException('The command "svn" is not installed.');
55 }
56
57 $filesystem = new Filesystem();
58
59 if (!$filesystem->exists($targetDir . '/.svn')) {
60 $filesystem->remove($targetDir);
61 $filesystem->mkdir($targetDir);
62
63 exec('svn checkout ' . $url . ' ' . $targetDir, $output, $result);
64
65 if ($result !== 0) {
66 throw new RuntimeException('The SVN checkout of ' . $url . 'failed.');
67 }
68 }
69
70 return new static(realpath($targetDir));
71 }
72
73 /**
74 * Reads the SVN repository at the given path.
75 *
76 * @param string $path The path to the repository.
77 */
78 public function __construct($path)
79 {
80 $this->path = $path;
81 }
82
83 /**
84 * Returns the path to the repository.
85 *
86 * @return string The path to the repository.
87 */
88 public function getPath()
89 {
90 return $this->path;
91 }
92
93 /**
94 * Returns the URL of the repository.
95 *
96 * @return string The URL of the repository.
97 */
98 public function getUrl()
99 {
100 return (string) $this->getSvnInfo()->entry->url;
101 }
102
103 /**
104 * Returns the last commit of the repository.
105 *
106 * @return SvnCommit The last commit.
107 */
108 public function getLastCommit()
109 {
110 if (null === $this->lastCommit) {
111 $this->lastCommit = new SvnCommit($this->getSvnInfo()->entry->commit);
112 }
113
114 return $this->lastCommit;
115 }
116
117 /**
118 * Returns information about the SVN repository.
119 *
120 * @return \SimpleXMLElement The XML result from the "svn info" command.
121 *
122 * @throws RuntimeException If the "svn info" command failed.
123 */
124 private function getSvnInfo()
125 {
126 if (null === $this->svnInfo) {
127 exec('svn info --xml '.$this->path, $output, $result);
128
129 $svnInfo = simplexml_load_string(implode("\n", $output));
130
131 if ($result !== 0) {
132 throw new RuntimeException('svn info failed');
133 }
134
135 $this->svnInfo = $svnInfo;
136 }
137
138 return $this->svnInfo;
139 }
140
141}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/Util/Version.php b/vendor/symfony/intl/Symfony/Component/Intl/Util/Version.php
new file mode 100644
index 00000000..5f6a4337
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/Util/Version.php
@@ -0,0 +1,96 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Intl\Util;
13
14/**
15 * Facilitates the comparison of version strings.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class Version
20{
21 /**
22 * Compares two versions with an operator.
23 *
24 * This method is identical to {@link version_compare()}, except that you
25 * can pass the number of regarded version components in the last argument
26 * $precision.
27 *
28 * Examples:
29 *
30 * Version::compare('1.2.3', '1.2.4', '==')
31 * // => false
32 *
33 * Version::compare('1.2.3', '1.2.4', '==', 2)
34 * // => true
35 *
36 * @param string $version1 A version string.
37 * @param string $version2 A version string to compare.
38 * @param string $operator The comparison operator.
39 * @param integer|null $precision The number of components to compare. Pass
40 * NULL to compare the versions unchanged.
41 *
42 * @return Boolean Whether the comparison succeeded.
43 *
44 * @see normalize()
45 */
46 public static function compare($version1, $version2, $operator, $precision = null)
47 {
48 $version1 = self::normalize($version1, $precision);
49 $version2 = self::normalize($version2, $precision);
50
51 return version_compare($version1, $version2, $operator);
52 }
53
54 /**
55 * Normalizes a version string to the number of components given in the
56 * parameter $precision.
57 *
58 * Examples:
59 *
60 * Version::normalize('1.2.3', 1);
61 * // => '1'
62 *
63 * Version::normalize('1.2.3', 2);
64 * // => '1.2'
65 *
66 * @param string $version A version string.
67 * @param integer|null $precision The number of components to include. Pass
68 * NULL to return the version unchanged.
69 *
70 * @return string|null The normalized version or NULL if it couldn't be
71 * normalized.
72 */
73 public static function normalize($version, $precision)
74 {
75 if (null === $precision) {
76 return $version;
77 }
78
79 $pattern = '[^\.]+';
80
81 for ($i = 2; $i <= $precision; ++$i) {
82 $pattern = sprintf('[^\.]+(\.%s)?', $pattern);
83 }
84
85 if (!preg_match('/^' . $pattern . '/', $version, $matches)) {
86 return null;
87 }
88
89 return $matches[0];
90 }
91
92 /**
93 * Must not be instantiated.
94 */
95 private function __construct() {}
96}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/composer.json b/vendor/symfony/intl/Symfony/Component/Intl/composer.json
new file mode 100644
index 00000000..29eedfa1
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/composer.json
@@ -0,0 +1,48 @@
1{
2 "name": "symfony/intl",
3 "type": "library",
4 "description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.",
5 "keywords": ["intl", "icu", "internationalization", "localization", "i18n", "l10n"],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Bernhard Schussek",
11 "email": "bschussek@gmail.com"
12 },
13 {
14 "name": "Eriksen Costa",
15 "email": "eriksen.costa@infranology.com.br"
16 },
17 {
18 "name": "Igor Wiedler",
19 "email": "igor@wiedler.ch"
20 },
21 {
22 "name": "Symfony Community",
23 "homepage": "http://symfony.com/contributors"
24 }
25 ],
26 "require": {
27 "php": ">=5.3.3",
28 "symfony/icu": "~1.0-RC"
29 },
30 "require-dev": {
31 "symfony/filesystem": ">=2.1"
32 },
33 "suggest": {
34 "ext-intl": "to use the component with locales other than \"en\""
35 },
36 "autoload": {
37 "psr-0": { "Symfony\\Component\\Intl\\": "" },
38 "classmap": [ "Symfony/Component/Intl/Resources/stubs" ],
39 "files": [ "Symfony/Component/Intl/Resources/stubs/functions.php" ]
40 },
41 "target-dir": "Symfony/Component/Intl",
42 "minimum-stability": "dev",
43 "extra": {
44 "branch-alias": {
45 "dev-master": "2.3-dev"
46 }
47 }
48}
diff --git a/vendor/symfony/intl/Symfony/Component/Intl/phpunit.xml.dist b/vendor/symfony/intl/Symfony/Component/Intl/phpunit.xml.dist
new file mode 100644
index 00000000..5e709f13
--- /dev/null
+++ b/vendor/symfony/intl/Symfony/Component/Intl/phpunit.xml.dist
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony Intl Component Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./Tests</directory>
25 <directory>./vendor</directory>
26 </exclude>
27 </whitelist>
28 </filter>
29</phpunit>
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/.gitignore b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/.gitignore
new file mode 100644
index 00000000..44de97a3
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/.gitignore
@@ -0,0 +1,4 @@
1vendor/
2composer.lock
3phpunit.xml
4
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/ExceptionInterface.php b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..4224f4e3
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/ExceptionInterface.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\OptionsResolver\Exception;
13
14/**
15 * Marker interface for the Options component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface ExceptionInterface
20{
21}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/InvalidOptionsException.php b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/InvalidOptionsException.php
new file mode 100644
index 00000000..2e7ea1bc
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/InvalidOptionsException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\OptionsResolver\Exception;
13
14/**
15 * Exception thrown when an invalid option is passed.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class InvalidOptionsException extends \InvalidArgumentException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/MissingOptionsException.php b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/MissingOptionsException.php
new file mode 100644
index 00000000..8544dfb2
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/MissingOptionsException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\OptionsResolver\Exception;
13
14/**
15 * Exception thrown when a required option is missing.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class MissingOptionsException extends \InvalidArgumentException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/OptionDefinitionException.php b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/OptionDefinitionException.php
new file mode 100644
index 00000000..11617fe1
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Exception/OptionDefinitionException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\OptionsResolver\Exception;
13
14/**
15 * Thrown when an option definition is invalid.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class OptionDefinitionException extends \RuntimeException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/LICENSE b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Options.php b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Options.php
new file mode 100644
index 00000000..5b958af4
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Options.php
@@ -0,0 +1,513 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\OptionsResolver;
13
14use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException;
15
16/**
17 * Container for resolving inter-dependent options.
18 *
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class Options implements \ArrayAccess, \Iterator, \Countable
22{
23 /**
24 * A list of option values.
25 * @var array
26 */
27 private $options = array();
28
29 /**
30 * A list of normalizer closures.
31 * @var array
32 */
33 private $normalizers = array();
34
35 /**
36 * A list of closures for evaluating lazy options.
37 * @var array
38 */
39 private $lazy = array();
40
41 /**
42 * A list containing the currently locked options.
43 * @var array
44 */
45 private $lock = array();
46
47 /**
48 * Whether at least one option has already been read.
49 *
50 * Once read, the options cannot be changed anymore. This is
51 * necessary in order to avoid inconsistencies during the resolving
52 * process. If any option is changed after being read, all evaluated
53 * lazy options that depend on this option would become invalid.
54 *
55 * @var Boolean
56 */
57 private $reading = false;
58
59 /**
60 * Sets the value of a given option.
61 *
62 * You can set lazy options by passing a closure with the following
63 * signature:
64 *
65 * <code>
66 * function (Options $options)
67 * </code>
68 *
69 * This closure will be evaluated once the option is read using
70 * {@link get()}. The closure has access to the resolved values of
71 * other options through the passed {@link Options} instance.
72 *
73 * @param string $option The name of the option.
74 * @param mixed $value The value of the option.
75 *
76 * @throws OptionDefinitionException If options have already been read.
77 * Once options are read, the container
78 * becomes immutable.
79 */
80 public function set($option, $value)
81 {
82 // Setting is not possible once an option is read, because then lazy
83 // options could manipulate the state of the object, leading to
84 // inconsistent results.
85 if ($this->reading) {
86 throw new OptionDefinitionException('Options cannot be set anymore once options have been read.');
87 }
88
89 // Setting is equivalent to overloading while discarding the previous
90 // option value
91 unset($this->options[$option]);
92 unset($this->lazy[$option]);
93
94 $this->overload($option, $value);
95 }
96
97 /**
98 * Sets the normalizer for a given option.
99 *
100 * Normalizers should be closures with the following signature:
101 *
102 * <code>
103 * function (Options $options, $value)
104 * </code>
105 *
106 * This closure will be evaluated once the option is read using
107 * {@link get()}. The closure has access to the resolved values of
108 * other options through the passed {@link Options} instance.
109 *
110 * @param string $option The name of the option.
111 * @param \Closure $normalizer The normalizer.
112 *
113 * @throws OptionDefinitionException If options have already been read.
114 * Once options are read, the container
115 * becomes immutable.
116 */
117 public function setNormalizer($option, \Closure $normalizer)
118 {
119 if ($this->reading) {
120 throw new OptionDefinitionException('Normalizers cannot be added anymore once options have been read.');
121 }
122
123 $this->normalizers[$option] = $normalizer;
124 }
125
126 /**
127 * Replaces the contents of the container with the given options.
128 *
129 * This method is a shortcut for {@link clear()} with subsequent
130 * calls to {@link set()}.
131 *
132 * @param array $options The options to set.
133 *
134 * @throws OptionDefinitionException If options have already been read.
135 * Once options are read, the container
136 * becomes immutable.
137 */
138 public function replace(array $options)
139 {
140 if ($this->reading) {
141 throw new OptionDefinitionException('Options cannot be replaced anymore once options have been read.');
142 }
143
144 $this->options = array();
145 $this->lazy = array();
146 $this->normalizers = array();
147
148 foreach ($options as $option => $value) {
149 $this->overload($option, $value);
150 }
151 }
152
153 /**
154 * Overloads the value of a given option.
155 *
156 * Contrary to {@link set()}, this method keeps the previous default
157 * value of the option so that you can access it if you pass a closure.
158 * Passed closures should have the following signature:
159 *
160 * <code>
161 * function (Options $options, $value)
162 * </code>
163 *
164 * The second parameter passed to the closure is the current default
165 * value of the option.
166 *
167 * @param string $option The option name.
168 * @param mixed $value The option value.
169 *
170 * @throws OptionDefinitionException If options have already been read.
171 * Once options are read, the container
172 * becomes immutable.
173 */
174 public function overload($option, $value)
175 {
176 if ($this->reading) {
177 throw new OptionDefinitionException('Options cannot be overloaded anymore once options have been read.');
178 }
179
180 // If an option is a closure that should be evaluated lazily, store it
181 // in the "lazy" property.
182 if ($value instanceof \Closure) {
183 $reflClosure = new \ReflectionFunction($value);
184 $params = $reflClosure->getParameters();
185
186 if (isset($params[0]) && null !== ($class = $params[0]->getClass()) && __CLASS__ === $class->name) {
187 // Initialize the option if no previous value exists
188 if (!isset($this->options[$option])) {
189 $this->options[$option] = null;
190 }
191
192 // Ignore previous lazy options if the closure has no second parameter
193 if (!isset($this->lazy[$option]) || !isset($params[1])) {
194 $this->lazy[$option] = array();
195 }
196
197 // Store closure for later evaluation
198 $this->lazy[$option][] = $value;
199
200 return;
201 }
202 }
203
204 // Remove lazy options by default
205 unset($this->lazy[$option]);
206
207 $this->options[$option] = $value;
208 }
209
210 /**
211 * Returns the value of the given option.
212 *
213 * If the option was a lazy option, it is evaluated now.
214 *
215 * @param string $option The option name.
216 *
217 * @return mixed The option value.
218 *
219 * @throws \OutOfBoundsException If the option does not exist.
220 * @throws OptionDefinitionException If a cyclic dependency is detected
221 * between two lazy options.
222 */
223 public function get($option)
224 {
225 $this->reading = true;
226
227 if (!array_key_exists($option, $this->options)) {
228 throw new \OutOfBoundsException(sprintf('The option "%s" does not exist.', $option));
229 }
230
231 if (isset($this->lazy[$option])) {
232 $this->resolve($option);
233 }
234
235 if (isset($this->normalizers[$option])) {
236 $this->normalize($option);
237 }
238
239 return $this->options[$option];
240 }
241
242 /**
243 * Returns whether the given option exists.
244 *
245 * @param string $option The option name.
246 *
247 * @return Boolean Whether the option exists.
248 */
249 public function has($option)
250 {
251 return array_key_exists($option, $this->options);
252 }
253
254 /**
255 * Removes the option with the given name.
256 *
257 * @param string $option The option name.
258 *
259 * @throws OptionDefinitionException If options have already been read.
260 * Once options are read, the container
261 * becomes immutable.
262 */
263 public function remove($option)
264 {
265 if ($this->reading) {
266 throw new OptionDefinitionException('Options cannot be removed anymore once options have been read.');
267 }
268
269 unset($this->options[$option]);
270 unset($this->lazy[$option]);
271 unset($this->normalizers[$option]);
272 }
273
274 /**
275 * Removes all options.
276 *
277 * @throws OptionDefinitionException If options have already been read.
278 * Once options are read, the container
279 * becomes immutable.
280 */
281 public function clear()
282 {
283 if ($this->reading) {
284 throw new OptionDefinitionException('Options cannot be cleared anymore once options have been read.');
285 }
286
287 $this->options = array();
288 $this->lazy = array();
289 $this->normalizers = array();
290 }
291
292 /**
293 * Returns the values of all options.
294 *
295 * Lazy options are evaluated at this point.
296 *
297 * @return array The option values.
298 */
299 public function all()
300 {
301 $this->reading = true;
302
303 // Performance-wise this is slightly better than
304 // while (null !== $option = key($this->lazy))
305 foreach ($this->lazy as $option => $closures) {
306 // Double check, in case the option has already been resolved
307 // by cascade in the previous cycles
308 if (isset($this->lazy[$option])) {
309 $this->resolve($option);
310 }
311 }
312
313 foreach ($this->normalizers as $option => $normalizer) {
314 if (isset($this->normalizers[$option])) {
315 $this->normalize($option);
316 }
317 }
318
319 return $this->options;
320 }
321
322 /**
323 * Equivalent to {@link has()}.
324 *
325 * @param string $option The option name.
326 *
327 * @return Boolean Whether the option exists.
328 *
329 * @see \ArrayAccess::offsetExists()
330 */
331 public function offsetExists($option)
332 {
333 return $this->has($option);
334 }
335
336 /**
337 * Equivalent to {@link get()}.
338 *
339 * @param string $option The option name.
340 *
341 * @return mixed The option value.
342 *
343 * @throws \OutOfBoundsException If the option does not exist.
344 * @throws OptionDefinitionException If a cyclic dependency is detected
345 * between two lazy options.
346 *
347 * @see \ArrayAccess::offsetGet()
348 */
349 public function offsetGet($option)
350 {
351 return $this->get($option);
352 }
353
354 /**
355 * Equivalent to {@link set()}.
356 *
357 * @param string $option The name of the option.
358 * @param mixed $value The value of the option. May be a closure with a
359 * signature as defined in DefaultOptions::add().
360 *
361 * @throws OptionDefinitionException If options have already been read.
362 * Once options are read, the container
363 * becomes immutable.
364 *
365 * @see \ArrayAccess::offsetSet()
366 */
367 public function offsetSet($option, $value)
368 {
369 $this->set($option, $value);
370 }
371
372 /**
373 * Equivalent to {@link remove()}.
374 *
375 * @param string $option The option name.
376 *
377 * @throws OptionDefinitionException If options have already been read.
378 * Once options are read, the container
379 * becomes immutable.
380 *
381 * @see \ArrayAccess::offsetUnset()
382 */
383 public function offsetUnset($option)
384 {
385 $this->remove($option);
386 }
387
388 /**
389 * {@inheritdoc}
390 */
391 public function current()
392 {
393 return $this->get($this->key());
394 }
395
396 /**
397 * {@inheritdoc}
398 */
399 public function next()
400 {
401 next($this->options);
402 }
403
404 /**
405 * {@inheritdoc}
406 */
407 public function key()
408 {
409 return key($this->options);
410 }
411
412 /**
413 * {@inheritdoc}
414 */
415 public function valid()
416 {
417 return null !== $this->key();
418 }
419
420 /**
421 * {@inheritdoc}
422 */
423 public function rewind()
424 {
425 reset($this->options);
426 }
427
428 /**
429 * {@inheritdoc}
430 */
431 public function count()
432 {
433 return count($this->options);
434 }
435
436 /**
437 * Evaluates the given lazy option.
438 *
439 * The evaluated value is written into the options array. The closure for
440 * evaluating the option is discarded afterwards.
441 *
442 * @param string $option The option to evaluate.
443 *
444 * @throws OptionDefinitionException If the option has a cyclic dependency
445 * on another option.
446 */
447 private function resolve($option)
448 {
449 // The code duplication with normalize() exists for performance
450 // reasons, in order to save a method call.
451 // Remember that this method is potentially called a couple of thousand
452 // times and needs to be as efficient as possible.
453 if (isset($this->lock[$option])) {
454 $conflicts = array();
455
456 foreach ($this->lock as $option => $locked) {
457 if ($locked) {
458 $conflicts[] = $option;
459 }
460 }
461
462 throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', $conflicts)));
463 }
464
465 $this->lock[$option] = true;
466 foreach ($this->lazy[$option] as $closure) {
467 $this->options[$option] = $closure($this, $this->options[$option]);
468 }
469 unset($this->lock[$option]);
470
471 // The option now isn't lazy anymore
472 unset($this->lazy[$option]);
473 }
474
475 /**
476 * Normalizes the given option.
477 *
478 * The evaluated value is written into the options array.
479 *
480 * @param string $option The option to normalizer.
481 *
482 * @throws OptionDefinitionException If the option has a cyclic dependency
483 * on another option.
484 */
485 private function normalize($option)
486 {
487 // The code duplication with resolve() exists for performance
488 // reasons, in order to save a method call.
489 // Remember that this method is potentially called a couple of thousand
490 // times and needs to be as efficient as possible.
491 if (isset($this->lock[$option])) {
492 $conflicts = array();
493
494 foreach ($this->lock as $option => $locked) {
495 if ($locked) {
496 $conflicts[] = $option;
497 }
498 }
499
500 throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', $conflicts)));
501 }
502
503 /** @var \Closure $normalizer */
504 $normalizer = $this->normalizers[$option];
505
506 $this->lock[$option] = true;
507 $this->options[$option] = $normalizer($this, array_key_exists($option, $this->options) ? $this->options[$option] : null);
508 unset($this->lock[$option]);
509
510 // The option is now normalized
511 unset($this->normalizers[$option]);
512 }
513}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/OptionsResolver.php b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/OptionsResolver.php
new file mode 100644
index 00000000..d6554baa
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/OptionsResolver.php
@@ -0,0 +1,346 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\OptionsResolver;
13
14use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException;
15use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
16use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
17
18/**
19 * Helper for merging default and concrete option values.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 * @author Tobias Schultze <http://tobion.de>
23 */
24class OptionsResolver implements OptionsResolverInterface
25{
26 /**
27 * The default option values.
28 * @var Options
29 */
30 private $defaultOptions;
31
32 /**
33 * The options known by the resolver.
34 * @var array
35 */
36 private $knownOptions = array();
37
38 /**
39 * The options without defaults that are required to be passed to resolve().
40 * @var array
41 */
42 private $requiredOptions = array();
43
44 /**
45 * A list of accepted values for each option.
46 * @var array
47 */
48 private $allowedValues = array();
49
50 /**
51 * A list of accepted types for each option.
52 * @var array
53 */
54 private $allowedTypes = array();
55
56 /**
57 * Creates a new instance.
58 */
59 public function __construct()
60 {
61 $this->defaultOptions = new Options();
62 }
63
64 /**
65 * Clones the resolver.
66 */
67 public function __clone()
68 {
69 $this->defaultOptions = clone $this->defaultOptions;
70 }
71
72 /**
73 * {@inheritdoc}
74 */
75 public function setDefaults(array $defaultValues)
76 {
77 foreach ($defaultValues as $option => $value) {
78 $this->defaultOptions->overload($option, $value);
79 $this->knownOptions[$option] = true;
80 unset($this->requiredOptions[$option]);
81 }
82
83 return $this;
84 }
85
86 /**
87 * {@inheritdoc}
88 */
89 public function replaceDefaults(array $defaultValues)
90 {
91 foreach ($defaultValues as $option => $value) {
92 $this->defaultOptions->set($option, $value);
93 $this->knownOptions[$option] = true;
94 unset($this->requiredOptions[$option]);
95 }
96
97 return $this;
98 }
99
100 /**
101 * {@inheritdoc}
102 */
103 public function setOptional(array $optionNames)
104 {
105 foreach ($optionNames as $key => $option) {
106 if (!is_int($key)) {
107 throw new OptionDefinitionException('You should not pass default values to setOptional()');
108 }
109
110 $this->knownOptions[$option] = true;
111 }
112
113 return $this;
114 }
115
116 /**
117 * {@inheritdoc}
118 */
119 public function setRequired(array $optionNames)
120 {
121 foreach ($optionNames as $key => $option) {
122 if (!is_int($key)) {
123 throw new OptionDefinitionException('You should not pass default values to setRequired()');
124 }
125
126 $this->knownOptions[$option] = true;
127 // set as required if no default has been set already
128 if (!isset($this->defaultOptions[$option])) {
129 $this->requiredOptions[$option] = true;
130 }
131 }
132
133 return $this;
134 }
135
136 /**
137 * {@inheritdoc}
138 */
139 public function setAllowedValues(array $allowedValues)
140 {
141 $this->validateOptionsExistence($allowedValues);
142
143 $this->allowedValues = array_replace($this->allowedValues, $allowedValues);
144
145 return $this;
146 }
147
148 /**
149 * {@inheritdoc}
150 */
151 public function addAllowedValues(array $allowedValues)
152 {
153 $this->validateOptionsExistence($allowedValues);
154
155 $this->allowedValues = array_merge_recursive($this->allowedValues, $allowedValues);
156
157 return $this;
158 }
159
160 /**
161 * {@inheritdoc}
162 */
163 public function setAllowedTypes(array $allowedTypes)
164 {
165 $this->validateOptionsExistence($allowedTypes);
166
167 $this->allowedTypes = array_replace($this->allowedTypes, $allowedTypes);
168
169 return $this;
170 }
171
172 /**
173 * {@inheritdoc}
174 */
175 public function addAllowedTypes(array $allowedTypes)
176 {
177 $this->validateOptionsExistence($allowedTypes);
178
179 $this->allowedTypes = array_merge_recursive($this->allowedTypes, $allowedTypes);
180
181 return $this;
182 }
183
184 /**
185 * {@inheritdoc}
186 */
187 public function setNormalizers(array $normalizers)
188 {
189 $this->validateOptionsExistence($normalizers);
190
191 foreach ($normalizers as $option => $normalizer) {
192 $this->defaultOptions->setNormalizer($option, $normalizer);
193 }
194
195 return $this;
196 }
197
198 /**
199 * {@inheritdoc}
200 */
201 public function isKnown($option)
202 {
203 return isset($this->knownOptions[$option]);
204 }
205
206 /**
207 * {@inheritdoc}
208 */
209 public function isRequired($option)
210 {
211 return isset($this->requiredOptions[$option]);
212 }
213
214 /**
215 * {@inheritdoc}
216 */
217 public function resolve(array $options = array())
218 {
219 $this->validateOptionsExistence($options);
220 $this->validateOptionsCompleteness($options);
221
222 // Make sure this method can be called multiple times
223 $combinedOptions = clone $this->defaultOptions;
224
225 // Override options set by the user
226 foreach ($options as $option => $value) {
227 $combinedOptions->set($option, $value);
228 }
229
230 // Resolve options
231 $resolvedOptions = $combinedOptions->all();
232
233 $this->validateOptionValues($resolvedOptions);
234 $this->validateOptionTypes($resolvedOptions);
235
236 return $resolvedOptions;
237 }
238
239 /**
240 * Validates that the given option names exist and throws an exception
241 * otherwise.
242 *
243 * @param array $options An list of option names as keys.
244 *
245 * @throws InvalidOptionsException If any of the options has not been defined.
246 */
247 private function validateOptionsExistence(array $options)
248 {
249 $diff = array_diff_key($options, $this->knownOptions);
250
251 if (count($diff) > 0) {
252 ksort($this->knownOptions);
253 ksort($diff);
254
255 throw new InvalidOptionsException(sprintf(
256 (count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Known options are: "%s"',
257 implode('", "', array_keys($diff)),
258 implode('", "', array_keys($this->knownOptions))
259 ));
260 }
261 }
262
263 /**
264 * Validates that all required options are given and throws an exception
265 * otherwise.
266 *
267 * @param array $options An list of option names as keys.
268 *
269 * @throws MissingOptionsException If a required option is missing.
270 */
271 private function validateOptionsCompleteness(array $options)
272 {
273 $diff = array_diff_key($this->requiredOptions, $options);
274
275 if (count($diff) > 0) {
276 ksort($diff);
277
278 throw new MissingOptionsException(sprintf(
279 count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.',
280 implode('", "', array_keys($diff))
281 ));
282 }
283 }
284
285 /**
286 * Validates that the given option values match the allowed values and
287 * throws an exception otherwise.
288 *
289 * @param array $options A list of option values.
290 *
291 * @throws InvalidOptionsException If any of the values does not match the
292 * allowed values of the option.
293 */
294 private function validateOptionValues(array $options)
295 {
296 foreach ($this->allowedValues as $option => $allowedValues) {
297 if (isset($options[$option]) && !in_array($options[$option], $allowedValues, true)) {
298 throw new InvalidOptionsException(sprintf('The option "%s" has the value "%s", but is expected to be one of "%s"', $option, $options[$option], implode('", "', $allowedValues)));
299 }
300 }
301 }
302
303 /**
304 * Validates that the given options match the allowed types and
305 * throws an exception otherwise.
306 *
307 * @param array $options A list of options.
308 *
309 * @throws InvalidOptionsException If any of the types does not match the
310 * allowed types of the option.
311 */
312 private function validateOptionTypes(array $options)
313 {
314 foreach ($this->allowedTypes as $option => $allowedTypes) {
315 if (!array_key_exists($option, $options)) {
316 continue;
317 }
318
319 $value = $options[$option];
320 $allowedTypes = (array) $allowedTypes;
321
322 foreach ($allowedTypes as $type) {
323 $isFunction = 'is_'.$type;
324
325 if (function_exists($isFunction) && $isFunction($value)) {
326 continue 2;
327 } elseif ($value instanceof $type) {
328 continue 2;
329 }
330 }
331
332 $printableValue = is_object($value)
333 ? get_class($value)
334 : (is_array($value)
335 ? 'Array'
336 : (string) $value);
337
338 throw new InvalidOptionsException(sprintf(
339 'The option "%s" with value "%s" is expected to be of type "%s"',
340 $option,
341 $printableValue,
342 implode('", "', $allowedTypes)
343 ));
344 }
345 }
346}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/OptionsResolverInterface.php b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/OptionsResolverInterface.php
new file mode 100644
index 00000000..8474c4bc
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/OptionsResolverInterface.php
@@ -0,0 +1,210 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\OptionsResolver;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17interface OptionsResolverInterface
18{
19 /**
20 * Sets default option values.
21 *
22 * The options can either be values of any types or closures that
23 * evaluate the option value lazily. These closures must have one
24 * of the following signatures:
25 *
26 * <code>
27 * function (Options $options)
28 * function (Options $options, $value)
29 * </code>
30 *
31 * The second parameter passed to the closure is the previously
32 * set default value, in case you are overwriting an existing
33 * default value.
34 *
35 * The closures should return the lazily created option value.
36 *
37 * @param array $defaultValues A list of option names as keys and default
38 * values or closures as values.
39 *
40 * @return OptionsResolverInterface The resolver instance.
41 */
42 public function setDefaults(array $defaultValues);
43
44 /**
45 * Replaces default option values.
46 *
47 * Old defaults are erased, which means that closures passed here cannot
48 * access the previous default value. This may be useful to improve
49 * performance if the previous default value is calculated by an expensive
50 * closure.
51 *
52 * @param array $defaultValues A list of option names as keys and default
53 * values or closures as values.
54 *
55 * @return OptionsResolverInterface The resolver instance.
56 */
57 public function replaceDefaults(array $defaultValues);
58
59 /**
60 * Sets optional options.
61 *
62 * This method declares valid option names without setting default values for them.
63 * If these options are not passed to {@link resolve()} and no default has been set
64 * for them, they will be missing in the final options array. This can be helpful
65 * if you want to determine whether an option has been set or not because otherwise
66 * {@link resolve()} would trigger an exception for unknown options.
67 *
68 * @param array $optionNames A list of option names.
69 *
70 * @return OptionsResolverInterface The resolver instance.
71 *
72 * @throws Exception\OptionDefinitionException When trying to pass default values.
73 */
74 public function setOptional(array $optionNames);
75
76 /**
77 * Sets required options.
78 *
79 * If these options are not passed to {@link resolve()} and no default has been set for
80 * them, an exception will be thrown.
81 *
82 * @param array $optionNames A list of option names.
83 *
84 * @return OptionsResolverInterface The resolver instance.
85 *
86 * @throws Exception\OptionDefinitionException When trying to pass default values.
87 */
88 public function setRequired(array $optionNames);
89
90 /**
91 * Sets allowed values for a list of options.
92 *
93 * @param array $allowedValues A list of option names as keys and arrays
94 * with values acceptable for that option as
95 * values.
96 *
97 * @return OptionsResolverInterface The resolver instance.
98 *
99 * @throws Exception\InvalidOptionsException If an option has not been defined
100 * (see {@link isKnown()}) for which
101 * an allowed value is set.
102 */
103 public function setAllowedValues(array $allowedValues);
104
105 /**
106 * Adds allowed values for a list of options.
107 *
108 * The values are merged with the allowed values defined previously.
109 *
110 * @param array $allowedValues A list of option names as keys and arrays
111 * with values acceptable for that option as
112 * values.
113 *
114 * @return OptionsResolverInterface The resolver instance.
115 *
116 * @throws Exception\InvalidOptionsException If an option has not been defined
117 * (see {@link isKnown()}) for which
118 * an allowed value is set.
119 */
120 public function addAllowedValues(array $allowedValues);
121
122 /**
123 * Sets allowed types for a list of options.
124 *
125 * @param array $allowedTypes A list of option names as keys and type
126 * names passed as string or array as values.
127 *
128 * @return OptionsResolverInterface The resolver instance.
129 *
130 * @throws Exception\InvalidOptionsException If an option has not been defined for
131 * which an allowed type is set.
132 */
133 public function setAllowedTypes(array $allowedTypes);
134
135 /**
136 * Adds allowed types for a list of options.
137 *
138 * The types are merged with the allowed types defined previously.
139 *
140 * @param array $allowedTypes A list of option names as keys and type
141 * names passed as string or array as values.
142 *
143 * @return OptionsResolverInterface The resolver instance.
144 *
145 * @throws Exception\InvalidOptionsException If an option has not been defined for
146 * which an allowed type is set.
147 */
148 public function addAllowedTypes(array $allowedTypes);
149
150 /**
151 * Sets normalizers that are applied on resolved options.
152 *
153 * The normalizers should be closures with the following signature:
154 *
155 * <code>
156 * function (Options $options, $value)
157 * </code>
158 *
159 * The second parameter passed to the closure is the value of
160 * the option.
161 *
162 * The closure should return the normalized value.
163 *
164 * @param array $normalizers An array of closures.
165 *
166 * @return OptionsResolverInterface The resolver instance.
167 */
168 public function setNormalizers(array $normalizers);
169
170 /**
171 * Returns whether an option is known.
172 *
173 * An option is known if it has been passed to either {@link setDefaults()},
174 * {@link setRequired()} or {@link setOptional()} before.
175 *
176 * @param string $option The name of the option.
177 *
178 * @return Boolean Whether the option is known.
179 */
180 public function isKnown($option);
181
182 /**
183 * Returns whether an option is required.
184 *
185 * An option is required if it has been passed to {@link setRequired()},
186 * but not to {@link setDefaults()}. That is, the option has been declared
187 * as required and no default value has been set.
188 *
189 * @param string $option The name of the option.
190 *
191 * @return Boolean Whether the option is required.
192 */
193 public function isRequired($option);
194
195 /**
196 * Returns the combination of the default and the passed options.
197 *
198 * @param array $options The custom option values.
199 *
200 * @return array A list of options and their values.
201 *
202 * @throws Exception\InvalidOptionsException If any of the passed options has not
203 * been defined or does not contain an
204 * allowed value.
205 * @throws Exception\MissingOptionsException If a required option is missing.
206 * @throws Exception\OptionDefinitionException If a cyclic dependency is detected
207 * between two lazy options.
208 */
209 public function resolve(array $options = array());
210}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/README.md b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/README.md
new file mode 100644
index 00000000..29cea102
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/README.md
@@ -0,0 +1,107 @@
1OptionsResolver Component
2=========================
3
4OptionsResolver helps at configuring objects with option arrays.
5
6It supports default values on different levels of your class hierarchy,
7option constraints (required vs. optional, allowed values) and lazy options
8whose default value depends on the value of another option.
9
10The following example demonstrates a Person class with two required options
11"firstName" and "lastName" and two optional options "age" and "gender", where
12the default value of "gender" is derived from the passed first name, if
13possible, and may only be one of "male" and "female".
14
15 use Symfony\Component\OptionsResolver\OptionsResolver;
16 use Symfony\Component\OptionsResolver\OptionsResolverInterface;
17 use Symfony\Component\OptionsResolver\Options;
18
19 class Person
20 {
21 protected $options;
22
23 public function __construct(array $options = array())
24 {
25 $resolver = new OptionsResolver();
26 $this->setDefaultOptions($resolver);
27
28 $this->options = $resolver->resolve($options);
29 }
30
31 protected function setDefaultOptions(OptionsResolverInterface $resolver)
32 {
33 $resolver->setRequired(array(
34 'firstName',
35 'lastName',
36 ));
37
38 $resolver->setDefaults(array(
39 'age' => null,
40 'gender' => function (Options $options) {
41 if (self::isKnownMaleName($options['firstName'])) {
42 return 'male';
43 }
44
45 return 'female';
46 },
47 ));
48
49 $resolver->setAllowedValues(array(
50 'gender' => array('male', 'female'),
51 ));
52 }
53 }
54
55We can now easily instantiate a Person object:
56
57 // 'gender' is implicitly set to 'female'
58 $person = new Person(array(
59 'firstName' => 'Jane',
60 'lastName' => 'Doe',
61 ));
62
63We can also override the default values of the optional options:
64
65 $person = new Person(array(
66 'firstName' => 'Abdullah',
67 'lastName' => 'Mogashi',
68 'gender' => 'male',
69 'age' => 30,
70 ));
71
72Options can be added or changed in subclasses by overriding the `setDefaultOptions`
73method:
74
75 use Symfony\Component\OptionsResolver\OptionsResolver;
76 use Symfony\Component\OptionsResolver\Options;
77
78 class Employee extends Person
79 {
80 protected function setDefaultOptions(OptionsResolverInterface $resolver)
81 {
82 parent::setDefaultOptions($resolver);
83
84 $resolver->setRequired(array(
85 'birthDate',
86 ));
87
88 $resolver->setDefaults(array(
89 // $previousValue contains the default value configured in the
90 // parent class
91 'age' => function (Options $options, $previousValue) {
92 return self::calculateAge($options['birthDate']);
93 }
94 ));
95 }
96 }
97
98
99
100Resources
101---------
102
103You can run the unit tests with the following command:
104
105 $ cd path/to/Symfony/Component/OptionsResolver/
106 $ composer.phar install --dev
107 $ phpunit
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
new file mode 100644
index 00000000..d50cd3fc
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
@@ -0,0 +1,681 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\OptionsResolver\Tests;
13
14use Symfony\Component\OptionsResolver\OptionsResolver;
15use Symfony\Component\OptionsResolver\Options;
16
17class OptionsResolverTest extends \PHPUnit_Framework_TestCase
18{
19 /**
20 * @var OptionsResolver
21 */
22 private $resolver;
23
24 protected function setUp()
25 {
26 $this->resolver = new OptionsResolver();
27 }
28
29 public function testResolve()
30 {
31 $this->resolver->setDefaults(array(
32 'one' => '1',
33 'two' => '2',
34 ));
35
36 $options = array(
37 'two' => '20',
38 );
39
40 $this->assertEquals(array(
41 'one' => '1',
42 'two' => '20',
43 ), $this->resolver->resolve($options));
44 }
45
46 public function testResolveLazy()
47 {
48 $this->resolver->setDefaults(array(
49 'one' => '1',
50 'two' => function (Options $options) {
51 return '20';
52 },
53 ));
54
55 $this->assertEquals(array(
56 'one' => '1',
57 'two' => '20',
58 ), $this->resolver->resolve(array()));
59 }
60
61 public function testResolveLazyDependencyOnOptional()
62 {
63 $this->resolver->setDefaults(array(
64 'one' => '1',
65 'two' => function (Options $options) {
66 return $options['one'].'2';
67 },
68 ));
69
70 $options = array(
71 'one' => '10',
72 );
73
74 $this->assertEquals(array(
75 'one' => '10',
76 'two' => '102',
77 ), $this->resolver->resolve($options));
78 }
79
80 public function testResolveLazyDependencyOnMissingOptionalWithoutDefault()
81 {
82 $test = $this;
83
84 $this->resolver->setOptional(array(
85 'one',
86 ));
87
88 $this->resolver->setDefaults(array(
89 'two' => function (Options $options) use ($test) {
90 /* @var \PHPUnit_Framework_TestCase $test */
91 $test->assertFalse(isset($options['one']));
92
93 return '2';
94 },
95 ));
96
97 $options = array(
98 );
99
100 $this->assertEquals(array(
101 'two' => '2',
102 ), $this->resolver->resolve($options));
103 }
104
105 public function testResolveLazyDependencyOnOptionalWithoutDefault()
106 {
107 $test = $this;
108
109 $this->resolver->setOptional(array(
110 'one',
111 ));
112
113 $this->resolver->setDefaults(array(
114 'two' => function (Options $options) use ($test) {
115 /* @var \PHPUnit_Framework_TestCase $test */
116 $test->assertTrue(isset($options['one']));
117
118 return $options['one'].'2';
119 },
120 ));
121
122 $options = array(
123 'one' => '10',
124 );
125
126 $this->assertEquals(array(
127 'one' => '10',
128 'two' => '102',
129 ), $this->resolver->resolve($options));
130 }
131
132 public function testResolveLazyDependencyOnRequired()
133 {
134 $this->resolver->setRequired(array(
135 'one',
136 ));
137 $this->resolver->setDefaults(array(
138 'two' => function (Options $options) {
139 return $options['one'].'2';
140 },
141 ));
142
143 $options = array(
144 'one' => '10',
145 );
146
147 $this->assertEquals(array(
148 'one' => '10',
149 'two' => '102',
150 ), $this->resolver->resolve($options));
151 }
152
153 public function testResolveLazyReplaceDefaults()
154 {
155 $test = $this;
156
157 $this->resolver->setDefaults(array(
158 'one' => function (Options $options) use ($test) {
159 /* @var \PHPUnit_Framework_TestCase $test */
160 $test->fail('Previous closure should not be executed');
161 },
162 ));
163
164 $this->resolver->replaceDefaults(array(
165 'one' => function (Options $options, $previousValue) {
166 return '1';
167 },
168 ));
169
170 $this->assertEquals(array(
171 'one' => '1',
172 ), $this->resolver->resolve(array()));
173 }
174
175 /**
176 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
177 */
178 public function testResolveFailsIfNonExistingOption()
179 {
180 $this->resolver->setDefaults(array(
181 'one' => '1',
182 ));
183
184 $this->resolver->setRequired(array(
185 'two',
186 ));
187
188 $this->resolver->setOptional(array(
189 'three',
190 ));
191
192 $this->resolver->resolve(array(
193 'foo' => 'bar',
194 ));
195 }
196
197 /**
198 * @expectedException \Symfony\Component\OptionsResolver\Exception\MissingOptionsException
199 */
200 public function testResolveFailsIfMissingRequiredOption()
201 {
202 $this->resolver->setRequired(array(
203 'one',
204 ));
205
206 $this->resolver->setDefaults(array(
207 'two' => '2',
208 ));
209
210 $this->resolver->resolve(array(
211 'two' => '20',
212 ));
213 }
214
215 public function testResolveSucceedsIfOptionValueAllowed()
216 {
217 $this->resolver->setDefaults(array(
218 'one' => '1',
219 ));
220
221 $this->resolver->setAllowedValues(array(
222 'one' => array('1', 'one'),
223 ));
224
225 $options = array(
226 'one' => 'one',
227 );
228
229 $this->assertEquals(array(
230 'one' => 'one',
231 ), $this->resolver->resolve($options));
232 }
233
234 public function testResolveSucceedsIfOptionValueAllowed2()
235 {
236 $this->resolver->setDefaults(array(
237 'one' => '1',
238 'two' => '2',
239 ));
240
241 $this->resolver->setAllowedValues(array(
242 'one' => '1',
243 'two' => '2',
244 ));
245 $this->resolver->addAllowedValues(array(
246 'one' => 'one',
247 'two' => 'two',
248 ));
249
250 $options = array(
251 'one' => '1',
252 'two' => 'two',
253 );
254
255 $this->assertEquals(array(
256 'one' => '1',
257 'two' => 'two',
258 ), $this->resolver->resolve($options));
259 }
260
261 public function testResolveSucceedsIfOptionalWithAllowedValuesNotSet()
262 {
263 $this->resolver->setRequired(array(
264 'one',
265 ));
266
267 $this->resolver->setOptional(array(
268 'two',
269 ));
270
271 $this->resolver->setAllowedValues(array(
272 'one' => array('1', 'one'),
273 'two' => array('2', 'two'),
274 ));
275
276 $options = array(
277 'one' => '1',
278 );
279
280 $this->assertEquals(array(
281 'one' => '1',
282 ), $this->resolver->resolve($options));
283 }
284
285 /**
286 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
287 */
288 public function testResolveFailsIfOptionValueNotAllowed()
289 {
290 $this->resolver->setDefaults(array(
291 'one' => '1',
292 ));
293
294 $this->resolver->setAllowedValues(array(
295 'one' => array('1', 'one'),
296 ));
297
298 $this->resolver->resolve(array(
299 'one' => '2',
300 ));
301 }
302
303 public function testResolveSucceedsIfOptionTypeAllowed()
304 {
305 $this->resolver->setDefaults(array(
306 'one' => '1',
307 ));
308
309 $this->resolver->setAllowedTypes(array(
310 'one' => 'string',
311 ));
312
313 $options = array(
314 'one' => 'one',
315 );
316
317 $this->assertEquals(array(
318 'one' => 'one',
319 ), $this->resolver->resolve($options));
320 }
321
322 public function testResolveSucceedsIfOptionTypeAllowedPassArray()
323 {
324 $this->resolver->setDefaults(array(
325 'one' => '1',
326 ));
327
328 $this->resolver->setAllowedTypes(array(
329 'one' => array('string', 'bool'),
330 ));
331
332 $options = array(
333 'one' => true,
334 );
335
336 $this->assertEquals(array(
337 'one' => true,
338 ), $this->resolver->resolve($options));
339 }
340
341 public function testResolveSucceedsIfOptionTypeAllowedPassObject()
342 {
343 $this->resolver->setDefaults(array(
344 'one' => '1',
345 ));
346
347 $this->resolver->setAllowedTypes(array(
348 'one' => 'object',
349 ));
350
351 $object = new \stdClass();
352 $options = array(
353 'one' => $object,
354 );
355
356 $this->assertEquals(array(
357 'one' => $object,
358 ), $this->resolver->resolve($options));
359 }
360
361 public function testResolveSucceedsIfOptionTypeAllowedPassClass()
362 {
363 $this->resolver->setDefaults(array(
364 'one' => '1',
365 ));
366
367 $this->resolver->setAllowedTypes(array(
368 'one' => '\stdClass',
369 ));
370
371 $object = new \stdClass();
372 $options = array(
373 'one' => $object,
374 );
375
376 $this->assertEquals(array(
377 'one' => $object,
378 ), $this->resolver->resolve($options));
379 }
380
381 public function testResolveSucceedsIfOptionTypeAllowedAddTypes()
382 {
383 $this->resolver->setDefaults(array(
384 'one' => '1',
385 'two' => '2',
386 ));
387
388 $this->resolver->setAllowedTypes(array(
389 'one' => 'string',
390 'two' => 'bool',
391 ));
392 $this->resolver->addAllowedTypes(array(
393 'one' => 'float',
394 'two' => 'integer',
395 ));
396
397 $options = array(
398 'one' => 1.23,
399 'two' => false,
400 );
401
402 $this->assertEquals(array(
403 'one' => 1.23,
404 'two' => false,
405 ), $this->resolver->resolve($options));
406 }
407
408 public function testResolveSucceedsIfOptionalWithTypeAndWithoutValue()
409 {
410 $this->resolver->setOptional(array(
411 'one',
412 'two',
413 ));
414
415 $this->resolver->setAllowedTypes(array(
416 'one' => 'string',
417 'two' => 'int',
418 ));
419
420 $options = array(
421 'two' => 1,
422 );
423
424 $this->assertEquals(array(
425 'two' => 1,
426 ), $this->resolver->resolve($options));
427 }
428
429 /**
430 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
431 */
432 public function testResolveFailsIfOptionTypeNotAllowed()
433 {
434 $this->resolver->setDefaults(array(
435 'one' => '1',
436 ));
437
438 $this->resolver->setAllowedTypes(array(
439 'one' => array('string', 'bool'),
440 ));
441
442 $this->resolver->resolve(array(
443 'one' => 1.23,
444 ));
445 }
446
447 /**
448 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
449 */
450 public function testResolveFailsIfOptionTypeNotAllowedMultipleOptions()
451 {
452 $this->resolver->setDefaults(array(
453 'one' => '1',
454 'two' => '2',
455 ));
456
457 $this->resolver->setAllowedTypes(array(
458 'one' => 'string',
459 'two' => 'bool',
460 ));
461
462 $this->resolver->resolve(array(
463 'one' => 'foo',
464 'two' => 1.23,
465 ));
466 }
467
468 /**
469 * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
470 */
471 public function testResolveFailsIfOptionTypeNotAllowedAddTypes()
472 {
473 $this->resolver->setDefaults(array(
474 'one' => '1',
475 ));
476
477 $this->resolver->setAllowedTypes(array(
478 'one' => 'string',
479 ));
480 $this->resolver->addAllowedTypes(array(
481 'one' => 'bool',
482 ));
483
484 $this->resolver->resolve(array(
485 'one' => 1.23,
486 ));
487 }
488
489 /**
490 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
491 */
492 public function testSetRequiredFailsIfDefaultIsPassed()
493 {
494 $this->resolver->setRequired(array(
495 'one' => '1',
496 ));
497 }
498
499 /**
500 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
501 */
502 public function testSetOptionalFailsIfDefaultIsPassed()
503 {
504 $this->resolver->setOptional(array(
505 'one' => '1',
506 ));
507 }
508
509 public function testFluidInterface()
510 {
511 $this->resolver->setDefaults(array('one' => '1'))
512 ->replaceDefaults(array('one' => '2'))
513 ->setAllowedValues(array('one' => array('1', '2')))
514 ->addAllowedValues(array('one' => array('3')))
515 ->setRequired(array('two'))
516 ->setOptional(array('three'));
517
518 $options = array(
519 'two' => '2',
520 );
521
522 $this->assertEquals(array(
523 'one' => '2',
524 'two' => '2',
525 ), $this->resolver->resolve($options));
526 }
527
528 public function testKnownIfDefaultWasSet()
529 {
530 $this->assertFalse($this->resolver->isKnown('foo'));
531
532 $this->resolver->setDefaults(array(
533 'foo' => 'bar',
534 ));
535
536 $this->assertTrue($this->resolver->isKnown('foo'));
537 }
538
539 public function testKnownIfRequired()
540 {
541 $this->assertFalse($this->resolver->isKnown('foo'));
542
543 $this->resolver->setRequired(array(
544 'foo',
545 ));
546
547 $this->assertTrue($this->resolver->isKnown('foo'));
548 }
549
550 public function testKnownIfOptional()
551 {
552 $this->assertFalse($this->resolver->isKnown('foo'));
553
554 $this->resolver->setOptional(array(
555 'foo',
556 ));
557
558 $this->assertTrue($this->resolver->isKnown('foo'));
559 }
560
561 public function testRequiredIfRequired()
562 {
563 $this->assertFalse($this->resolver->isRequired('foo'));
564
565 $this->resolver->setRequired(array(
566 'foo',
567 ));
568
569 $this->assertTrue($this->resolver->isRequired('foo'));
570 }
571
572 public function testNotRequiredIfRequiredAndDefaultValue()
573 {
574 $this->assertFalse($this->resolver->isRequired('foo'));
575
576 $this->resolver->setRequired(array(
577 'foo',
578 ));
579 $this->resolver->setDefaults(array(
580 'foo' => 'bar',
581 ));
582
583 $this->assertFalse($this->resolver->isRequired('foo'));
584 }
585
586 public function testNormalizersTransformFinalOptions()
587 {
588 $this->resolver->setDefaults(array(
589 'foo' => 'bar',
590 'bam' => 'baz',
591 ));
592 $this->resolver->setNormalizers(array(
593 'foo' => function (Options $options, $value) {
594 return $options['bam'].'['.$value.']';
595 },
596 ));
597
598 $expected = array(
599 'foo' => 'baz[bar]',
600 'bam' => 'baz',
601 );
602
603 $this->assertEquals($expected, $this->resolver->resolve(array()));
604
605 $expected = array(
606 'foo' => 'boo[custom]',
607 'bam' => 'boo',
608 );
609
610 $this->assertEquals($expected, $this->resolver->resolve(array(
611 'foo' => 'custom',
612 'bam' => 'boo',
613 )));
614 }
615
616 public function testResolveWithoutOptionSucceedsIfRequiredAndDefaultValue()
617 {
618 $this->resolver->setRequired(array(
619 'foo',
620 ));
621 $this->resolver->setDefaults(array(
622 'foo' => 'bar',
623 ));
624
625 $this->assertEquals(array(
626 'foo' => 'bar'
627 ), $this->resolver->resolve(array()));
628 }
629
630 public function testResolveWithoutOptionSucceedsIfDefaultValueAndRequired()
631 {
632 $this->resolver->setDefaults(array(
633 'foo' => 'bar',
634 ));
635 $this->resolver->setRequired(array(
636 'foo',
637 ));
638
639 $this->assertEquals(array(
640 'foo' => 'bar'
641 ), $this->resolver->resolve(array()));
642 }
643
644 public function testResolveSucceedsIfOptionRequiredAndValueAllowed()
645 {
646 $this->resolver->setRequired(array(
647 'one', 'two',
648 ));
649 $this->resolver->setAllowedValues(array(
650 'two' => array('2'),
651 ));
652
653 $options = array(
654 'one' => '1',
655 'two' => '2'
656 );
657
658 $this->assertEquals($options, $this->resolver->resolve($options));
659 }
660
661 public function testClone()
662 {
663 $this->resolver->setDefaults(array('one' => '1'));
664
665 $clone = clone $this->resolver;
666
667 // Changes after cloning don't affect each other
668 $this->resolver->setDefaults(array('two' => '2'));
669 $clone->setDefaults(array('three' => '3'));
670
671 $this->assertEquals(array(
672 'one' => '1',
673 'two' => '2',
674 ), $this->resolver->resolve());
675
676 $this->assertEquals(array(
677 'one' => '1',
678 'three' => '3',
679 ), $clone->resolve());
680 }
681}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Tests/OptionsTest.php b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Tests/OptionsTest.php
new file mode 100644
index 00000000..e24a7647
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/Tests/OptionsTest.php
@@ -0,0 +1,529 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\OptionsResolver\Tests;
13
14use Symfony\Component\OptionsResolver\Options;
15
16class OptionsTest extends \PHPUnit_Framework_TestCase
17{
18 /**
19 * @var Options
20 */
21 private $options;
22
23 protected function setUp()
24 {
25 $this->options = new Options();
26 }
27
28 public function testArrayAccess()
29 {
30 $this->assertFalse(isset($this->options['foo']));
31 $this->assertFalse(isset($this->options['bar']));
32
33 $this->options['foo'] = 0;
34 $this->options['bar'] = 1;
35
36 $this->assertTrue(isset($this->options['foo']));
37 $this->assertTrue(isset($this->options['bar']));
38
39 unset($this->options['bar']);
40
41 $this->assertTrue(isset($this->options['foo']));
42 $this->assertFalse(isset($this->options['bar']));
43 $this->assertEquals(0, $this->options['foo']);
44 }
45
46 public function testCountable()
47 {
48 $this->options->set('foo', 0);
49 $this->options->set('bar', 1);
50
51 $this->assertCount(2, $this->options);
52 }
53
54 /**
55 * @expectedException \OutOfBoundsException
56 */
57 public function testGetNonExisting()
58 {
59 $this->options->get('foo');
60 }
61
62 /**
63 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
64 */
65 public function testSetNotSupportedAfterGet()
66 {
67 $this->options->set('foo', 'bar');
68 $this->options->get('foo');
69 $this->options->set('foo', 'baz');
70 }
71
72 /**
73 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
74 */
75 public function testRemoveNotSupportedAfterGet()
76 {
77 $this->options->set('foo', 'bar');
78 $this->options->get('foo');
79 $this->options->remove('foo');
80 }
81
82 /**
83 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
84 */
85 public function testSetNormalizerNotSupportedAfterGet()
86 {
87 $this->options->set('foo', 'bar');
88 $this->options->get('foo');
89 $this->options->setNormalizer('foo', function () {});
90 }
91
92 public function testSetLazyOption()
93 {
94 $test = $this;
95
96 $this->options->set('foo', function (Options $options) use ($test) {
97 return 'dynamic';
98 });
99
100 $this->assertEquals('dynamic', $this->options->get('foo'));
101 }
102
103 public function testSetDiscardsPreviousValue()
104 {
105 $test = $this;
106
107 // defined by superclass
108 $this->options->set('foo', 'bar');
109
110 // defined by subclass
111 $this->options->set('foo', function (Options $options, $previousValue) use ($test) {
112 /* @var \PHPUnit_Framework_TestCase $test */
113 $test->assertNull($previousValue);
114
115 return 'dynamic';
116 });
117
118 $this->assertEquals('dynamic', $this->options->get('foo'));
119 }
120
121 public function testOverloadKeepsPreviousValue()
122 {
123 $test = $this;
124
125 // defined by superclass
126 $this->options->set('foo', 'bar');
127
128 // defined by subclass
129 $this->options->overload('foo', function (Options $options, $previousValue) use ($test) {
130 /* @var \PHPUnit_Framework_TestCase $test */
131 $test->assertEquals('bar', $previousValue);
132
133 return 'dynamic';
134 });
135
136 $this->assertEquals('dynamic', $this->options->get('foo'));
137 }
138
139 public function testPreviousValueIsEvaluatedIfLazy()
140 {
141 $test = $this;
142
143 // defined by superclass
144 $this->options->set('foo', function (Options $options) {
145 return 'bar';
146 });
147
148 // defined by subclass
149 $this->options->overload('foo', function (Options $options, $previousValue) use ($test) {
150 /* @var \PHPUnit_Framework_TestCase $test */
151 $test->assertEquals('bar', $previousValue);
152
153 return 'dynamic';
154 });
155
156 $this->assertEquals('dynamic', $this->options->get('foo'));
157 }
158
159 public function testPreviousValueIsNotEvaluatedIfNoSecondArgument()
160 {
161 $test = $this;
162
163 // defined by superclass
164 $this->options->set('foo', function (Options $options) use ($test) {
165 $test->fail('Should not be called');
166 });
167
168 // defined by subclass, no $previousValue argument defined!
169 $this->options->overload('foo', function (Options $options) use ($test) {
170 return 'dynamic';
171 });
172
173 $this->assertEquals('dynamic', $this->options->get('foo'));
174 }
175
176 public function testLazyOptionCanAccessOtherOptions()
177 {
178 $test = $this;
179
180 $this->options->set('foo', 'bar');
181
182 $this->options->set('bam', function (Options $options) use ($test) {
183 /* @var \PHPUnit_Framework_TestCase $test */
184 $test->assertEquals('bar', $options->get('foo'));
185
186 return 'dynamic';
187 });
188
189 $this->assertEquals('bar', $this->options->get('foo'));
190 $this->assertEquals('dynamic', $this->options->get('bam'));
191 }
192
193 public function testLazyOptionCanAccessOtherLazyOptions()
194 {
195 $test = $this;
196
197 $this->options->set('foo', function (Options $options) {
198 return 'bar';
199 });
200
201 $this->options->set('bam', function (Options $options) use ($test) {
202 /* @var \PHPUnit_Framework_TestCase $test */
203 $test->assertEquals('bar', $options->get('foo'));
204
205 return 'dynamic';
206 });
207
208 $this->assertEquals('bar', $this->options->get('foo'));
209 $this->assertEquals('dynamic', $this->options->get('bam'));
210 }
211
212 public function testNormalizer()
213 {
214 $this->options->set('foo', 'bar');
215
216 $this->options->setNormalizer('foo', function () {
217 return 'normalized';
218 });
219
220 $this->assertEquals('normalized', $this->options->get('foo'));
221 }
222
223 public function testNormalizerReceivesUnnormalizedValue()
224 {
225 $this->options->set('foo', 'bar');
226
227 $this->options->setNormalizer('foo', function (Options $options, $value) {
228 return 'normalized['.$value.']';
229 });
230
231 $this->assertEquals('normalized[bar]', $this->options->get('foo'));
232 }
233
234 public function testNormalizerCanAccessOtherOptions()
235 {
236 $test = $this;
237
238 $this->options->set('foo', 'bar');
239 $this->options->set('bam', 'baz');
240
241 $this->options->setNormalizer('bam', function (Options $options) use ($test) {
242 /* @var \PHPUnit_Framework_TestCase $test */
243 $test->assertEquals('bar', $options->get('foo'));
244
245 return 'normalized';
246 });
247
248 $this->assertEquals('bar', $this->options->get('foo'));
249 $this->assertEquals('normalized', $this->options->get('bam'));
250 }
251
252 public function testNormalizerCanAccessOtherLazyOptions()
253 {
254 $test = $this;
255
256 $this->options->set('foo', function (Options $options) {
257 return 'bar';
258 });
259 $this->options->set('bam', 'baz');
260
261 $this->options->setNormalizer('bam', function (Options $options) use ($test) {
262 /* @var \PHPUnit_Framework_TestCase $test */
263 $test->assertEquals('bar', $options->get('foo'));
264
265 return 'normalized';
266 });
267
268 $this->assertEquals('bar', $this->options->get('foo'));
269 $this->assertEquals('normalized', $this->options->get('bam'));
270 }
271
272 /**
273 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
274 */
275 public function testFailForCyclicDependencies()
276 {
277 $this->options->set('foo', function (Options $options) {
278 $options->get('bam');
279 });
280
281 $this->options->set('bam', function (Options $options) {
282 $options->get('foo');
283 });
284
285 $this->options->get('foo');
286 }
287
288 /**
289 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
290 */
291 public function testFailForCyclicDependenciesBetweenNormalizers()
292 {
293 $this->options->set('foo', 'bar');
294 $this->options->set('bam', 'baz');
295
296 $this->options->setNormalizer('foo', function (Options $options) {
297 $options->get('bam');
298 });
299
300 $this->options->setNormalizer('bam', function (Options $options) {
301 $options->get('foo');
302 });
303
304 $this->options->get('foo');
305 }
306
307 /**
308 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
309 */
310 public function testFailForCyclicDependenciesBetweenNormalizerAndLazyOption()
311 {
312 $this->options->set('foo', function (Options $options) {
313 $options->get('bam');
314 });
315 $this->options->set('bam', 'baz');
316
317 $this->options->setNormalizer('bam', function (Options $options) {
318 $options->get('foo');
319 });
320
321 $this->options->get('foo');
322 }
323
324 public function testAllInvokesEachLazyOptionOnlyOnce()
325 {
326 $test = $this;
327 $i = 1;
328
329 $this->options->set('foo', function (Options $options) use ($test, &$i) {
330 $test->assertSame(1, $i);
331 ++$i;
332
333 // Implicitly invoke lazy option for "bam"
334 $options->get('bam');
335 });
336 $this->options->set('bam', function (Options $options) use ($test, &$i) {
337 $test->assertSame(2, $i);
338 ++$i;
339 });
340
341 $this->options->all();
342 }
343
344 public function testAllInvokesEachNormalizerOnlyOnce()
345 {
346 $test = $this;
347 $i = 1;
348
349 $this->options->set('foo', 'bar');
350 $this->options->set('bam', 'baz');
351
352 $this->options->setNormalizer('foo', function (Options $options) use ($test, &$i) {
353 $test->assertSame(1, $i);
354 ++$i;
355
356 // Implicitly invoke normalizer for "bam"
357 $options->get('bam');
358 });
359 $this->options->setNormalizer('bam', function (Options $options) use ($test, &$i) {
360 $test->assertSame(2, $i);
361 ++$i;
362 });
363
364 $this->options->all();
365 }
366
367 public function testReplaceClearsAndSets()
368 {
369 $this->options->set('one', '1');
370
371 $this->options->replace(array(
372 'two' => '2',
373 'three' => function (Options $options) {
374 return '2' === $options['two'] ? '3' : 'foo';
375 }
376 ));
377
378 $this->assertEquals(array(
379 'two' => '2',
380 'three' => '3',
381 ), $this->options->all());
382 }
383
384 public function testClearRemovesAllOptions()
385 {
386 $this->options->set('one', 1);
387 $this->options->set('two', 2);
388
389 $this->options->clear();
390
391 $this->assertEmpty($this->options->all());
392
393 }
394
395 /**
396 * @covers Symfony\Component\OptionsResolver\Options::replace
397 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
398 */
399 public function testCannotReplaceAfterOptionWasRead()
400 {
401 $this->options->set('one', 1);
402 $this->options->all();
403
404 $this->options->replace(array(
405 'two' => '2',
406 ));
407 }
408
409 /**
410 * @covers Symfony\Component\OptionsResolver\Options::overload
411 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
412 */
413 public function testCannotOverloadAfterOptionWasRead()
414 {
415 $this->options->set('one', 1);
416 $this->options->all();
417
418 $this->options->overload('one', 2);
419 }
420
421 /**
422 * @covers Symfony\Component\OptionsResolver\Options::clear
423 * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
424 */
425 public function testCannotClearAfterOptionWasRead()
426 {
427 $this->options->set('one', 1);
428 $this->options->all();
429
430 $this->options->clear();
431 }
432
433 public function testOverloadCannotBeEvaluatedLazilyWithoutExpectedClosureParams()
434 {
435 $this->options->set('foo', 'bar');
436
437 $this->options->overload('foo', function () {
438 return 'test';
439 });
440
441 $this->assertNotEquals('test', $this->options->get('foo'));
442 $this->assertTrue(is_callable($this->options->get('foo')));
443 }
444
445 public function testOverloadCannotBeEvaluatedLazilyWithoutFirstParamTypeHint()
446 {
447 $this->options->set('foo', 'bar');
448
449 $this->options->overload('foo', function ($object) {
450 return 'test';
451 });
452
453 $this->assertNotEquals('test', $this->options->get('foo'));
454 $this->assertTrue(is_callable($this->options->get('foo')));
455 }
456
457 public function testOptionsIteration()
458 {
459 $this->options->set('foo', 'bar');
460 $this->options->set('foo1', 'bar1');
461 $expectedResult = array('foo' => 'bar', 'foo1' => 'bar1');
462
463 $this->assertEquals($expectedResult, iterator_to_array($this->options, true));
464 }
465
466 public function testHasWithNullValue()
467 {
468 $this->options->set('foo', null);
469
470 $this->assertTrue($this->options->has('foo'));
471 }
472
473 public function testRemoveOptionAndNormalizer()
474 {
475 $this->options->set('foo1', 'bar');
476 $this->options->setNormalizer('foo1', function (Options $options) {
477 return '';
478 });
479 $this->options->set('foo2', 'bar');
480 $this->options->setNormalizer('foo2', function (Options $options) {
481 return '';
482 });
483
484 $this->options->remove('foo2');
485 $this->assertEquals(array('foo1' => ''), $this->options->all());
486 }
487
488 public function testReplaceOptionAndNormalizer()
489 {
490 $this->options->set('foo1', 'bar');
491 $this->options->setNormalizer('foo1', function (Options $options) {
492 return '';
493 });
494 $this->options->set('foo2', 'bar');
495 $this->options->setNormalizer('foo2', function (Options $options) {
496 return '';
497 });
498
499 $this->options->replace(array('foo1' => 'new'));
500 $this->assertEquals(array('foo1' => 'new'), $this->options->all());
501 }
502
503 public function testClearOptionAndNormalizer()
504 {
505 $this->options->set('foo1', 'bar');
506 $this->options->setNormalizer('foo1', function (Options $options) {
507 return '';
508 });
509 $this->options->set('foo2', 'bar');
510 $this->options->setNormalizer('foo2', function (Options $options) {
511 return '';
512 });
513
514 $this->options->clear();
515 $this->assertEmpty($this->options->all());
516 }
517
518 public function testNormalizerWithoutCorrespondingOption()
519 {
520 $test = $this;
521
522 $this->options->setNormalizer('foo', function (Options $options, $previousValue) use ($test) {
523 $test->assertNull($previousValue);
524
525 return '';
526 });
527 $this->assertEquals(array('foo' => ''), $this->options->all());
528 }
529}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/composer.json b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/composer.json
new file mode 100644
index 00000000..f13d246e
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/composer.json
@@ -0,0 +1,31 @@
1{
2 "name": "symfony/options-resolver",
3 "type": "library",
4 "description": "Symfony OptionsResolver Component",
5 "keywords": ["options", "config", "configuration"],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3"
20 },
21 "autoload": {
22 "psr-0": { "Symfony\\Component\\OptionsResolver\\": "" }
23 },
24 "target-dir": "Symfony/Component/OptionsResolver",
25 "minimum-stability": "dev",
26 "extra": {
27 "branch-alias": {
28 "dev-master": "2.3-dev"
29 }
30 }
31}
diff --git a/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/phpunit.xml.dist b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/phpunit.xml.dist
new file mode 100644
index 00000000..ad24d17b
--- /dev/null
+++ b/vendor/symfony/options-resolver/Symfony/Component/OptionsResolver/phpunit.xml.dist
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony OptionsResolver Component Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./Resources</directory>
25 <directory>./Tests</directory>
26 </exclude>
27 </whitelist>
28 </filter>
29</phpunit>
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitattributes b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitattributes
new file mode 100644
index 00000000..80481513
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitattributes
@@ -0,0 +1,2 @@
1/Tests export-ignore
2phpunit.xml.dist export-ignore
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitignore b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitignore
new file mode 100644
index 00000000..44de97a3
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitignore
@@ -0,0 +1,4 @@
1vendor/
2composer.lock
3phpunit.xml
4
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/CHANGELOG.md b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/CHANGELOG.md
new file mode 100644
index 00000000..071ef3b5
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/CHANGELOG.md
@@ -0,0 +1,14 @@
1CHANGELOG
2=========
3
42.3.0
5------
6
7 * added PropertyAccessorBuilder, to enable or disable the support of "__call"
8 * added support for "__call" in the PropertyAccessor (disabled by default)
9 * [BC BREAK] changed PropertyAccessor to continue its search for a property or
10 method even if a non-public match was found. Before, a PropertyAccessDeniedException
11 was thrown in this case. Class PropertyAccessDeniedException was removed
12 now.
13 * deprecated PropertyAccess::getPropertyAccessor
14 * added PropertyAccess::createPropertyAccessor and PropertyAccess::createPropertyAccessorBuilder
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..d1fcdac9
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess\Exception;
13
14/**
15 * Marker interface for the PropertyAccess component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface ExceptionInterface
20{
21}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/InvalidPropertyPathException.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/InvalidPropertyPathException.php
new file mode 100644
index 00000000..69de31ce
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/InvalidPropertyPathException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess\Exception;
13
14/**
15 * Thrown when a property path is malformed.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class InvalidPropertyPathException extends RuntimeException
20{
21}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/NoSuchPropertyException.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/NoSuchPropertyException.php
new file mode 100644
index 00000000..ebaa5a30
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/NoSuchPropertyException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess\Exception;
13
14/**
15 * Thrown when a property cannot be found.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class NoSuchPropertyException extends RuntimeException
20{
21}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/OutOfBoundsException.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/OutOfBoundsException.php
new file mode 100644
index 00000000..a3c45597
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/OutOfBoundsException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess\Exception;
13
14/**
15 * Base OutOfBoundsException for the PropertyAccess component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/RuntimeException.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/RuntimeException.php
new file mode 100644
index 00000000..9fe843e3
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/RuntimeException.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess\Exception;
13
14/**
15 * Base RuntimeException for the PropertyAccess component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class RuntimeException extends \RuntimeException implements ExceptionInterface
20{
21}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/UnexpectedTypeException.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/UnexpectedTypeException.php
new file mode 100644
index 00000000..029d48c2
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/UnexpectedTypeException.php
@@ -0,0 +1,25 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess\Exception;
13
14/**
15 * Thrown when a value does not match an expected type.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class UnexpectedTypeException extends RuntimeException
20{
21 public function __construct($value, $expectedType)
22 {
23 parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
24 }
25}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/LICENSE b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccess.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccess.php
new file mode 100644
index 00000000..3b234df9
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccess.php
@@ -0,0 +1,60 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14/**
15 * Entry point of the PropertyAccess component.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19final class PropertyAccess
20{
21 /**
22 * Creates a property accessor with the default configuration.
23 *
24 * @return PropertyAccessor The new property accessor
25 */
26 public static function createPropertyAccessor()
27 {
28 return self::createPropertyAccessorBuilder()->getPropertyAccessor();
29 }
30
31 /**
32 * Creates a property accessor builder.
33 *
34 * @return PropertyAccessorBuilder The new property accessor builder
35 */
36 public static function createPropertyAccessorBuilder()
37 {
38 return new PropertyAccessorBuilder();
39 }
40
41 /**
42 * Alias of {@link getPropertyAccessor}.
43 *
44 * @return PropertyAccessor The new property accessor
45 *
46 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
47 * {@link createPropertyAccessor()} instead.
48 */
49 public static function getPropertyAccessor()
50 {
51 return self::createPropertyAccessor();
52 }
53
54 /**
55 * This class cannot be instantiated.
56 */
57 private function __construct()
58 {
59 }
60}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessor.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessor.php
new file mode 100644
index 00000000..c65d919e
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessor.php
@@ -0,0 +1,442 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
15use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
16
17/**
18 * Default implementation of {@link PropertyAccessorInterface}.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class PropertyAccessor implements PropertyAccessorInterface
23{
24 const VALUE = 0;
25 const IS_REF = 1;
26
27 private $magicCall;
28
29 /**
30 * Should not be used by application code. Use
31 * {@link PropertyAccess::getPropertyAccessor()} instead.
32 */
33 public function __construct($magicCall = false)
34 {
35 $this->magicCall = $magicCall;
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getValue($objectOrArray, $propertyPath)
42 {
43 if (is_string($propertyPath)) {
44 $propertyPath = new PropertyPath($propertyPath);
45 } elseif (!$propertyPath instanceof PropertyPathInterface) {
46 throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface');
47 }
48
49 $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength());
50
51 return $propertyValues[count($propertyValues) - 1][self::VALUE];
52 }
53
54 /**
55 * {@inheritdoc}
56 */
57 public function setValue(&$objectOrArray, $propertyPath, $value)
58 {
59 if (is_string($propertyPath)) {
60 $propertyPath = new PropertyPath($propertyPath);
61 } elseif (!$propertyPath instanceof PropertyPathInterface) {
62 throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface');
63 }
64
65 $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength() - 1);
66 $overwrite = true;
67
68 // Add the root object to the list
69 array_unshift($propertyValues, array(
70 self::VALUE => &$objectOrArray,
71 self::IS_REF => true,
72 ));
73
74 for ($i = count($propertyValues) - 1; $i >= 0; --$i) {
75 $objectOrArray =& $propertyValues[$i][self::VALUE];
76
77 if ($overwrite) {
78 if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
79 throw new UnexpectedTypeException($objectOrArray, 'object or array');
80 }
81
82 $property = $propertyPath->getElement($i);
83 //$singular = $propertyPath->singulars[$i];
84 $singular = null;
85
86 if ($propertyPath->isIndex($i)) {
87 $this->writeIndex($objectOrArray, $property, $value);
88 } else {
89 $this->writeProperty($objectOrArray, $property, $singular, $value);
90 }
91 }
92
93 $value =& $objectOrArray;
94 $overwrite = !$propertyValues[$i][self::IS_REF];
95 }
96 }
97
98 /**
99 * Reads the path from an object up to a given path index.
100 *
101 * @param object|array $objectOrArray The object or array to read from
102 * @param PropertyPathInterface $propertyPath The property path to read
103 * @param integer $lastIndex The index up to which should be read
104 *
105 * @return array The values read in the path.
106 *
107 * @throws UnexpectedTypeException If a value within the path is neither object nor array.
108 */
109 private function &readPropertiesUntil(&$objectOrArray, PropertyPathInterface $propertyPath, $lastIndex)
110 {
111 $propertyValues = array();
112
113 for ($i = 0; $i < $lastIndex; ++$i) {
114 if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
115 throw new UnexpectedTypeException($objectOrArray, 'object or array');
116 }
117
118 $property = $propertyPath->getElement($i);
119 $isIndex = $propertyPath->isIndex($i);
120 $isArrayAccess = is_array($objectOrArray) || $objectOrArray instanceof \ArrayAccess;
121
122 // Create missing nested arrays on demand
123 if ($isIndex && $isArrayAccess && !isset($objectOrArray[$property])) {
124 $objectOrArray[$property] = $i + 1 < $propertyPath->getLength() ? array() : null;
125 }
126
127 if ($isIndex) {
128 $propertyValue =& $this->readIndex($objectOrArray, $property);
129 } else {
130 $propertyValue =& $this->readProperty($objectOrArray, $property);
131 }
132
133 $objectOrArray =& $propertyValue[self::VALUE];
134
135 $propertyValues[] =& $propertyValue;
136 }
137
138 return $propertyValues;
139 }
140
141 /**
142 * Reads a key from an array-like structure.
143 *
144 * @param \ArrayAccess|array $array The array or \ArrayAccess object to read from
145 * @param string|integer $index The key to read
146 *
147 * @return mixed The value of the key
148 *
149 * @throws NoSuchPropertyException If the array does not implement \ArrayAccess or it is not an array
150 */
151 private function &readIndex(&$array, $index)
152 {
153 if (!$array instanceof \ArrayAccess && !is_array($array)) {
154 throw new NoSuchPropertyException(sprintf('Index "%s" cannot be read from object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array)));
155 }
156
157 // Use an array instead of an object since performance is very crucial here
158 $result = array(
159 self::VALUE => null,
160 self::IS_REF => false
161 );
162
163 if (isset($array[$index])) {
164 if (is_array($array)) {
165 $result[self::VALUE] =& $array[$index];
166 $result[self::IS_REF] = true;
167 } else {
168 $result[self::VALUE] = $array[$index];
169 // Objects are always passed around by reference
170 $result[self::IS_REF] = is_object($array[$index]) ? true : false;
171 }
172 }
173
174 return $result;
175 }
176
177 /**
178 * Reads the a property from an object or array.
179 *
180 * @param object $object The object to read from.
181 * @param string $property The property to read.
182 *
183 * @return mixed The value of the read property
184 *
185 * @throws NoSuchPropertyException If the property does not exist or is not
186 * public.
187 */
188 private function &readProperty(&$object, $property)
189 {
190 // Use an array instead of an object since performance is
191 // very crucial here
192 $result = array(
193 self::VALUE => null,
194 self::IS_REF => false
195 );
196
197 if (!is_object($object)) {
198 throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you should write the property path as "[%s]" instead?', $property, $property));
199 }
200
201 $camelProp = $this->camelize($property);
202 $reflClass = new \ReflectionClass($object);
203 $getter = 'get'.$camelProp;
204 $isser = 'is'.$camelProp;
205 $hasser = 'has'.$camelProp;
206 $classHasProperty = $reflClass->hasProperty($property);
207
208 if ($reflClass->hasMethod($getter) && $reflClass->getMethod($getter)->isPublic()) {
209 $result[self::VALUE] = $object->$getter();
210 } elseif ($reflClass->hasMethod($isser) && $reflClass->getMethod($isser)->isPublic()) {
211 $result[self::VALUE] = $object->$isser();
212 } elseif ($reflClass->hasMethod($hasser) && $reflClass->getMethod($hasser)->isPublic()) {
213 $result[self::VALUE] = $object->$hasser();
214 } elseif ($reflClass->hasMethod('__get') && $reflClass->getMethod('__get')->isPublic()) {
215 $result[self::VALUE] = $object->$property;
216 } elseif ($classHasProperty && $reflClass->getProperty($property)->isPublic()) {
217 $result[self::VALUE] =& $object->$property;
218 $result[self::IS_REF] = true;
219 } elseif (!$classHasProperty && property_exists($object, $property)) {
220 // Needed to support \stdClass instances. We need to explicitly
221 // exclude $classHasProperty, otherwise if in the previous clause
222 // a *protected* property was found on the class, property_exists()
223 // returns true, consequently the following line will result in a
224 // fatal error.
225 $result[self::VALUE] =& $object->$property;
226 $result[self::IS_REF] = true;
227 } elseif ($this->magicCall && $reflClass->hasMethod('__call') && $reflClass->getMethod('__call')->isPublic()) {
228 // we call the getter and hope the __call do the job
229 $result[self::VALUE] = $object->$getter();
230 } else {
231 throw new NoSuchPropertyException(sprintf(
232 'Neither the property "%s" nor one of the methods "%s()", '.
233 '"%s()", "%s()", "__get()" or "__call()" exist and have public access in '.
234 'class "%s".',
235 $property,
236 $getter,
237 $isser,
238 $hasser,
239 $reflClass->name
240 ));
241 }
242
243 // Objects are always passed around by reference
244 if (is_object($result[self::VALUE])) {
245 $result[self::IS_REF] = true;
246 }
247
248 return $result;
249 }
250
251 /**
252 * Sets the value of the property at the given index in the path
253 *
254 * @param \ArrayAccess|array $array An array or \ArrayAccess object to write to
255 * @param string|integer $index The index to write at
256 * @param mixed $value The value to write
257 *
258 * @throws NoSuchPropertyException If the array does not implement \ArrayAccess or it is not an array
259 */
260 private function writeIndex(&$array, $index, $value)
261 {
262 if (!$array instanceof \ArrayAccess && !is_array($array)) {
263 throw new NoSuchPropertyException(sprintf('Index "%s" cannot be modified in object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array)));
264 }
265
266 $array[$index] = $value;
267 }
268
269 /**
270 * Sets the value of the property at the given index in the path
271 *
272 * @param object|array $object The object or array to write to
273 * @param string $property The property to write
274 * @param string|null $singular The singular form of the property name or null
275 * @param mixed $value The value to write
276 *
277 * @throws NoSuchPropertyException If the property does not exist or is not
278 * public.
279 */
280 private function writeProperty(&$object, $property, $singular, $value)
281 {
282 $guessedAdders = '';
283
284 if (!is_object($object)) {
285 throw new NoSuchPropertyException(sprintf('Cannot write property "%s" to an array. Maybe you should write the property path as "[%s]" instead?', $property, $property));
286 }
287
288 $reflClass = new \ReflectionClass($object);
289 $plural = $this->camelize($property);
290
291 // Any of the two methods is required, but not yet known
292 $singulars = null !== $singular ? array($singular) : (array) StringUtil::singularify($plural);
293
294 if (is_array($value) || $value instanceof \Traversable) {
295 $methods = $this->findAdderAndRemover($reflClass, $singulars);
296
297 if (null !== $methods) {
298 // At this point the add and remove methods have been found
299 // Use iterator_to_array() instead of clone in order to prevent side effects
300 // see https://github.com/symfony/symfony/issues/4670
301 $itemsToAdd = is_object($value) ? iterator_to_array($value) : $value;
302 $itemToRemove = array();
303 $propertyValue = $this->readProperty($object, $property);
304 $previousValue = $propertyValue[self::VALUE];
305
306 if (is_array($previousValue) || $previousValue instanceof \Traversable) {
307 foreach ($previousValue as $previousItem) {
308 foreach ($value as $key => $item) {
309 if ($item === $previousItem) {
310 // Item found, don't add
311 unset($itemsToAdd[$key]);
312
313 // Next $previousItem
314 continue 2;
315 }
316 }
317
318 // Item not found, add to remove list
319 $itemToRemove[] = $previousItem;
320 }
321 }
322
323 foreach ($itemToRemove as $item) {
324 call_user_func(array($object, $methods[1]), $item);
325 }
326
327 foreach ($itemsToAdd as $item) {
328 call_user_func(array($object, $methods[0]), $item);
329 }
330
331 return;
332 } else {
333 // It is sufficient to include only the adders in the error
334 // message. If the user implements the adder but not the remover,
335 // an exception will be thrown in findAdderAndRemover() that
336 // the remover has to be implemented as well.
337 $guessedAdders = '"add'.implode('()", "add', $singulars).'()", ';
338 }
339 }
340
341 $setter = 'set'.$this->camelize($property);
342 $classHasProperty = $reflClass->hasProperty($property);
343
344 if ($reflClass->hasMethod($setter) && $reflClass->getMethod($setter)->isPublic()) {
345 $object->$setter($value);
346 } elseif ($reflClass->hasMethod('__set') && $reflClass->getMethod('__set')->isPublic()) {
347 $object->$property = $value;
348 } elseif ($classHasProperty && $reflClass->getProperty($property)->isPublic()) {
349 $object->$property = $value;
350 } elseif (!$classHasProperty && property_exists($object, $property)) {
351 // Needed to support \stdClass instances. We need to explicitly
352 // exclude $classHasProperty, otherwise if in the previous clause
353 // a *protected* property was found on the class, property_exists()
354 // returns true, consequently the following line will result in a
355 // fatal error.
356 $object->$property = $value;
357 } elseif ($this->magicCall && $reflClass->hasMethod('__call') && $reflClass->getMethod('__call')->isPublic()) {
358 // we call the getter and hope the __call do the job
359 $object->$setter($value);
360 } else {
361 throw new NoSuchPropertyException(sprintf(
362 'Neither the property "%s" nor one of the methods %s"%s()", '.
363 '"__set()" or "__call()" exist and have public access in class "%s".',
364 $property,
365 $guessedAdders,
366 $setter,
367 $reflClass->name
368 ));
369 }
370 }
371
372 /**
373 * Camelizes a given string.
374 *
375 * @param string $string Some string
376 *
377 * @return string The camelized version of the string
378 */
379 private function camelize($string)
380 {
381 return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $string);
382 }
383
384 /**
385 * Searches for add and remove methods.
386 *
387 * @param \ReflectionClass $reflClass The reflection class for the given object
388 * @param array $singulars The singular form of the property name or null
389 *
390 * @return array|null An array containing the adder and remover when found, null otherwise
391 *
392 * @throws NoSuchPropertyException If the property does not exist
393 */
394 private function findAdderAndRemover(\ReflectionClass $reflClass, array $singulars)
395 {
396 foreach ($singulars as $singular) {
397 $addMethod = 'add'.$singular;
398 $removeMethod = 'remove'.$singular;
399
400 $addMethodFound = $this->isAccessible($reflClass, $addMethod, 1);
401 $removeMethodFound = $this->isAccessible($reflClass, $removeMethod, 1);
402
403 if ($addMethodFound && $removeMethodFound) {
404 return array($addMethod, $removeMethod);
405 }
406
407 if ($addMethodFound xor $removeMethodFound) {
408 throw new NoSuchPropertyException(sprintf(
409 'Found the public method "%s()", but did not find a public "%s()" on class %s',
410 $addMethodFound ? $addMethod : $removeMethod,
411 $addMethodFound ? $removeMethod : $addMethod,
412 $reflClass->name
413 ));
414 }
415 }
416
417 return null;
418 }
419
420 /**
421 * Returns whether a method is public and has a specific number of required parameters.
422 *
423 * @param \ReflectionClass $class The class of the method
424 * @param string $methodName The method name
425 * @param integer $parameters The number of parameters
426 *
427 * @return Boolean Whether the method is public and has $parameters
428 * required parameters
429 */
430 private function isAccessible(\ReflectionClass $class, $methodName, $parameters)
431 {
432 if ($class->hasMethod($methodName)) {
433 $method = $class->getMethod($methodName);
434
435 if ($method->isPublic() && $method->getNumberOfRequiredParameters() === $parameters) {
436 return true;
437 }
438 }
439
440 return false;
441 }
442}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php
new file mode 100644
index 00000000..25686e95
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php
@@ -0,0 +1,67 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14/**
15 * A configurable builder for PropertyAccessorInterface objects.
16 *
17 * @author Jérémie Augustin <jeremie.augustin@pixel-cookers.com>
18 */
19class PropertyAccessorBuilder
20{
21 /**
22 * @var Boolean
23 */
24 private $magicCall = false;
25
26 /**
27 * Enables the use of "__call" by the ProperyAccessor.
28 *
29 * @return PropertyAccessorBuilder The builder object
30 */
31 public function enableMagicCall()
32 {
33 $this->magicCall = true;
34
35 return $this;
36 }
37
38 /**
39 * Disables the use of "__call" by the ProperyAccessor.
40 *
41 * @return PropertyAccessorBuilder The builder object
42 */
43 public function disableMagicCall()
44 {
45 $this->magicCall = false;
46
47 return $this;
48 }
49
50 /**
51 * @return Boolean true if the use of "__call" by the ProperyAccessor is enabled
52 */
53 public function isMagicCallEnabled()
54 {
55 return $this->magicCall;
56 }
57
58 /**
59 * Builds and returns a new propertyAccessor object.
60 *
61 * @return PropertyAccessorInterface The built propertyAccessor
62 */
63 public function getPropertyAccessor()
64 {
65 return new PropertyAccessor($this->magicCall);
66 }
67}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php
new file mode 100644
index 00000000..1eed7c7b
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php
@@ -0,0 +1,81 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14/**
15 * Writes and reads values to/from an object/array graph.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface PropertyAccessorInterface
20{
21 /**
22 * Sets the value at the end of the property path of the object
23 *
24 * Example:
25 *
26 * use Symfony\Component\PropertyAccess\PropertyAccess;
27 *
28 * $propertyAccessor = PropertyAccess::getPropertyAccessor();
29 *
30 * echo $propertyAccessor->setValue($object, 'child.name', 'Fabien');
31 * // equals echo $object->getChild()->setName('Fabien');
32 *
33 * This method first tries to find a public setter for each property in the
34 * path. The name of the setter must be the camel-cased property name
35 * prefixed with "set".
36 *
37 * If the setter does not exist, this method tries to find a public
38 * property. The value of the property is then changed.
39 *
40 * If neither is found, an exception is thrown.
41 *
42 * @param object|array $objectOrArray The object or array to modify
43 * @param string|PropertyPathInterface $propertyPath The property path to modify
44 * @param mixed $value The value to set at the end of the property path
45 *
46 * @throws Exception\NoSuchPropertyException If a property does not exist or is not public.
47 * @throws Exception\UnexpectedTypeException If a value within the path is neither object
48 * nor array
49 */
50 public function setValue(&$objectOrArray, $propertyPath, $value);
51
52 /**
53 * Returns the value at the end of the property path of the object
54 *
55 * Example:
56 *
57 * use Symfony\Component\PropertyAccess\PropertyAccess;
58 *
59 * $propertyAccessor = PropertyAccess::getPropertyAccessor();
60 *
61 * echo $propertyAccessor->getValue($object, 'child.name);
62 * // equals echo $object->getChild()->getName();
63 *
64 * This method first tries to find a public getter for each property in the
65 * path. The name of the getter must be the camel-cased property name
66 * prefixed with "get", "is", or "has".
67 *
68 * If the getter does not exist, this method tries to find a public
69 * property. The value of the property is then returned.
70 *
71 * If none of them are found, an exception is thrown.
72 *
73 * @param object|array $objectOrArray The object or array to traverse
74 * @param string|PropertyPathInterface $propertyPath The property path to read
75 *
76 * @return mixed The value at the end of the property path
77 *
78 * @throws Exception\NoSuchPropertyException If a property does not exist or is not public.
79 */
80 public function getValue($objectOrArray, $propertyPath);
81}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPath.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPath.php
new file mode 100644
index 00000000..840fc715
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPath.php
@@ -0,0 +1,225 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14use Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException;
15use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException;
16use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
17
18/**
19 * Default implementation of {@link PropertyPathInterface}.
20 *
21 * @author Bernhard Schussek <bschussek@gmail.com>
22 */
23class PropertyPath implements \IteratorAggregate, PropertyPathInterface
24{
25 /**
26 * Character used for separating between plural and singular of an element.
27 * @var string
28 */
29 const SINGULAR_SEPARATOR = '|';
30
31 /**
32 * The elements of the property path
33 * @var array
34 */
35 private $elements = array();
36
37 /**
38 * The singular forms of the elements in the property path.
39 * @var array
40 */
41 private $singulars = array();
42
43 /**
44 * The number of elements in the property path
45 * @var integer
46 */
47 private $length;
48
49 /**
50 * Contains a Boolean for each property in $elements denoting whether this
51 * element is an index. It is a property otherwise.
52 * @var array
53 */
54 private $isIndex = array();
55
56 /**
57 * String representation of the path
58 * @var string
59 */
60 private $pathAsString;
61
62 /**
63 * Constructs a property path from a string.
64 *
65 * @param PropertyPath|string $propertyPath The property path as string or instance
66 *
67 * @throws UnexpectedTypeException If the given path is not a string
68 * @throws InvalidPropertyPathException If the syntax of the property path is not valid
69 */
70 public function __construct($propertyPath)
71 {
72 // Can be used as copy constructor
73 if ($propertyPath instanceof PropertyPath) {
74 /* @var PropertyPath $propertyPath */
75 $this->elements = $propertyPath->elements;
76 $this->singulars = $propertyPath->singulars;
77 $this->length = $propertyPath->length;
78 $this->isIndex = $propertyPath->isIndex;
79 $this->pathAsString = $propertyPath->pathAsString;
80
81 return;
82 }
83 if (!is_string($propertyPath)) {
84 throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPath');
85 }
86
87 if ('' === $propertyPath) {
88 throw new InvalidPropertyPathException('The property path should not be empty.');
89 }
90
91 $this->pathAsString = $propertyPath;
92 $position = 0;
93 $remaining = $propertyPath;
94
95 // first element is evaluated differently - no leading dot for properties
96 $pattern = '/^(([^\.\[]+)|\[([^\]]+)\])(.*)/';
97
98 while (preg_match($pattern, $remaining, $matches)) {
99 if ('' !== $matches[2]) {
100 $element = $matches[2];
101 $this->isIndex[] = false;
102 } else {
103 $element = $matches[3];
104 $this->isIndex[] = true;
105 }
106 // Disabled this behaviour as the syntax is not yet final
107 //$pos = strpos($element, self::SINGULAR_SEPARATOR);
108 $pos = false;
109 $singular = null;
110
111 if (false !== $pos) {
112 $singular = substr($element, $pos + 1);
113 $element = substr($element, 0, $pos);
114 }
115
116 $this->elements[] = $element;
117 $this->singulars[] = $singular;
118
119 $position += strlen($matches[1]);
120 $remaining = $matches[4];
121 $pattern = '/^(\.(\w+)|\[([^\]]+)\])(.*)/';
122 }
123
124 if ('' !== $remaining) {
125 throw new InvalidPropertyPathException(sprintf(
126 'Could not parse property path "%s". Unexpected token "%s" at position %d',
127 $propertyPath,
128 $remaining{0},
129 $position
130 ));
131 }
132
133 $this->length = count($this->elements);
134 }
135
136 /**
137 * {@inheritdoc}
138 */
139 public function __toString()
140 {
141 return $this->pathAsString;
142 }
143
144 /**
145 * {@inheritdoc}
146 */
147 public function getLength()
148 {
149 return $this->length;
150 }
151
152 /**
153 * {@inheritdoc}
154 */
155 public function getParent()
156 {
157 if ($this->length <= 1) {
158 return null;
159 }
160
161 $parent = clone $this;
162
163 --$parent->length;
164 $parent->pathAsString = substr($parent->pathAsString, 0, max(strrpos($parent->pathAsString, '.'), strrpos($parent->pathAsString, '[')));
165 array_pop($parent->elements);
166 array_pop($parent->singulars);
167 array_pop($parent->isIndex);
168
169 return $parent;
170 }
171
172 /**
173 * Returns a new iterator for this path
174 *
175 * @return PropertyPathIteratorInterface
176 */
177 public function getIterator()
178 {
179 return new PropertyPathIterator($this);
180 }
181
182 /**
183 * {@inheritdoc}
184 */
185 public function getElements()
186 {
187 return $this->elements;
188 }
189
190 /**
191 * {@inheritdoc}
192 */
193 public function getElement($index)
194 {
195 if (!isset($this->elements[$index])) {
196 throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index));
197 }
198
199 return $this->elements[$index];
200 }
201
202 /**
203 * {@inheritdoc}
204 */
205 public function isProperty($index)
206 {
207 if (!isset($this->isIndex[$index])) {
208 throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index));
209 }
210
211 return !$this->isIndex[$index];
212 }
213
214 /**
215 * {@inheritdoc}
216 */
217 public function isIndex($index)
218 {
219 if (!isset($this->isIndex[$index])) {
220 throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index));
221 }
222
223 return $this->isIndex[$index];
224 }
225}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathBuilder.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathBuilder.php
new file mode 100644
index 00000000..f4eb0fb9
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathBuilder.php
@@ -0,0 +1,306 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class PropertyPathBuilder
20{
21 /**
22 * @var array
23 */
24 private $elements = array();
25
26 /**
27 * @var array
28 */
29 private $isIndex = array();
30
31 /**
32 * Creates a new property path builder.
33 *
34 * @param null|PropertyPathInterface|string $path The path to initially store
35 * in the builder. Optional.
36 */
37 public function __construct($path = null)
38 {
39 if (null !== $path) {
40 $this->append($path);
41 }
42 }
43
44 /**
45 * Appends a (sub-) path to the current path.
46 *
47 * @param PropertyPathInterface|string $path The path to append.
48 * @param integer $offset The offset where the appended
49 * piece starts in $path.
50 * @param integer $length The length of the appended piece.
51 * If 0, the full path is appended.
52 */
53 public function append($path, $offset = 0, $length = 0)
54 {
55 if (is_string($path)) {
56 $path = new PropertyPath($path);
57 }
58
59 if (0 === $length) {
60 $end = $path->getLength();
61 } else {
62 $end = $offset + $length;
63 }
64
65 for (; $offset < $end; ++$offset) {
66 $this->elements[] = $path->getElement($offset);
67 $this->isIndex[] = $path->isIndex($offset);
68 }
69 }
70
71 /**
72 * Appends an index element to the current path.
73 *
74 * @param string $name The name of the appended index
75 */
76 public function appendIndex($name)
77 {
78 $this->elements[] = $name;
79 $this->isIndex[] = true;
80 }
81
82 /**
83 * Appends a property element to the current path.
84 *
85 * @param string $name The name of the appended property
86 */
87 public function appendProperty($name)
88 {
89 $this->elements[] = $name;
90 $this->isIndex[] = false;
91 }
92
93 /**
94 * Removes elements from the current path.
95 *
96 * @param integer $offset The offset at which to remove
97 * @param integer $length The length of the removed piece
98 *
99 * @throws OutOfBoundsException if offset is invalid
100 */
101 public function remove($offset, $length = 1)
102 {
103 if (!isset($this->elements[$offset])) {
104 throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset));
105 }
106
107 $this->resize($offset, $length, 0);
108 }
109
110 /**
111 * Replaces a sub-path by a different (sub-) path.
112 *
113 * @param integer $offset The offset at which to replace.
114 * @param integer $length The length of the piece to replace.
115 * @param PropertyPathInterface|string $path The path to insert.
116 * @param integer $pathOffset The offset where the inserted piece
117 * starts in $path.
118 * @param integer $pathLength The length of the inserted piece.
119 * If 0, the full path is inserted.
120 *
121 * @throws OutOfBoundsException If the offset is invalid
122 */
123 public function replace($offset, $length, $path, $pathOffset = 0, $pathLength = 0)
124 {
125 if (is_string($path)) {
126 $path = new PropertyPath($path);
127 }
128
129 if ($offset < 0 && abs($offset) <= $this->getLength()) {
130 $offset = $this->getLength() + $offset;
131 } elseif (!isset($this->elements[$offset])) {
132 throw new OutOfBoundsException('The offset ' . $offset . ' is not within the property path');
133 }
134
135 if (0 === $pathLength) {
136 $pathLength = $path->getLength() - $pathOffset;
137 }
138
139 $this->resize($offset, $length, $pathLength);
140
141 for ($i = 0; $i < $pathLength; ++$i) {
142 $this->elements[$offset + $i] = $path->getElement($pathOffset + $i);
143 $this->isIndex[$offset + $i] = $path->isIndex($pathOffset + $i);
144 }
145 }
146
147 /**
148 * Replaces a property element by an index element.
149 *
150 * @param integer $offset The offset at which to replace
151 * @param string $name The new name of the element. Optional.
152 *
153 * @throws OutOfBoundsException If the offset is invalid
154 */
155 public function replaceByIndex($offset, $name = null)
156 {
157 if (!isset($this->elements[$offset])) {
158 throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset));
159 }
160
161 if (null !== $name) {
162 $this->elements[$offset] = $name;
163 }
164
165 $this->isIndex[$offset] = true;
166 }
167
168 /**
169 * Replaces an index element by a property element.
170 *
171 * @param integer $offset The offset at which to replace
172 * @param string $name The new name of the element. Optional.
173 *
174 * @throws OutOfBoundsException If the offset is invalid
175 */
176 public function replaceByProperty($offset, $name = null)
177 {
178 if (!isset($this->elements[$offset])) {
179 throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset));
180 }
181
182 if (null !== $name) {
183 $this->elements[$offset] = $name;
184 }
185
186 $this->isIndex[$offset] = false;
187 }
188
189 /**
190 * Returns the length of the current path.
191 *
192 * @return integer The path length
193 */
194 public function getLength()
195 {
196 return count($this->elements);
197 }
198
199 /**
200 * Returns the current property path.
201 *
202 * @return PropertyPathInterface The constructed property path
203 */
204 public function getPropertyPath()
205 {
206 $pathAsString = $this->__toString();
207
208 return '' !== $pathAsString ? new PropertyPath($pathAsString) : null;
209 }
210
211 /**
212 * Returns the current property path as string.
213 *
214 * @return string The property path as string
215 */
216 public function __toString()
217 {
218 $string = '';
219
220 foreach ($this->elements as $offset => $element) {
221 if ($this->isIndex[$offset]) {
222 $element = '['.$element.']';
223 } elseif ('' !== $string) {
224 $string .= '.';
225 }
226
227 $string .= $element;
228 }
229
230 return $string;
231 }
232
233 /**
234 * Resizes the path so that a chunk of length $cutLength is
235 * removed at $offset and another chunk of length $insertionLength
236 * can be inserted.
237 *
238 * @param integer $offset The offset where the removed chunk starts
239 * @param integer $cutLength The length of the removed chunk
240 * @param integer $insertionLength The length of the inserted chunk
241 */
242 private function resize($offset, $cutLength, $insertionLength)
243 {
244 // Nothing else to do in this case
245 if ($insertionLength === $cutLength) {
246 return;
247 }
248
249 $length = count($this->elements);
250
251 if ($cutLength > $insertionLength) {
252 // More elements should be removed than inserted
253 $diff = $cutLength - $insertionLength;
254 $newLength = $length - $diff;
255
256 // Shift elements to the left (left-to-right until the new end)
257 // Max allowed offset to be shifted is such that
258 // $offset + $diff < $length (otherwise invalid index access)
259 // i.e. $offset < $length - $diff = $newLength
260 for ($i = $offset; $i < $newLength; ++$i) {
261 $this->elements[$i] = $this->elements[$i + $diff];
262 $this->isIndex[$i] = $this->isIndex[$i + $diff];
263 }
264
265 // All remaining elements should be removed
266 for (; $i < $length; ++$i) {
267 unset($this->elements[$i]);
268 unset($this->isIndex[$i]);
269 }
270 } else {
271 $diff = $insertionLength - $cutLength;
272
273 $newLength = $length + $diff;
274 $indexAfterInsertion = $offset + $insertionLength;
275
276 // $diff <= $insertionLength
277 // $indexAfterInsertion >= $insertionLength
278 // => $diff <= $indexAfterInsertion
279
280 // In each of the following loops, $i >= $diff must hold,
281 // otherwise ($i - $diff) becomes negative.
282
283 // Shift old elements to the right to make up space for the
284 // inserted elements. This needs to be done left-to-right in
285 // order to preserve an ascending array index order
286 // Since $i = max($length, $indexAfterInsertion) and $indexAfterInsertion >= $diff,
287 // $i >= $diff is guaranteed.
288 for ($i = max($length, $indexAfterInsertion); $i < $newLength; ++$i) {
289 $this->elements[$i] = $this->elements[$i - $diff];
290 $this->isIndex[$i] = $this->isIndex[$i - $diff];
291 }
292
293 // Shift remaining elements to the right. Do this right-to-left
294 // so we don't overwrite elements before copying them
295 // The last written index is the immediate index after the inserted
296 // string, because the indices before that will be overwritten
297 // anyway.
298 // Since $i >= $indexAfterInsertion and $indexAfterInsertion >= $diff,
299 // $i >= $diff is guaranteed.
300 for ($i = $length - 1; $i >= $indexAfterInsertion; --$i) {
301 $this->elements[$i] = $this->elements[$i - $diff];
302 $this->isIndex[$i] = $this->isIndex[$i - $diff];
303 }
304 }
305 }
306}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathInterface.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathInterface.php
new file mode 100644
index 00000000..95f34ffa
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathInterface.php
@@ -0,0 +1,86 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14/**
15 * A sequence of property names or array indices.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface PropertyPathInterface extends \Traversable
20{
21 /**
22 * Returns the string representation of the property path
23 *
24 * @return string The path as string
25 */
26 public function __toString();
27
28 /**
29 * Returns the length of the property path, i.e. the number of elements.
30 *
31 * @return integer The path length
32 */
33 public function getLength();
34
35 /**
36 * Returns the parent property path.
37 *
38 * The parent property path is the one that contains the same items as
39 * this one except for the last one.
40 *
41 * If this property path only contains one item, null is returned.
42 *
43 * @return PropertyPath The parent path or null
44 */
45 public function getParent();
46
47 /**
48 * Returns the elements of the property path as array
49 *
50 * @return array An array of property/index names
51 */
52 public function getElements();
53
54 /**
55 * Returns the element at the given index in the property path
56 *
57 * @param integer $index The index key
58 *
59 * @return string A property or index name
60 *
61 * @throws Exception\OutOfBoundsException If the offset is invalid
62 */
63 public function getElement($index);
64
65 /**
66 * Returns whether the element at the given index is a property
67 *
68 * @param integer $index The index in the property path
69 *
70 * @return Boolean Whether the element at this index is a property
71 *
72 * @throws Exception\OutOfBoundsException If the offset is invalid
73 */
74 public function isProperty($index);
75
76 /**
77 * Returns whether the element at the given index is an array index
78 *
79 * @param integer $index The index in the property path
80 *
81 * @return Boolean Whether the element at this index is an array index
82 *
83 * @throws Exception\OutOfBoundsException If the offset is invalid
84 */
85 public function isIndex($index);
86}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIterator.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIterator.php
new file mode 100644
index 00000000..d6cd49ca
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIterator.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14/**
15 * Traverses a property path and provides additional methods to find out
16 * information about the current element
17 *
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class PropertyPathIterator extends \ArrayIterator implements PropertyPathIteratorInterface
21{
22 /**
23 * The traversed property path
24 * @var PropertyPathInterface
25 */
26 protected $path;
27
28 /**
29 * Constructor.
30 *
31 * @param PropertyPathInterface $path The property path to traverse
32 */
33 public function __construct(PropertyPathInterface $path)
34 {
35 parent::__construct($path->getElements());
36
37 $this->path = $path;
38 }
39
40 /**
41 * {@inheritdoc}
42 */
43 public function isIndex()
44 {
45 return $this->path->isIndex($this->key());
46 }
47
48 /**
49 * {@inheritdoc}
50 */
51 public function isProperty()
52 {
53 return $this->path->isProperty($this->key());
54 }
55}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIteratorInterface.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIteratorInterface.php
new file mode 100644
index 00000000..cb43f8d7
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIteratorInterface.php
@@ -0,0 +1,34 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17interface PropertyPathIteratorInterface extends \Iterator, \SeekableIterator
18{
19 /**
20 * Returns whether the current element in the property path is an array
21 * index.
22 *
23 * @return Boolean
24 */
25 public function isIndex();
26
27 /**
28 * Returns whether the current element in the property path is a property
29 * name.
30 *
31 * @return Boolean
32 */
33 public function isProperty();
34}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/README.md b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/README.md
new file mode 100644
index 00000000..0ae94e08
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/README.md
@@ -0,0 +1,14 @@
1PropertyAccess Component
2========================
3
4PropertyAccess reads/writes values from/to object/array graphs using a simple
5string notation.
6
7Resources
8---------
9
10You can run the unit tests with the following command:
11
12 $ cd path/to/Symfony/Component/PropertyAccess/
13 $ composer.phar install --dev
14 $ phpunit
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php
new file mode 100644
index 00000000..e782cc10
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php
@@ -0,0 +1,195 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\PropertyAccess;
13
14/**
15 * Creates singulars from plurals.
16 *
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19class StringUtil
20{
21 /**
22 * Map english plural to singular suffixes
23 *
24 * @var array
25 *
26 * @see http://english-zone.com/spelling/plurals.html
27 * @see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English
28 */
29 private static $pluralMap = array(
30 // First entry: plural suffix, reversed
31 // Second entry: length of plural suffix
32 // Third entry: Whether the suffix may succeed a vocal
33 // Fourth entry: Whether the suffix may succeed a consonant
34 // Fifth entry: singular suffix, normal
35
36 // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
37 array('a', 1, true, true, array('on', 'um')),
38
39 // nebulae (nebula)
40 array('ea', 2, true, true, 'a'),
41
42 // mice (mouse), lice (louse)
43 array('eci', 3, false, true, 'ouse'),
44
45 // geese (goose)
46 array('esee', 4, false, true, 'oose'),
47
48 // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
49 array('i', 1, true, true, 'us'),
50
51 // men (man), women (woman)
52 array('nem', 3, true, true, 'man'),
53
54 // children (child)
55 array('nerdlihc', 8, true, true, 'child'),
56
57 // oxen (ox)
58 array('nexo', 4, false, false, 'ox'),
59
60 // indices (index), appendices (appendix), prices (price)
61 array('seci', 4, false, true, array('ex', 'ix', 'ice')),
62
63 // babies (baby)
64 array('sei', 3, false, true, 'y'),
65
66 // analyses (analysis), ellipses (ellipsis), funguses (fungus),
67 // neuroses (neurosis), theses (thesis), emphases (emphasis),
68 // oases (oasis), crises (crisis), houses (house), bases (base),
69 // atlases (atlas), kisses (kiss)
70 array('ses', 3, true, true, array('s', 'se', 'sis')),
71
72 // objectives (objective), alternative (alternatives)
73 array('sevit', 5, true, true, 'tive'),
74
75 // lives (life), wives (wife)
76 array('sevi', 4, false, true, 'ife'),
77
78 // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
79 array('sev', 3, true, true, 'f'),
80
81 // axes (axis), axes (ax), axes (axe)
82 array('sexa', 4, false, false, array('ax', 'axe', 'axis')),
83
84 // indexes (index), matrixes (matrix)
85 array('sex', 3, true, false, 'x'),
86
87 // quizzes (quiz)
88 array('sezz', 4, true, false, 'z'),
89
90 // bureaus (bureau)
91 array('suae', 4, false, true, 'eau'),
92
93 // roses (rose), garages (garage), cassettes (cassette),
94 // waltzes (waltz), heroes (hero), bushes (bush), arches (arch),
95 // shoes (shoe)
96 array('se', 2, true, true, array('', 'e')),
97
98 // tags (tag)
99 array('s', 1, true, true, ''),
100
101 // chateaux (chateau)
102 array('xuae', 4, false, true, 'eau'),
103 );
104
105 /**
106 * This class should not be instantiated
107 */
108 private function __construct() {}
109
110 /**
111 * Returns the singular form of a word
112 *
113 * If the method can't determine the form with certainty, an array of the
114 * possible singulars is returned.
115 *
116 * @param string $plural A word in plural form
117 * @return string|array The singular form or an array of possible singular
118 * forms
119 */
120 public static function singularify($plural)
121 {
122 $pluralRev = strrev($plural);
123 $lowerPluralRev = strtolower($pluralRev);
124 $pluralLength = strlen($lowerPluralRev);
125
126 // The outer loop iterates over the entries of the plural table
127 // The inner loop $j iterates over the characters of the plural suffix
128 // in the plural table to compare them with the characters of the actual
129 // given plural suffix
130 foreach (self::$pluralMap as $map) {
131 $suffix = $map[0];
132 $suffixLength = $map[1];
133 $j = 0;
134
135 // Compare characters in the plural table and of the suffix of the
136 // given plural one by one
137 while ($suffix[$j] === $lowerPluralRev[$j]) {
138 // Let $j point to the next character
139 ++$j;
140
141 // Successfully compared the last character
142 // Add an entry with the singular suffix to the singular array
143 if ($j === $suffixLength) {
144 // Is there any character preceding the suffix in the plural string?
145 if ($j < $pluralLength) {
146 $nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]);
147
148 if (!$map[2] && $nextIsVocal) {
149 // suffix may not succeed a vocal but next char is one
150 break;
151 }
152
153 if (!$map[3] && !$nextIsVocal) {
154 // suffix may not succeed a consonant but next char is one
155 break;
156 }
157 }
158
159 $newBase = substr($plural, 0, $pluralLength - $suffixLength);
160 $newSuffix = $map[4];
161
162 // Check whether the first character in the plural suffix
163 // is uppercased. If yes, uppercase the first character in
164 // the singular suffix too
165 $firstUpper = ctype_upper($pluralRev[$j - 1]);
166
167 if (is_array($newSuffix)) {
168 $singulars = array();
169
170 foreach ($newSuffix as $newSuffixEntry) {
171 $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);
172 }
173
174 return $singulars;
175 }
176
177 return $newBase.($firstUpper ? ucFirst($newSuffix) : $newSuffix);
178 }
179
180 // Suffix is longer than word
181 if ($j === $pluralLength) {
182 break;
183 }
184 }
185 }
186
187 // Convert teeth to tooth, feet to foot
188 if (false !== ($pos = strpos($plural, 'ee'))) {
189 return substr_replace($plural, 'oo', $pos, 2);
190 }
191
192 // Assume that plural and singular is identical
193 return $plural;
194 }
195}
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/composer.json b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/composer.json
new file mode 100644
index 00000000..31860427
--- /dev/null
+++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/composer.json
@@ -0,0 +1,31 @@
1{
2 "name": "symfony/property-access",
3 "type": "library",
4 "description": "Symfony PropertyAccess Component",
5 "keywords": ["property", "index", "access", "object", "array", "extraction", "injection", "reflection", "property path"],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3"
20 },
21 "autoload": {
22 "psr-0": { "Symfony\\Component\\PropertyAccess\\": "" }
23 },
24 "target-dir": "Symfony/Component/PropertyAccess",
25 "minimum-stability": "dev",
26 "extra": {
27 "branch-alias": {
28 "dev-master": "2.3-dev"
29 }
30 }
31}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/.gitignore b/vendor/symfony/routing/Symfony/Component/Routing/.gitignore
new file mode 100644
index 00000000..44de97a3
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/.gitignore
@@ -0,0 +1,4 @@
1vendor/
2composer.lock
3phpunit.xml
4
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Annotation/Route.php b/vendor/symfony/routing/Symfony/Component/Routing/Annotation/Route.php
new file mode 100644
index 00000000..abdbea27
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Annotation/Route.php
@@ -0,0 +1,156 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Annotation;
13
14/**
15 * Annotation class for @Route().
16 *
17 * @Annotation
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class Route
22{
23 private $path;
24 private $name;
25 private $requirements;
26 private $options;
27 private $defaults;
28 private $host;
29 private $methods;
30 private $schemes;
31
32 /**
33 * Constructor.
34 *
35 * @param array $data An array of key/value parameters.
36 *
37 * @throws \BadMethodCallException
38 */
39 public function __construct(array $data)
40 {
41 $this->requirements = array();
42 $this->options = array();
43 $this->defaults = array();
44 $this->methods = array();
45 $this->schemes = array();
46
47 if (isset($data['value'])) {
48 $data['path'] = $data['value'];
49 unset($data['value']);
50 }
51
52 foreach ($data as $key => $value) {
53 $method = 'set'.str_replace('_', '', $key);
54 if (!method_exists($this, $method)) {
55 throw new \BadMethodCallException(sprintf("Unknown property '%s' on annotation '%s'.", $key, get_class($this)));
56 }
57 $this->$method($value);
58 }
59 }
60
61 /**
62 * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead.
63 */
64 public function setPattern($pattern)
65 {
66 $this->path = $pattern;
67 }
68
69 /**
70 * @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead.
71 */
72 public function getPattern()
73 {
74 return $this->path;
75 }
76
77 public function setPath($path)
78 {
79 $this->path = $path;
80 }
81
82 public function getPath()
83 {
84 return $this->path;
85 }
86
87 public function setHost($pattern)
88 {
89 $this->host = $pattern;
90 }
91
92 public function getHost()
93 {
94 return $this->host;
95 }
96
97 public function setName($name)
98 {
99 $this->name = $name;
100 }
101
102 public function getName()
103 {
104 return $this->name;
105 }
106
107 public function setRequirements($requirements)
108 {
109 $this->requirements = $requirements;
110 }
111
112 public function getRequirements()
113 {
114 return $this->requirements;
115 }
116
117 public function setOptions($options)
118 {
119 $this->options = $options;
120 }
121
122 public function getOptions()
123 {
124 return $this->options;
125 }
126
127 public function setDefaults($defaults)
128 {
129 $this->defaults = $defaults;
130 }
131
132 public function getDefaults()
133 {
134 return $this->defaults;
135 }
136
137 public function setSchemes($schemes)
138 {
139 $this->schemes = is_array($schemes) ? $schemes : array($schemes);
140 }
141
142 public function getSchemes()
143 {
144 return $this->schemes;
145 }
146
147 public function setMethods($methods)
148 {
149 $this->methods = is_array($methods) ? $methods : array($methods);
150 }
151
152 public function getMethods()
153 {
154 return $this->methods;
155 }
156}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/CHANGELOG.md b/vendor/symfony/routing/Symfony/Component/Routing/CHANGELOG.md
new file mode 100644
index 00000000..f0c616d0
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/CHANGELOG.md
@@ -0,0 +1,162 @@
1CHANGELOG
2=========
3
42.3.0
5-----
6
7 * added RequestContext::getQueryString()
8
92.2.0
10-----
11
12 * [DEPRECATION] Several route settings have been renamed (the old ones will be removed in 3.0):
13
14 * The `pattern` setting for a route has been deprecated in favor of `path`
15 * The `_scheme` and `_method` requirements have been moved to the `schemes` and `methods` settings
16
17 Before:
18
19 ```
20 article_edit:
21 pattern: /article/{id}
22 requirements: { '_method': 'POST|PUT', '_scheme': 'https', 'id': '\d+' }
23
24 <route id="article_edit" pattern="/article/{id}">
25 <requirement key="_method">POST|PUT</requirement>
26 <requirement key="_scheme">https</requirement>
27 <requirement key="id">\d+</requirement>
28 </route>
29
30 $route = new Route();
31 $route->setPattern('/article/{id}');
32 $route->setRequirement('_method', 'POST|PUT');
33 $route->setRequirement('_scheme', 'https');
34 ```
35
36 After:
37
38 ```
39 article_edit:
40 path: /article/{id}
41 methods: [POST, PUT]
42 schemes: https
43 requirements: { 'id': '\d+' }
44
45 <route id="article_edit" pattern="/article/{id}" methods="POST PUT" schemes="https">
46 <requirement key="id">\d+</requirement>
47 </route>
48
49 $route = new Route();
50 $route->setPath('/article/{id}');
51 $route->setMethods(array('POST', 'PUT'));
52 $route->setSchemes('https');
53 ```
54
55 * [BC BREAK] RouteCollection does not behave like a tree structure anymore but as
56 a flat array of Routes. So when using PHP to build the RouteCollection, you must
57 make sure to add routes to the sub-collection before adding it to the parent
58 collection (this is not relevant when using YAML or XML for Route definitions).
59
60 Before:
61
62 ```
63 $rootCollection = new RouteCollection();
64 $subCollection = new RouteCollection();
65 $rootCollection->addCollection($subCollection);
66 $subCollection->add('foo', new Route('/foo'));
67 ```
68
69 After:
70
71 ```
72 $rootCollection = new RouteCollection();
73 $subCollection = new RouteCollection();
74 $subCollection->add('foo', new Route('/foo'));
75 $rootCollection->addCollection($subCollection);
76 ```
77
78 Also one must call `addCollection` from the bottom to the top hierarchy.
79 So the correct sequence is the following (and not the reverse):
80
81 ```
82 $childCollection->->addCollection($grandchildCollection);
83 $rootCollection->addCollection($childCollection);
84 ```
85
86 * [DEPRECATION] The methods `RouteCollection::getParent()` and `RouteCollection::getRoot()`
87 have been deprecated and will be removed in Symfony 2.3.
88 * [BC BREAK] Misusing the `RouteCollection::addPrefix` method to add defaults, requirements
89 or options without adding a prefix is not supported anymore. So if you called `addPrefix`
90 with an empty prefix or `/` only (both have no relevance), like
91 `addPrefix('', $defaultsArray, $requirementsArray, $optionsArray)`
92 you need to use the new dedicated methods `addDefaults($defaultsArray)`,
93 `addRequirements($requirementsArray)` or `addOptions($optionsArray)` instead.
94 * [DEPRECATION] The `$options` parameter to `RouteCollection::addPrefix()` has been deprecated
95 because adding options has nothing to do with adding a path prefix. If you want to add options
96 to all child routes of a RouteCollection, you can use `addOptions()`.
97 * [DEPRECATION] The method `RouteCollection::getPrefix()` has been deprecated
98 because it suggested that all routes in the collection would have this prefix, which is
99 not necessarily true. On top of that, since there is no tree structure anymore, this method
100 is also useless. Don't worry about performance, prefix optimization for matching is still done
101 in the dumper, which was also improved in 2.2.0 to find even more grouping possibilities.
102 * [DEPRECATION] `RouteCollection::addCollection(RouteCollection $collection)` should now only be
103 used with a single parameter. The other params `$prefix`, `$default`, `$requirements` and `$options`
104 will still work, but have been deprecated. The `addPrefix` method should be used for this
105 use-case instead.
106 Before: `$parentCollection->addCollection($collection, '/prefix', array(...), array(...))`
107 After:
108 ```
109 $collection->addPrefix('/prefix', array(...), array(...));
110 $parentCollection->addCollection($collection);
111 ```
112 * added support for the method default argument values when defining a @Route
113 * Adjacent placeholders without separator work now, e.g. `/{x}{y}{z}.{_format}`.
114 * Characters that function as separator between placeholders are now whitelisted
115 to fix routes with normal text around a variable, e.g. `/prefix{var}suffix`.
116 * [BC BREAK] The default requirement of a variable has been changed slightly.
117 Previously it disallowed the previous and the next char around a variable. Now
118 it disallows the slash (`/`) and the next char. Using the previous char added
119 no value and was problematic because the route `/index.{_format}` would be
120 matched by `/index.ht/ml`.
121 * The default requirement now uses possessive quantifiers when possible which
122 improves matching performance by up to 20% because it prevents backtracking
123 when it's not needed.
124 * The ConfigurableRequirementsInterface can now also be used to disable the requirements
125 check on URL generation completely by calling `setStrictRequirements(null)`. It
126 improves performance in production environment as you should know that params always
127 pass the requirements (otherwise it would break your link anyway).
128 * There is no restriction on the route name anymore. So non-alphanumeric characters
129 are now also allowed.
130 * [BC BREAK] `RouteCompilerInterface::compile(Route $route)` was made static
131 (only relevant if you implemented your own RouteCompiler).
132 * Added possibility to generate relative paths and network paths in the UrlGenerator, e.g.
133 "../parent-file" and "//example.com/dir/file". The third parameter in
134 `UrlGeneratorInterface::generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)`
135 now accepts more values and you should use the constants defined in `UrlGeneratorInterface` for
136 claritiy. The old method calls with a Boolean parameter will continue to work because they
137 equal the signature using the constants.
138
1392.1.0
140-----
141
142 * added RequestMatcherInterface
143 * added RequestContext::fromRequest()
144 * the UrlMatcher does not throw a \LogicException anymore when the required
145 scheme is not the current one
146 * added TraceableUrlMatcher
147 * added the possibility to define options, default values and requirements
148 for placeholders in prefix, including imported routes
149 * added RouterInterface::getRouteCollection
150 * [BC BREAK] the UrlMatcher urldecodes the route parameters only once, they
151 were decoded twice before. Note that the `urldecode()` calls have been
152 changed for a single `rawurldecode()` in order to support `+` for input
153 paths.
154 * added RouteCollection::getRoot method to retrieve the root of a
155 RouteCollection tree
156 * [BC BREAK] made RouteCollection::setParent private which could not have
157 been used anyway without creating inconsistencies
158 * [BC BREAK] RouteCollection::remove also removes a route from parent
159 collections (not only from its children)
160 * added ConfigurableRequirementsInterface that allows to disable exceptions
161 (and generate empty URLs instead) when generating a route with an invalid
162 parameter value
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/CompiledRoute.php b/vendor/symfony/routing/Symfony/Component/Routing/CompiledRoute.php
new file mode 100644
index 00000000..78784554
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/CompiledRoute.php
@@ -0,0 +1,134 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing;
13
14/**
15 * CompiledRoutes are returned by the RouteCompiler class.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19class CompiledRoute
20{
21 private $variables;
22 private $tokens;
23 private $staticPrefix;
24 private $regex;
25 private $pathVariables;
26 private $hostVariables;
27 private $hostRegex;
28 private $hostTokens;
29
30 /**
31 * Constructor.
32 *
33 * @param string $staticPrefix The static prefix of the compiled route
34 * @param string $regex The regular expression to use to match this route
35 * @param array $tokens An array of tokens to use to generate URL for this route
36 * @param array $pathVariables An array of path variables
37 * @param string|null $hostRegex Host regex
38 * @param array $hostTokens Host tokens
39 * @param array $hostVariables An array of host variables
40 * @param array $variables An array of variables (variables defined in the path and in the host patterns)
41 */
42 public function __construct($staticPrefix, $regex, array $tokens, array $pathVariables, $hostRegex = null, array $hostTokens = array(), array $hostVariables = array(), array $variables = array())
43 {
44 $this->staticPrefix = (string) $staticPrefix;
45 $this->regex = $regex;
46 $this->tokens = $tokens;
47 $this->pathVariables = $pathVariables;
48 $this->hostRegex = $hostRegex;
49 $this->hostTokens = $hostTokens;
50 $this->hostVariables = $hostVariables;
51 $this->variables = $variables;
52 }
53
54 /**
55 * Returns the static prefix.
56 *
57 * @return string The static prefix
58 */
59 public function getStaticPrefix()
60 {
61 return $this->staticPrefix;
62 }
63
64 /**
65 * Returns the regex.
66 *
67 * @return string The regex
68 */
69 public function getRegex()
70 {
71 return $this->regex;
72 }
73
74 /**
75 * Returns the host regex
76 *
77 * @return string|null The host regex or null
78 */
79 public function getHostRegex()
80 {
81 return $this->hostRegex;
82 }
83
84 /**
85 * Returns the tokens.
86 *
87 * @return array The tokens
88 */
89 public function getTokens()
90 {
91 return $this->tokens;
92 }
93
94 /**
95 * Returns the host tokens.
96 *
97 * @return array The tokens
98 */
99 public function getHostTokens()
100 {
101 return $this->hostTokens;
102 }
103
104 /**
105 * Returns the variables.
106 *
107 * @return array The variables
108 */
109 public function getVariables()
110 {
111 return $this->variables;
112 }
113
114 /**
115 * Returns the path variables.
116 *
117 * @return array The variables
118 */
119 public function getPathVariables()
120 {
121 return $this->pathVariables;
122 }
123
124 /**
125 * Returns the host variables.
126 *
127 * @return array The variables
128 */
129 public function getHostVariables()
130 {
131 return $this->hostVariables;
132 }
133
134}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..5289f525
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * ExceptionInterface
16 *
17 * @author Alexandre Salomé <alexandre.salome@gmail.com>
18 *
19 * @api
20 */
21interface ExceptionInterface
22{
23}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php
new file mode 100644
index 00000000..4f124695
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * Exception thrown when a parameter is not valid
16 *
17 * @author Alexandre Salomé <alexandre.salome@gmail.com>
18 *
19 * @api
20 */
21class InvalidParameterException extends \InvalidArgumentException implements ExceptionInterface
22{
23}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php
new file mode 100644
index 00000000..32f10913
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * The resource was found but the request method is not allowed.
16 *
17 * This exception should trigger an HTTP 405 response in your application code.
18 *
19 * @author Kris Wallsmith <kris@symfony.com>
20 *
21 * @api
22 */
23class MethodNotAllowedException extends \RuntimeException implements ExceptionInterface
24{
25 /**
26 * @var array
27 */
28 protected $allowedMethods = array();
29
30 public function __construct(array $allowedMethods, $message = null, $code = 0, \Exception $previous = null)
31 {
32 $this->allowedMethods = array_map('strtoupper', $allowedMethods);
33
34 parent::__construct($message, $code, $previous);
35 }
36
37 /**
38 * Gets the allowed HTTP methods.
39 *
40 * @return array
41 */
42 public function getAllowedMethods()
43 {
44 return $this->allowedMethods;
45 }
46}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php
new file mode 100644
index 00000000..5a523fa5
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php
@@ -0,0 +1,24 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * Exception thrown when a route cannot be generated because of missing
16 * mandatory parameters.
17 *
18 * @author Alexandre Salomé <alexandre.salome@gmail.com>
19 *
20 * @api
21 */
22class MissingMandatoryParametersException extends \InvalidArgumentException implements ExceptionInterface
23{
24}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php
new file mode 100644
index 00000000..362a0d61
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php
@@ -0,0 +1,25 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * The resource was not found.
16 *
17 * This exception should trigger an HTTP 404 response in your application code.
18 *
19 * @author Kris Wallsmith <kris@symfony.com>
20 *
21 * @api
22 */
23class ResourceNotFoundException extends \RuntimeException implements ExceptionInterface
24{
25}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php
new file mode 100644
index 00000000..4d5f288e
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * Exception thrown when a route does not exists
16 *
17 * @author Alexandre Salomé <alexandre.salome@gmail.com>
18 *
19 * @api
20 */
21class RouteNotFoundException extends \InvalidArgumentException implements ExceptionInterface
22{
23}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php
new file mode 100644
index 00000000..5925838c
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Generator;
13
14/**
15 * ConfigurableRequirementsInterface must be implemented by URL generators that
16 * can be configured whether an exception should be generated when the parameters
17 * do not match the requirements. It is also possible to disable the requirements
18 * check for URL generation completely.
19 *
20 * The possible configurations and use-cases:
21 * - setStrictRequirements(true): Throw an exception for mismatching requirements. This
22 * is mostly useful in development environment.
23 * - setStrictRequirements(false): Don't throw an exception but return null as URL for
24 * mismatching requirements and log the problem. Useful when you cannot control all
25 * params because they come from third party libs but don't want to have a 404 in
26 * production environment. It should log the mismatch so one can review it.
27 * - setStrictRequirements(null): Return the URL with the given parameters without
28 * checking the requirements at all. When generating an URL you should either trust
29 * your params or you validated them beforehand because otherwise it would break your
30 * link anyway. So in production environment you should know that params always pass
31 * the requirements. Thus this option allows to disable the check on URL generation for
32 * performance reasons (saving a preg_match for each requirement every time a URL is
33 * generated).
34 *
35 * @author Fabien Potencier <fabien@symfony.com>
36 * @author Tobias Schultze <http://tobion.de>
37 */
38interface ConfigurableRequirementsInterface
39{
40 /**
41 * Enables or disables the exception on incorrect parameters.
42 * Passing null will deactivate the requirements check completely.
43 *
44 * @param Boolean|null $enabled
45 */
46 public function setStrictRequirements($enabled);
47
48 /**
49 * Returns whether to throw an exception on incorrect parameters.
50 * Null means the requirements check is deactivated completely.
51 *
52 * @return Boolean|null
53 */
54 public function isStrictRequirements();
55}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php
new file mode 100644
index 00000000..4739bd83
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Generator\Dumper;
13
14use Symfony\Component\Routing\RouteCollection;
15
16/**
17 * GeneratorDumper is the base class for all built-in generator dumpers.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21abstract class GeneratorDumper implements GeneratorDumperInterface
22{
23 /**
24 * @var RouteCollection
25 */
26 private $routes;
27
28 /**
29 * Constructor.
30 *
31 * @param RouteCollection $routes The RouteCollection to dump
32 */
33 public function __construct(RouteCollection $routes)
34 {
35 $this->routes = $routes;
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getRoutes()
42 {
43 return $this->routes;
44 }
45}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php
new file mode 100644
index 00000000..deb0c0a2
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Generator\Dumper;
13
14use Symfony\Component\Routing\RouteCollection;
15
16/**
17 * GeneratorDumperInterface is the interface that all generator dumper classes must implement.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 *
21 * @api
22 */
23interface GeneratorDumperInterface
24{
25 /**
26 * Dumps a set of routes to a string representation of executable code
27 * that can then be used to generate a URL of such a route.
28 *
29 * @param array $options An array of options
30 *
31 * @return string Executable code
32 */
33 public function dump(array $options = array());
34
35 /**
36 * Gets the routes to dump.
37 *
38 * @return RouteCollection A RouteCollection instance
39 */
40 public function getRoutes();
41}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php
new file mode 100644
index 00000000..42cd9108
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php
@@ -0,0 +1,123 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Generator\Dumper;
13
14/**
15 * PhpGeneratorDumper creates a PHP class able to generate URLs for a given set of routes.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @author Tobias Schultze <http://tobion.de>
19 *
20 * @api
21 */
22class PhpGeneratorDumper extends GeneratorDumper
23{
24 /**
25 * Dumps a set of routes to a PHP class.
26 *
27 * Available options:
28 *
29 * * class: The class name
30 * * base_class: The base class name
31 *
32 * @param array $options An array of options
33 *
34 * @return string A PHP class representing the generator class
35 *
36 * @api
37 */
38 public function dump(array $options = array())
39 {
40 $options = array_merge(array(
41 'class' => 'ProjectUrlGenerator',
42 'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
43 ), $options);
44
45 return <<<EOF
46<?php
47
48use Symfony\Component\Routing\RequestContext;
49use Symfony\Component\Routing\Exception\RouteNotFoundException;
50use Psr\Log\LoggerInterface;
51
52/**
53 * {$options['class']}
54 *
55 * This class has been auto-generated
56 * by the Symfony Routing Component.
57 */
58class {$options['class']} extends {$options['base_class']}
59{
60 static private \$declaredRoutes = {$this->generateDeclaredRoutes()};
61
62 /**
63 * Constructor.
64 */
65 public function __construct(RequestContext \$context, LoggerInterface \$logger = null)
66 {
67 \$this->context = \$context;
68 \$this->logger = \$logger;
69 }
70
71{$this->generateGenerateMethod()}
72}
73
74EOF;
75 }
76
77 /**
78 * Generates PHP code representing an array of defined routes
79 * together with the routes properties (e.g. requirements).
80 *
81 * @return string PHP code
82 */
83 private function generateDeclaredRoutes()
84 {
85 $routes = "array(\n";
86 foreach ($this->getRoutes()->all() as $name => $route) {
87 $compiledRoute = $route->compile();
88
89 $properties = array();
90 $properties[] = $compiledRoute->getVariables();
91 $properties[] = $route->getDefaults();
92 $properties[] = $route->getRequirements();
93 $properties[] = $compiledRoute->getTokens();
94 $properties[] = $compiledRoute->getHostTokens();
95
96 $routes .= sprintf(" '%s' => %s,\n", $name, str_replace("\n", '', var_export($properties, true)));
97 }
98 $routes .= ' )';
99
100 return $routes;
101 }
102
103 /**
104 * Generates PHP code representing the `generate` method that implements the UrlGeneratorInterface.
105 *
106 * @return string PHP code
107 */
108 private function generateGenerateMethod()
109 {
110 return <<<EOF
111 public function generate(\$name, \$parameters = array(), \$referenceType = self::ABSOLUTE_PATH)
112 {
113 if (!isset(self::\$declaredRoutes[\$name])) {
114 throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', \$name));
115 }
116
117 list(\$variables, \$defaults, \$requirements, \$tokens, \$hostTokens) = self::\$declaredRoutes[\$name];
118
119 return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$referenceType, \$hostTokens);
120 }
121EOF;
122 }
123}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php
new file mode 100644
index 00000000..f224cb3f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php
@@ -0,0 +1,322 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Generator;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\RequestContext;
16use Symfony\Component\Routing\Exception\InvalidParameterException;
17use Symfony\Component\Routing\Exception\RouteNotFoundException;
18use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
19use Psr\Log\LoggerInterface;
20
21/**
22 * UrlGenerator can generate a URL or a path for any route in the RouteCollection
23 * based on the passed parameters.
24 *
25 * @author Fabien Potencier <fabien@symfony.com>
26 * @author Tobias Schultze <http://tobion.de>
27 *
28 * @api
29 */
30class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInterface
31{
32 /**
33 * @var RouteCollection
34 */
35 protected $routes;
36
37 /**
38 * @var RequestContext
39 */
40 protected $context;
41
42 /**
43 * @var Boolean|null
44 */
45 protected $strictRequirements = true;
46
47 /**
48 * @var LoggerInterface|null
49 */
50 protected $logger;
51
52 /**
53 * This array defines the characters (besides alphanumeric ones) that will not be percent-encoded in the path segment of the generated URL.
54 *
55 * PHP's rawurlencode() encodes all chars except "a-zA-Z0-9-._~" according to RFC 3986. But we want to allow some chars
56 * to be used in their literal form (reasons below). Other chars inside the path must of course be encoded, e.g.
57 * "?" and "#" (would be interpreted wrongly as query and fragment identifier),
58 * "'" and """ (are used as delimiters in HTML).
59 */
60 protected $decodedChars = array(
61 // the slash can be used to designate a hierarchical structure and we want allow using it with this meaning
62 // some webservers don't allow the slash in encoded form in the path for security reasons anyway
63 // see http://stackoverflow.com/questions/4069002/http-400-if-2f-part-of-get-url-in-jboss
64 '%2F' => '/',
65 // the following chars are general delimiters in the URI specification but have only special meaning in the authority component
66 // so they can safely be used in the path in unencoded form
67 '%40' => '@',
68 '%3A' => ':',
69 // these chars are only sub-delimiters that have no predefined meaning and can therefore be used literally
70 // so URI producing applications can use these chars to delimit subcomponents in a path segment without being encoded for better readability
71 '%3B' => ';',
72 '%2C' => ',',
73 '%3D' => '=',
74 '%2B' => '+',
75 '%21' => '!',
76 '%2A' => '*',
77 '%7C' => '|',
78 );
79
80 /**
81 * Constructor.
82 *
83 * @param RouteCollection $routes A RouteCollection instance
84 * @param RequestContext $context The context
85 * @param LoggerInterface|null $logger A logger instance
86 *
87 * @api
88 */
89 public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null)
90 {
91 $this->routes = $routes;
92 $this->context = $context;
93 $this->logger = $logger;
94 }
95
96 /**
97 * {@inheritdoc}
98 */
99 public function setContext(RequestContext $context)
100 {
101 $this->context = $context;
102 }
103
104 /**
105 * {@inheritdoc}
106 */
107 public function getContext()
108 {
109 return $this->context;
110 }
111
112 /**
113 * {@inheritdoc}
114 */
115 public function setStrictRequirements($enabled)
116 {
117 $this->strictRequirements = null === $enabled ? null : (Boolean) $enabled;
118 }
119
120 /**
121 * {@inheritdoc}
122 */
123 public function isStrictRequirements()
124 {
125 return $this->strictRequirements;
126 }
127
128 /**
129 * {@inheritDoc}
130 */
131 public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
132 {
133 if (null === $route = $this->routes->get($name)) {
134 throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
135 }
136
137 // the Route has a cache of its own and is not recompiled as long as it does not get modified
138 $compiledRoute = $route->compile();
139
140 return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostTokens());
141 }
142
143 /**
144 * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
145 * @throws InvalidParameterException When a parameter value for a placeholder is not correct because
146 * it does not match the requirement
147 */
148 protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens)
149 {
150 $variables = array_flip($variables);
151 $mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);
152
153 // all params must be given
154 if ($diff = array_diff_key($variables, $mergedParams)) {
155 throw new MissingMandatoryParametersException(sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', array_keys($diff)), $name));
156 }
157
158 $url = '';
159 $optional = true;
160 foreach ($tokens as $token) {
161 if ('variable' === $token[0]) {
162 if (!$optional || !array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) {
163 // check requirement
164 if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) {
165 $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]);
166 if ($this->strictRequirements) {
167 throw new InvalidParameterException($message);
168 }
169
170 if ($this->logger) {
171 $this->logger->error($message);
172 }
173
174 return null;
175 }
176
177 $url = $token[1].$mergedParams[$token[3]].$url;
178 $optional = false;
179 }
180 } else {
181 // static text
182 $url = $token[1].$url;
183 $optional = false;
184 }
185 }
186
187 if ('' === $url) {
188 $url = '/';
189 }
190
191 // the contexts base url is already encoded (see Symfony\Component\HttpFoundation\Request)
192 $url = strtr(rawurlencode($url), $this->decodedChars);
193
194 // the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
195 // so we need to encode them as they are not used for this purpose here
196 // otherwise we would generate a URI that, when followed by a user agent (e.g. browser), does not match this route
197 $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/'));
198 if ('/..' === substr($url, -3)) {
199 $url = substr($url, 0, -2).'%2E%2E';
200 } elseif ('/.' === substr($url, -2)) {
201 $url = substr($url, 0, -1).'%2E';
202 }
203
204 $schemeAuthority = '';
205 if ($host = $this->context->getHost()) {
206 $scheme = $this->context->getScheme();
207 if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme !== $req) {
208 $referenceType = self::ABSOLUTE_URL;
209 $scheme = $req;
210 }
211
212 if ($hostTokens) {
213 $routeHost = '';
214 foreach ($hostTokens as $token) {
215 if ('variable' === $token[0]) {
216 if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) {
217 $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]);
218
219 if ($this->strictRequirements) {
220 throw new InvalidParameterException($message);
221 }
222
223 if ($this->logger) {
224 $this->logger->error($message);
225 }
226
227 return null;
228 }
229
230 $routeHost = $token[1].$mergedParams[$token[3]].$routeHost;
231 } else {
232 $routeHost = $token[1].$routeHost;
233 }
234 }
235
236 if ($routeHost !== $host) {
237 $host = $routeHost;
238 if (self::ABSOLUTE_URL !== $referenceType) {
239 $referenceType = self::NETWORK_PATH;
240 }
241 }
242 }
243
244 if (self::ABSOLUTE_URL === $referenceType || self::NETWORK_PATH === $referenceType) {
245 $port = '';
246 if ('http' === $scheme && 80 != $this->context->getHttpPort()) {
247 $port = ':'.$this->context->getHttpPort();
248 } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) {
249 $port = ':'.$this->context->getHttpsPort();
250 }
251
252 $schemeAuthority = self::NETWORK_PATH === $referenceType ? '//' : "$scheme://";
253 $schemeAuthority .= $host.$port;
254 }
255 }
256
257 if (self::RELATIVE_PATH === $referenceType) {
258 $url = self::getRelativePath($this->context->getPathInfo(), $url);
259 } else {
260 $url = $schemeAuthority.$this->context->getBaseUrl().$url;
261 }
262
263 // add a query string if needed
264 $extra = array_diff_key($parameters, $variables, $defaults);
265 if ($extra && $query = http_build_query($extra, '', '&')) {
266 $url .= '?'.$query;
267 }
268
269 return $url;
270 }
271
272 /**
273 * Returns the target path as relative reference from the base path.
274 *
275 * Only the URIs path component (no schema, host etc.) is relevant and must be given, starting with a slash.
276 * Both paths must be absolute and not contain relative parts.
277 * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
278 * Furthermore, they can be used to reduce the link size in documents.
279 *
280 * Example target paths, given a base path of "/a/b/c/d":
281 * - "/a/b/c/d" -> ""
282 * - "/a/b/c/" -> "./"
283 * - "/a/b/" -> "../"
284 * - "/a/b/c/other" -> "other"
285 * - "/a/x/y" -> "../../x/y"
286 *
287 * @param string $basePath The base path
288 * @param string $targetPath The target path
289 *
290 * @return string The relative target path
291 */
292 public static function getRelativePath($basePath, $targetPath)
293 {
294 if ($basePath === $targetPath) {
295 return '';
296 }
297
298 $sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
299 $targetDirs = explode('/', isset($targetPath[0]) && '/' === $targetPath[0] ? substr($targetPath, 1) : $targetPath);
300 array_pop($sourceDirs);
301 $targetFile = array_pop($targetDirs);
302
303 foreach ($sourceDirs as $i => $dir) {
304 if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
305 unset($sourceDirs[$i], $targetDirs[$i]);
306 } else {
307 break;
308 }
309 }
310
311 $targetDirs[] = $targetFile;
312 $path = str_repeat('../', count($sourceDirs)).implode('/', $targetDirs);
313
314 // A reference to the same base directory or an empty subdirectory must be prefixed with "./".
315 // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
316 // as the first segment of a relative-path reference, as it would be mistaken for a scheme name
317 // (see http://tools.ietf.org/html/rfc3986#section-4.2).
318 return '' === $path || '/' === $path[0]
319 || false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
320 ? "./$path" : $path;
321 }
322}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php
new file mode 100644
index 00000000..8e3b2778
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php
@@ -0,0 +1,87 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Generator;
13
14use Symfony\Component\Routing\Exception\InvalidParameterException;
15use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
16use Symfony\Component\Routing\Exception\RouteNotFoundException;
17use Symfony\Component\Routing\RequestContextAwareInterface;
18
19/**
20 * UrlGeneratorInterface is the interface that all URL generator classes must implement.
21 *
22 * The constants in this interface define the different types of resource references that
23 * are declared in RFC 3986: http://tools.ietf.org/html/rfc3986
24 * We are using the term "URL" instead of "URI" as this is more common in web applications
25 * and we do not need to distinguish them as the difference is mostly semantical and
26 * less technical. Generating URIs, i.e. representation-independent resource identifiers,
27 * is also possible.
28 *
29 * @author Fabien Potencier <fabien@symfony.com>
30 * @author Tobias Schultze <http://tobion.de>
31 *
32 * @api
33 */
34interface UrlGeneratorInterface extends RequestContextAwareInterface
35{
36 /**
37 * Generates an absolute URL, e.g. "http://example.com/dir/file".
38 */
39 const ABSOLUTE_URL = true;
40
41 /**
42 * Generates an absolute path, e.g. "/dir/file".
43 */
44 const ABSOLUTE_PATH = false;
45
46 /**
47 * Generates a relative path based on the current request path, e.g. "../parent-file".
48 * @see UrlGenerator::getRelativePath()
49 */
50 const RELATIVE_PATH = 'relative';
51
52 /**
53 * Generates a network path, e.g. "//example.com/dir/file".
54 * Such reference reuses the current scheme but specifies the host.
55 */
56 const NETWORK_PATH = 'network';
57
58 /**
59 * Generates a URL or path for a specific route based on the given parameters.
60 *
61 * Parameters that reference placeholders in the route pattern will substitute them in the
62 * path or host. Extra params are added as query string to the URL.
63 *
64 * When the passed reference type cannot be generated for the route because it requires a different
65 * host or scheme than the current one, the method will return a more comprehensive reference
66 * that includes the required params. For example, when you call this method with $referenceType = ABSOLUTE_PATH
67 * but the route requires the https scheme whereas the current scheme is http, it will instead return an
68 * ABSOLUTE_URL with the https scheme and the current host. This makes sure the generated URL matches
69 * the route in any case.
70 *
71 * If there is no route with the given name, the generator must throw the RouteNotFoundException.
72 *
73 * @param string $name The name of the route
74 * @param mixed $parameters An array of parameters
75 * @param Boolean|string $referenceType The type of reference to be generated (one of the constants)
76 *
77 * @return string The generated URL
78 *
79 * @throws RouteNotFoundException If the named route doesn't exist
80 * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
81 * @throws InvalidParameterException When a parameter value for a placeholder is not correct because
82 * it does not match the requirement
83 *
84 * @api
85 */
86 public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH);
87}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/LICENSE b/vendor/symfony/routing/Symfony/Component/Routing/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
new file mode 100644
index 00000000..9831d85a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
@@ -0,0 +1,246 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Loader;
13
14use Doctrine\Common\Annotations\Reader;
15use Symfony\Component\Config\Resource\FileResource;
16use Symfony\Component\Routing\Route;
17use Symfony\Component\Routing\RouteCollection;
18use Symfony\Component\Config\Loader\LoaderInterface;
19use Symfony\Component\Config\Loader\LoaderResolverInterface;
20
21/**
22 * AnnotationClassLoader loads routing information from a PHP class and its methods.
23 *
24 * You need to define an implementation for the getRouteDefaults() method. Most of the
25 * time, this method should define some PHP callable to be called for the route
26 * (a controller in MVC speak).
27 *
28 * The @Route annotation can be set on the class (for global parameters),
29 * and on each method.
30 *
31 * The @Route annotation main value is the route path. The annotation also
32 * recognizes several parameters: requirements, options, defaults, schemes,
33 * methods, host, and name. The name parameter is mandatory.
34 * Here is an example of how you should be able to use it:
35 *
36 * /**
37 * * @Route("/Blog")
38 * * /
39 * class Blog
40 * {
41 * /**
42 * * @Route("/", name="blog_index")
43 * * /
44 * public function index()
45 * {
46 * }
47 *
48 * /**
49 * * @Route("/{id}", name="blog_post", requirements = {"id" = "\d+"})
50 * * /
51 * public function show()
52 * {
53 * }
54 * }
55 *
56 * @author Fabien Potencier <fabien@symfony.com>
57 */
58abstract class AnnotationClassLoader implements LoaderInterface
59{
60 /**
61 * @var Reader
62 */
63 protected $reader;
64
65 /**
66 * @var string
67 */
68 protected $routeAnnotationClass = 'Symfony\\Component\\Routing\\Annotation\\Route';
69
70 /**
71 * @var integer
72 */
73 protected $defaultRouteIndex = 0;
74
75 /**
76 * Constructor.
77 *
78 * @param Reader $reader
79 */
80 public function __construct(Reader $reader)
81 {
82 $this->reader = $reader;
83 }
84
85 /**
86 * Sets the annotation class to read route properties from.
87 *
88 * @param string $class A fully-qualified class name
89 */
90 public function setRouteAnnotationClass($class)
91 {
92 $this->routeAnnotationClass = $class;
93 }
94
95 /**
96 * Loads from annotations from a class.
97 *
98 * @param string $class A class name
99 * @param string|null $type The resource type
100 *
101 * @return RouteCollection A RouteCollection instance
102 *
103 * @throws \InvalidArgumentException When route can't be parsed
104 */
105 public function load($class, $type = null)
106 {
107 if (!class_exists($class)) {
108 throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
109 }
110
111 $globals = array(
112 'path' => '',
113 'requirements' => array(),
114 'options' => array(),
115 'defaults' => array(),
116 'schemes' => array(),
117 'methods' => array(),
118 'host' => '',
119 );
120
121 $class = new \ReflectionClass($class);
122 if ($class->isAbstract()) {
123 throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class));
124 }
125
126 if ($annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass)) {
127 // for BC reasons
128 if (null !== $annot->getPath()) {
129 $globals['path'] = $annot->getPath();
130 } elseif (null !== $annot->getPattern()) {
131 $globals['path'] = $annot->getPattern();
132 }
133
134 if (null !== $annot->getRequirements()) {
135 $globals['requirements'] = $annot->getRequirements();
136 }
137
138 if (null !== $annot->getOptions()) {
139 $globals['options'] = $annot->getOptions();
140 }
141
142 if (null !== $annot->getDefaults()) {
143 $globals['defaults'] = $annot->getDefaults();
144 }
145
146 if (null !== $annot->getSchemes()) {
147 $globals['schemes'] = $annot->getSchemes();
148 }
149
150 if (null !== $annot->getMethods()) {
151 $globals['methods'] = $annot->getMethods();
152 }
153
154 if (null !== $annot->getHost()) {
155 $globals['host'] = $annot->getHost();
156 }
157 }
158
159 $collection = new RouteCollection();
160 $collection->addResource(new FileResource($class->getFileName()));
161
162 foreach ($class->getMethods() as $method) {
163 $this->defaultRouteIndex = 0;
164 foreach ($this->reader->getMethodAnnotations($method) as $annot) {
165 if ($annot instanceof $this->routeAnnotationClass) {
166 $this->addRoute($collection, $annot, $globals, $class, $method);
167 }
168 }
169 }
170
171 return $collection;
172 }
173
174 protected function addRoute(RouteCollection $collection, $annot, $globals, \ReflectionClass $class, \ReflectionMethod $method)
175 {
176 $name = $annot->getName();
177 if (null === $name) {
178 $name = $this->getDefaultRouteName($class, $method);
179 }
180
181 $defaults = array_replace($globals['defaults'], $annot->getDefaults());
182 foreach ($method->getParameters() as $param) {
183 if ($param->isOptional()) {
184 $defaults[$param->getName()] = $param->getDefaultValue();
185 }
186 }
187 $requirements = array_replace($globals['requirements'], $annot->getRequirements());
188 $options = array_replace($globals['options'], $annot->getOptions());
189 $schemes = array_replace($globals['schemes'], $annot->getSchemes());
190 $methods = array_replace($globals['methods'], $annot->getMethods());
191
192 $host = $annot->getHost();
193 if (null === $host) {
194 $host = $globals['host'];
195 }
196
197 $route = new Route($globals['path'].$annot->getPath(), $defaults, $requirements, $options, $host, $schemes, $methods);
198
199 $this->configureRoute($route, $class, $method, $annot);
200
201 $collection->add($name, $route);
202 }
203
204 /**
205 * {@inheritdoc}
206 */
207 public function supports($resource, $type = null)
208 {
209 return is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || 'annotation' === $type);
210 }
211
212 /**
213 * {@inheritdoc}
214 */
215 public function setResolver(LoaderResolverInterface $resolver)
216 {
217 }
218
219 /**
220 * {@inheritdoc}
221 */
222 public function getResolver()
223 {
224 }
225
226 /**
227 * Gets the default route name for a class method.
228 *
229 * @param \ReflectionClass $class
230 * @param \ReflectionMethod $method
231 *
232 * @return string
233 */
234 protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method)
235 {
236 $name = strtolower(str_replace('\\', '_', $class->name).'_'.$method->name);
237 if ($this->defaultRouteIndex > 0) {
238 $name .= '_'.$this->defaultRouteIndex;
239 }
240 $this->defaultRouteIndex++;
241
242 return $name;
243 }
244
245 abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, $annot);
246}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
new file mode 100644
index 00000000..abd68ed6
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
@@ -0,0 +1,77 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Config\Resource\DirectoryResource;
16
17/**
18 * AnnotationDirectoryLoader loads routing information from annotations set
19 * on PHP classes and methods.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 */
23class AnnotationDirectoryLoader extends AnnotationFileLoader
24{
25 /**
26 * Loads from annotations from a directory.
27 *
28 * @param string $path A directory path
29 * @param string|null $type The resource type
30 *
31 * @return RouteCollection A RouteCollection instance
32 *
33 * @throws \InvalidArgumentException When the directory does not exist or its routes cannot be parsed
34 */
35 public function load($path, $type = null)
36 {
37 $dir = $this->locator->locate($path);
38
39 $collection = new RouteCollection();
40 $collection->addResource(new DirectoryResource($dir, '/\.php$/'));
41 $files = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::LEAVES_ONLY));
42 usort($files, function (\SplFileInfo $a, \SplFileInfo $b) {
43 return (string) $a > (string) $b ? 1 : -1;
44 });
45
46 foreach ($files as $file) {
47 if (!$file->isFile() || '.php' !== substr($file->getFilename(), -4)) {
48 continue;
49 }
50
51 if ($class = $this->findClass($file)) {
52 $refl = new \ReflectionClass($class);
53 if ($refl->isAbstract()) {
54 continue;
55 }
56
57 $collection->addCollection($this->loader->load($class, $type));
58 }
59 }
60
61 return $collection;
62 }
63
64 /**
65 * {@inheritdoc}
66 */
67 public function supports($resource, $type = null)
68 {
69 try {
70 $path = $this->locator->locate($resource);
71 } catch (\Exception $e) {
72 return false;
73 }
74
75 return is_string($resource) && is_dir($path) && (!$type || 'annotation' === $type);
76 }
77}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
new file mode 100644
index 00000000..33776fdc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
@@ -0,0 +1,122 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Config\Resource\FileResource;
16use Symfony\Component\Config\Loader\FileLoader;
17use Symfony\Component\Config\FileLocatorInterface;
18
19/**
20 * AnnotationFileLoader loads routing information from annotations set
21 * on a PHP class and its methods.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 */
25class AnnotationFileLoader extends FileLoader
26{
27 protected $loader;
28
29 /**
30 * Constructor.
31 *
32 * @param FileLocatorInterface $locator A FileLocator instance
33 * @param AnnotationClassLoader $loader An AnnotationClassLoader instance
34 * @param string|array $paths A path or an array of paths where to look for resources
35 *
36 * @throws \RuntimeException
37 */
38 public function __construct(FileLocatorInterface $locator, AnnotationClassLoader $loader, $paths = array())
39 {
40 if (!function_exists('token_get_all')) {
41 throw new \RuntimeException('The Tokenizer extension is required for the routing annotation loaders.');
42 }
43
44 parent::__construct($locator, $paths);
45
46 $this->loader = $loader;
47 }
48
49 /**
50 * Loads from annotations from a file.
51 *
52 * @param string $file A PHP file path
53 * @param string|null $type The resource type
54 *
55 * @return RouteCollection A RouteCollection instance
56 *
57 * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
58 */
59 public function load($file, $type = null)
60 {
61 $path = $this->locator->locate($file);
62
63 $collection = new RouteCollection();
64 if ($class = $this->findClass($path)) {
65 $collection->addResource(new FileResource($path));
66 $collection->addCollection($this->loader->load($class, $type));
67 }
68
69 return $collection;
70 }
71
72 /**
73 * {@inheritdoc}
74 */
75 public function supports($resource, $type = null)
76 {
77 return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'annotation' === $type);
78 }
79
80 /**
81 * Returns the full class name for the first class in the file.
82 *
83 * @param string $file A PHP file path
84 *
85 * @return string|false Full class name if found, false otherwise
86 */
87 protected function findClass($file)
88 {
89 $class = false;
90 $namespace = false;
91 $tokens = token_get_all(file_get_contents($file));
92 for ($i = 0, $count = count($tokens); $i < $count; $i++) {
93 $token = $tokens[$i];
94
95 if (!is_array($token)) {
96 continue;
97 }
98
99 if (true === $class && T_STRING === $token[0]) {
100 return $namespace.'\\'.$token[1];
101 }
102
103 if (true === $namespace && T_STRING === $token[0]) {
104 $namespace = '';
105 do {
106 $namespace .= $token[1];
107 $token = $tokens[++$i];
108 } while ($i < $count && is_array($token) && in_array($token[0], array(T_NS_SEPARATOR, T_STRING)));
109 }
110
111 if (T_CLASS === $token[0]) {
112 $class = true;
113 }
114
115 if (T_NAMESPACE === $token[0]) {
116 $namespace = true;
117 }
118 }
119
120 return false;
121 }
122}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php
new file mode 100644
index 00000000..8212c291
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php
@@ -0,0 +1,52 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Config\Loader\Loader;
15use Symfony\Component\Routing\RouteCollection;
16
17/**
18 * ClosureLoader loads routes from a PHP closure.
19 *
20 * The Closure must return a RouteCollection instance.
21 *
22 * @author Fabien Potencier <fabien@symfony.com>
23 *
24 * @api
25 */
26class ClosureLoader extends Loader
27{
28 /**
29 * Loads a Closure.
30 *
31 * @param \Closure $closure A Closure
32 * @param string|null $type The resource type
33 *
34 * @return RouteCollection A RouteCollection instance
35 *
36 * @api
37 */
38 public function load($closure, $type = null)
39 {
40 return call_user_func($closure);
41 }
42
43 /**
44 * {@inheritdoc}
45 *
46 * @api
47 */
48 public function supports($resource, $type = null)
49 {
50 return $resource instanceof \Closure && (!$type || 'closure' === $type);
51 }
52}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php
new file mode 100644
index 00000000..98b7efbf
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php
@@ -0,0 +1,62 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Config\Loader\FileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16use Symfony\Component\Routing\RouteCollection;
17
18/**
19 * PhpFileLoader loads routes from a PHP file.
20 *
21 * The file must return a RouteCollection instance.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 *
25 * @api
26 */
27class PhpFileLoader extends FileLoader
28{
29 /**
30 * Loads a PHP file.
31 *
32 * @param string $file A PHP file path
33 * @param string|null $type The resource type
34 *
35 * @return RouteCollection A RouteCollection instance
36 *
37 * @api
38 */
39 public function load($file, $type = null)
40 {
41 // the loader variable is exposed to the included file below
42 $loader = $this;
43
44 $path = $this->locator->locate($file);
45 $this->setCurrentDir(dirname($path));
46
47 $collection = include $path;
48 $collection->addResource(new FileResource($path));
49
50 return $collection;
51 }
52
53 /**
54 * {@inheritdoc}
55 *
56 * @api
57 */
58 public function supports($resource, $type = null)
59 {
60 return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'php' === $type);
61 }
62}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php
new file mode 100644
index 00000000..da7b33d8
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php
@@ -0,0 +1,238 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Config\Resource\FileResource;
17use Symfony\Component\Config\Loader\FileLoader;
18use Symfony\Component\Config\Util\XmlUtils;
19
20/**
21 * XmlFileLoader loads XML routing files.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 * @author Tobias Schultze <http://tobion.de>
25 *
26 * @api
27 */
28class XmlFileLoader extends FileLoader
29{
30 const NAMESPACE_URI = 'http://symfony.com/schema/routing';
31 const SCHEME_PATH = '/schema/routing/routing-1.0.xsd';
32
33 /**
34 * Loads an XML file.
35 *
36 * @param string $file An XML file path
37 * @param string|null $type The resource type
38 *
39 * @return RouteCollection A RouteCollection instance
40 *
41 * @throws \InvalidArgumentException When the file cannot be loaded or when the XML cannot be
42 * parsed because it does not validate against the scheme.
43 *
44 * @api
45 */
46 public function load($file, $type = null)
47 {
48 $path = $this->locator->locate($file);
49
50 $xml = $this->loadFile($path);
51
52 $collection = new RouteCollection();
53 $collection->addResource(new FileResource($path));
54
55 // process routes and imports
56 foreach ($xml->documentElement->childNodes as $node) {
57 if (!$node instanceof \DOMElement) {
58 continue;
59 }
60
61 $this->parseNode($collection, $node, $path, $file);
62 }
63
64 return $collection;
65 }
66
67 /**
68 * Parses a node from a loaded XML file.
69 *
70 * @param RouteCollection $collection Collection to associate with the node
71 * @param \DOMElement $node Element to parse
72 * @param string $path Full path of the XML file being processed
73 * @param string $file Loaded file name
74 *
75 * @throws \InvalidArgumentException When the XML is invalid
76 */
77 protected function parseNode(RouteCollection $collection, \DOMElement $node, $path, $file)
78 {
79 if (self::NAMESPACE_URI !== $node->namespaceURI) {
80 return;
81 }
82
83 switch ($node->localName) {
84 case 'route':
85 $this->parseRoute($collection, $node, $path);
86 break;
87 case 'import':
88 $this->parseImport($collection, $node, $path, $file);
89 break;
90 default:
91 throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "route" or "import".', $node->localName, $path));
92 }
93 }
94
95 /**
96 * {@inheritdoc}
97 *
98 * @api
99 */
100 public function supports($resource, $type = null)
101 {
102 return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'xml' === $type);
103 }
104
105 /**
106 * Parses a route and adds it to the RouteCollection.
107 *
108 * @param RouteCollection $collection RouteCollection instance
109 * @param \DOMElement $node Element to parse that represents a Route
110 * @param string $path Full path of the XML file being processed
111 *
112 * @throws \InvalidArgumentException When the XML is invalid
113 */
114 protected function parseRoute(RouteCollection $collection, \DOMElement $node, $path)
115 {
116 if ('' === ($id = $node->getAttribute('id')) || (!$node->hasAttribute('pattern') && !$node->hasAttribute('path'))) {
117 throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have an "id" and a "path" attribute.', $path));
118 }
119
120 if ($node->hasAttribute('pattern')) {
121 if ($node->hasAttribute('path')) {
122 throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".', $path));
123 }
124
125 $node->setAttribute('path', $node->getAttribute('pattern'));
126 $node->removeAttribute('pattern');
127 }
128
129 $schemes = preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY);
130 $methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY);
131
132 list($defaults, $requirements, $options) = $this->parseConfigs($node, $path);
133
134 $route = new Route($node->getAttribute('path'), $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods);
135 $collection->add($id, $route);
136 }
137
138 /**
139 * Parses an import and adds the routes in the resource to the RouteCollection.
140 *
141 * @param RouteCollection $collection RouteCollection instance
142 * @param \DOMElement $node Element to parse that represents a Route
143 * @param string $path Full path of the XML file being processed
144 * @param string $file Loaded file name
145 *
146 * @throws \InvalidArgumentException When the XML is invalid
147 */
148 protected function parseImport(RouteCollection $collection, \DOMElement $node, $path, $file)
149 {
150 if ('' === $resource = $node->getAttribute('resource')) {
151 throw new \InvalidArgumentException(sprintf('The <import> element in file "%s" must have a "resource" attribute.', $path));
152 }
153
154 $type = $node->getAttribute('type');
155 $prefix = $node->getAttribute('prefix');
156 $host = $node->hasAttribute('host') ? $node->getAttribute('host') : null;
157 $schemes = $node->hasAttribute('schemes') ? preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY) : null;
158 $methods = $node->hasAttribute('methods') ? preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY) : null;
159
160 list($defaults, $requirements, $options) = $this->parseConfigs($node, $path);
161
162 $this->setCurrentDir(dirname($path));
163
164 $subCollection = $this->import($resource, ('' !== $type ? $type : null), false, $file);
165 /* @var $subCollection RouteCollection */
166 $subCollection->addPrefix($prefix);
167 if (null !== $host) {
168 $subCollection->setHost($host);
169 }
170 if (null !== $schemes) {
171 $subCollection->setSchemes($schemes);
172 }
173 if (null !== $methods) {
174 $subCollection->setMethods($methods);
175 }
176 $subCollection->addDefaults($defaults);
177 $subCollection->addRequirements($requirements);
178 $subCollection->addOptions($options);
179
180 $collection->addCollection($subCollection);
181 }
182
183 /**
184 * Loads an XML file.
185 *
186 * @param string $file An XML file path
187 *
188 * @return \DOMDocument
189 *
190 * @throws \InvalidArgumentException When loading of XML file fails because of syntax errors
191 * or when the XML structure is not as expected by the scheme -
192 * see validate()
193 */
194 protected function loadFile($file)
195 {
196 return XmlUtils::loadFile($file, __DIR__.static::SCHEME_PATH);
197 }
198
199 /**
200 * Parses the config elements (default, requirement, option).
201 *
202 * @param \DOMElement $node Element to parse that contains the configs
203 * @param string $path Full path of the XML file being processed
204 *
205 * @return array An array with the defaults as first item, requirements as second and options as third.
206 *
207 * @throws \InvalidArgumentException When the XML is invalid
208 */
209 private function parseConfigs(\DOMElement $node, $path)
210 {
211 $defaults = array();
212 $requirements = array();
213 $options = array();
214
215 foreach ($node->getElementsByTagNameNS(self::NAMESPACE_URI, '*') as $n) {
216 switch ($n->localName) {
217 case 'default':
218 if ($n->hasAttribute('xsi:nil') && 'true' == $n->getAttribute('xsi:nil')) {
219 $defaults[$n->getAttribute('key')] = null;
220 } else {
221 $defaults[$n->getAttribute('key')] = trim($n->textContent);
222 }
223
224 break;
225 case 'requirement':
226 $requirements[$n->getAttribute('key')] = trim($n->textContent);
227 break;
228 case 'option':
229 $options[$n->getAttribute('key')] = trim($n->textContent);
230 break;
231 default:
232 throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement" or "option".', $n->localName, $path));
233 }
234 }
235
236 return array($defaults, $requirements, $options);
237 }
238}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php
new file mode 100644
index 00000000..9deea7fe
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php
@@ -0,0 +1,212 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Config\Resource\FileResource;
17use Symfony\Component\Yaml\Parser as YamlParser;
18use Symfony\Component\Config\Loader\FileLoader;
19
20/**
21 * YamlFileLoader loads Yaml routing files.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 * @author Tobias Schultze <http://tobion.de>
25 *
26 * @api
27 */
28class YamlFileLoader extends FileLoader
29{
30 private static $availableKeys = array(
31 'resource', 'type', 'prefix', 'pattern', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options',
32 );
33 private $yamlParser;
34
35 /**
36 * Loads a Yaml file.
37 *
38 * @param string $file A Yaml file path
39 * @param string|null $type The resource type
40 *
41 * @return RouteCollection A RouteCollection instance
42 *
43 * @throws \InvalidArgumentException When a route can't be parsed because YAML is invalid
44 *
45 * @api
46 */
47 public function load($file, $type = null)
48 {
49 $path = $this->locator->locate($file);
50
51 if (!stream_is_local($path)) {
52 throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $path));
53 }
54
55 if (!file_exists($path)) {
56 throw new \InvalidArgumentException(sprintf('File "%s" not found.', $path));
57 }
58
59 if (null === $this->yamlParser) {
60 $this->yamlParser = new YamlParser();
61 }
62
63 $config = $this->yamlParser->parse(file_get_contents($path));
64
65 $collection = new RouteCollection();
66 $collection->addResource(new FileResource($path));
67
68 // empty file
69 if (null === $config) {
70 return $collection;
71 }
72
73 // not an array
74 if (!is_array($config)) {
75 throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path));
76 }
77
78 foreach ($config as $name => $config) {
79 if (isset($config['pattern'])) {
80 if (isset($config['path'])) {
81 throw new \InvalidArgumentException(sprintf('The file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".', $path));
82 }
83
84 $config['path'] = $config['pattern'];
85 unset($config['pattern']);
86 }
87
88 $this->validate($config, $name, $path);
89
90 if (isset($config['resource'])) {
91 $this->parseImport($collection, $config, $path, $file);
92 } else {
93 $this->parseRoute($collection, $name, $config, $path);
94 }
95 }
96
97 return $collection;
98 }
99
100 /**
101 * {@inheritdoc}
102 *
103 * @api
104 */
105 public function supports($resource, $type = null)
106 {
107 return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'yaml' === $type);
108 }
109
110 /**
111 * Parses a route and adds it to the RouteCollection.
112 *
113 * @param RouteCollection $collection A RouteCollection instance
114 * @param string $name Route name
115 * @param array $config Route definition
116 * @param string $path Full path of the YAML file being processed
117 */
118 protected function parseRoute(RouteCollection $collection, $name, array $config, $path)
119 {
120 $defaults = isset($config['defaults']) ? $config['defaults'] : array();
121 $requirements = isset($config['requirements']) ? $config['requirements'] : array();
122 $options = isset($config['options']) ? $config['options'] : array();
123 $host = isset($config['host']) ? $config['host'] : '';
124 $schemes = isset($config['schemes']) ? $config['schemes'] : array();
125 $methods = isset($config['methods']) ? $config['methods'] : array();
126
127 $route = new Route($config['path'], $defaults, $requirements, $options, $host, $schemes, $methods);
128
129 $collection->add($name, $route);
130 }
131
132 /**
133 * Parses an import and adds the routes in the resource to the RouteCollection.
134 *
135 * @param RouteCollection $collection A RouteCollection instance
136 * @param array $config Route definition
137 * @param string $path Full path of the YAML file being processed
138 * @param string $file Loaded file name
139 */
140 protected function parseImport(RouteCollection $collection, array $config, $path, $file)
141 {
142 $type = isset($config['type']) ? $config['type'] : null;
143 $prefix = isset($config['prefix']) ? $config['prefix'] : '';
144 $defaults = isset($config['defaults']) ? $config['defaults'] : array();
145 $requirements = isset($config['requirements']) ? $config['requirements'] : array();
146 $options = isset($config['options']) ? $config['options'] : array();
147 $host = isset($config['host']) ? $config['host'] : null;
148 $schemes = isset($config['schemes']) ? $config['schemes'] : null;
149 $methods = isset($config['methods']) ? $config['methods'] : null;
150
151 $this->setCurrentDir(dirname($path));
152
153 $subCollection = $this->import($config['resource'], $type, false, $file);
154 /* @var $subCollection RouteCollection */
155 $subCollection->addPrefix($prefix);
156 if (null !== $host) {
157 $subCollection->setHost($host);
158 }
159 if (null !== $schemes) {
160 $subCollection->setSchemes($schemes);
161 }
162 if (null !== $methods) {
163 $subCollection->setMethods($methods);
164 }
165 $subCollection->addDefaults($defaults);
166 $subCollection->addRequirements($requirements);
167 $subCollection->addOptions($options);
168
169 $collection->addCollection($subCollection);
170 }
171
172 /**
173 * Validates the route configuration.
174 *
175 * @param array $config A resource config
176 * @param string $name The config key
177 * @param string $path The loaded file path
178 *
179 * @throws \InvalidArgumentException If one of the provided config keys is not supported,
180 * something is missing or the combination is nonsense
181 */
182 protected function validate($config, $name, $path)
183 {
184 if (!is_array($config)) {
185 throw new \InvalidArgumentException(sprintf('The definition of "%s" in "%s" must be a YAML array.', $name, $path));
186 }
187 if ($extraKeys = array_diff(array_keys($config), self::$availableKeys)) {
188 throw new \InvalidArgumentException(sprintf(
189 'The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".',
190 $path, $name, implode('", "', $extraKeys), implode('", "', self::$availableKeys)
191 ));
192 }
193 if (isset($config['resource']) && isset($config['path'])) {
194 throw new \InvalidArgumentException(sprintf(
195 'The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.',
196 $path, $name
197 ));
198 }
199 if (!isset($config['resource']) && isset($config['type'])) {
200 throw new \InvalidArgumentException(sprintf(
201 'The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.',
202 $name, $path
203 ));
204 }
205 if (!isset($config['resource']) && !isset($config['path'])) {
206 throw new \InvalidArgumentException(sprintf(
207 'You must define a "path" for the route "%s" in file "%s".',
208 $name, $path
209 ));
210 }
211 }
212}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd b/vendor/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
new file mode 100644
index 00000000..daea8143
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
@@ -0,0 +1,64 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<xsd:schema xmlns="http://symfony.com/schema/routing"
4 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
5 targetNamespace="http://symfony.com/schema/routing"
6 elementFormDefault="qualified">
7
8 <xsd:annotation>
9 <xsd:documentation><![CDATA[
10 Symfony XML Routing Schema, version 1.0
11 Authors: Fabien Potencier, Tobias Schultze
12
13 This scheme defines the elements and attributes that can be used to define
14 routes. A route maps an HTTP request to a set of configuration variables.
15 ]]></xsd:documentation>
16 </xsd:annotation>
17
18 <xsd:element name="routes" type="routes" />
19
20 <xsd:complexType name="routes">
21 <xsd:choice minOccurs="0" maxOccurs="unbounded">
22 <xsd:element name="import" type="import" />
23 <xsd:element name="route" type="route" />
24 </xsd:choice>
25 </xsd:complexType>
26
27 <xsd:group name="configs">
28 <xsd:choice>
29 <xsd:element name="default" nillable="true" type="element" />
30 <xsd:element name="requirement" type="element" />
31 <xsd:element name="option" type="element" />
32 </xsd:choice>
33 </xsd:group>
34
35 <xsd:complexType name="route">
36 <xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
37
38 <xsd:attribute name="id" type="xsd:string" use="required" />
39 <xsd:attribute name="path" type="xsd:string" />
40 <xsd:attribute name="pattern" type="xsd:string" />
41 <xsd:attribute name="host" type="xsd:string" />
42 <xsd:attribute name="schemes" type="xsd:string" />
43 <xsd:attribute name="methods" type="xsd:string" />
44 </xsd:complexType>
45
46 <xsd:complexType name="import">
47 <xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
48
49 <xsd:attribute name="resource" type="xsd:string" use="required" />
50 <xsd:attribute name="type" type="xsd:string" />
51 <xsd:attribute name="prefix" type="xsd:string" />
52 <xsd:attribute name="host" type="xsd:string" />
53 <xsd:attribute name="schemes" type="xsd:string" />
54 <xsd:attribute name="methods" type="xsd:string" />
55 </xsd:complexType>
56
57 <xsd:complexType name="element">
58 <xsd:simpleContent>
59 <xsd:extension base="xsd:string">
60 <xsd:attribute name="key" type="xsd:string" use="required" />
61 </xsd:extension>
62 </xsd:simpleContent>
63 </xsd:complexType>
64</xsd:schema>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php
new file mode 100644
index 00000000..76612e61
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php
@@ -0,0 +1,94 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15
16/**
17 * ApacheUrlMatcher matches URL based on Apache mod_rewrite matching (see ApacheMatcherDumper).
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
21 */
22class ApacheUrlMatcher extends UrlMatcher
23{
24 /**
25 * Tries to match a URL based on Apache mod_rewrite matching.
26 *
27 * Returns false if no route matches the URL.
28 *
29 * @param string $pathinfo The pathinfo to be parsed
30 *
31 * @return array An array of parameters
32 *
33 * @throws MethodNotAllowedException If the current method is not allowed
34 */
35 public function match($pathinfo)
36 {
37 $parameters = array();
38 $defaults = array();
39 $allow = array();
40 $route = null;
41
42 foreach ($_SERVER as $key => $value) {
43 $name = $key;
44
45 // skip non-routing variables
46 // this improves performance when $_SERVER contains many usual
47 // variables like HTTP_*, DOCUMENT_ROOT, REQUEST_URI, ...
48 if (false === strpos($name, '_ROUTING_')) {
49 continue;
50 }
51
52 while (0 === strpos($name, 'REDIRECT_')) {
53 $name = substr($name, 9);
54 }
55
56 // expect _ROUTING_<type>_<name>
57 // or _ROUTING_<type>
58
59 if (0 !== strpos($name, '_ROUTING_')) {
60 continue;
61 }
62 if (false !== $pos = strpos($name, '_', 9)) {
63 $type = substr($name, 9, $pos-9);
64 $name = substr($name, $pos+1);
65 } else {
66 $type = substr($name, 9);
67 }
68
69 if ('param' === $type) {
70 if ('' !== $value) {
71 $parameters[$name] = $value;
72 }
73 } elseif ('default' === $type) {
74 $defaults[$name] = $value;
75 } elseif ('route' === $type) {
76 $route = $value;
77 } elseif ('allow' === $type) {
78 $allow[] = $name;
79 }
80
81 unset($_SERVER[$key]);
82 }
83
84 if (null !== $route) {
85 $parameters['_route'] = $route;
86
87 return $this->mergeDefaults($parameters, $defaults);
88 } elseif (0 < count($allow)) {
89 throw new MethodNotAllowedException($allow);
90 } else {
91 return parent::match($pathinfo);
92 }
93 }
94}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php
new file mode 100644
index 00000000..804da19d
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php
@@ -0,0 +1,252 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15
16/**
17 * Dumps a set of Apache mod_rewrite rules.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 * @author Kris Wallsmith <kris@symfony.com>
21 */
22class ApacheMatcherDumper extends MatcherDumper
23{
24 /**
25 * Dumps a set of Apache mod_rewrite rules.
26 *
27 * Available options:
28 *
29 * * script_name: The script name (app.php by default)
30 * * base_uri: The base URI ("" by default)
31 *
32 * @param array $options An array of options
33 *
34 * @return string A string to be used as Apache rewrite rules
35 *
36 * @throws \LogicException When the route regex is invalid
37 */
38 public function dump(array $options = array())
39 {
40 $options = array_merge(array(
41 'script_name' => 'app.php',
42 'base_uri' => '',
43 ), $options);
44
45 $options['script_name'] = self::escape($options['script_name'], ' ', '\\');
46
47 $rules = array("# skip \"real\" requests\nRewriteCond %{REQUEST_FILENAME} -f\nRewriteRule .* - [QSA,L]");
48 $methodVars = array();
49 $hostRegexUnique = 0;
50 $prevHostRegex = '';
51
52 foreach ($this->getRoutes()->all() as $name => $route) {
53
54 $compiledRoute = $route->compile();
55 $hostRegex = $compiledRoute->getHostRegex();
56
57 if (null !== $hostRegex && $prevHostRegex !== $hostRegex) {
58 $prevHostRegex = $hostRegex;
59 $hostRegexUnique++;
60
61 $rule = array();
62
63 $regex = $this->regexToApacheRegex($hostRegex);
64 $regex = self::escape($regex, ' ', '\\');
65
66 $rule[] = sprintf('RewriteCond %%{HTTP:Host} %s', $regex);
67
68 $variables = array();
69 $variables[] = sprintf('E=__ROUTING_host_%s:1', $hostRegexUnique);
70
71 foreach ($compiledRoute->getHostVariables() as $i => $variable) {
72 $variables[] = sprintf('E=__ROUTING_host_%s_%s:%%%d', $hostRegexUnique, $variable, $i+1);
73 }
74
75 $variables = implode(',', $variables);
76
77 $rule[] = sprintf('RewriteRule .? - [%s]', $variables);
78
79 $rules[] = implode("\n", $rule);
80 }
81
82 $rules[] = $this->dumpRoute($name, $route, $options, $hostRegexUnique);
83
84 if ($req = $route->getRequirement('_method')) {
85 $methods = explode('|', strtoupper($req));
86 $methodVars = array_merge($methodVars, $methods);
87 }
88 }
89 if (0 < count($methodVars)) {
90 $rule = array('# 405 Method Not Allowed');
91 $methodVars = array_values(array_unique($methodVars));
92 if (in_array('GET', $methodVars) && !in_array('HEAD', $methodVars)) {
93 $methodVars[] = 'HEAD';
94 }
95 foreach ($methodVars as $i => $methodVar) {
96 $rule[] = sprintf('RewriteCond %%{ENV:_ROUTING__allow_%s} =1%s', $methodVar, isset($methodVars[$i + 1]) ? ' [OR]' : '');
97 }
98 $rule[] = sprintf('RewriteRule .* %s [QSA,L]', $options['script_name']);
99
100 $rules[] = implode("\n", $rule);
101 }
102
103 return implode("\n\n", $rules)."\n";
104 }
105
106 /**
107 * Dumps a single route
108 *
109 * @param string $name Route name
110 * @param Route $route The route
111 * @param array $options Options
112 * @param bool $hostRegexUnique Unique identifier for the host regex
113 *
114 * @return string The compiled route
115 */
116 private function dumpRoute($name, $route, array $options, $hostRegexUnique)
117 {
118 $compiledRoute = $route->compile();
119
120 // prepare the apache regex
121 $regex = $this->regexToApacheRegex($compiledRoute->getRegex());
122 $regex = '^'.self::escape(preg_quote($options['base_uri']).substr($regex, 1), ' ', '\\');
123
124 $methods = $this->getRouteMethods($route);
125
126 $hasTrailingSlash = (!$methods || in_array('HEAD', $methods)) && '/$' === substr($regex, -2) && '^/$' !== $regex;
127
128 $variables = array('E=_ROUTING_route:'.$name);
129 foreach ($compiledRoute->getHostVariables() as $variable) {
130 $variables[] = sprintf('E=_ROUTING_param_%s:%%{ENV:__ROUTING_host_%s_%s}', $variable, $hostRegexUnique, $variable);
131 }
132 foreach ($compiledRoute->getPathVariables() as $i => $variable) {
133 $variables[] = 'E=_ROUTING_param_'.$variable.':%'.($i + 1);
134 }
135 foreach ($route->getDefaults() as $key => $value) {
136 $variables[] = 'E=_ROUTING_default_'.$key.':'.strtr($value, array(
137 ':' => '\\:',
138 '=' => '\\=',
139 '\\' => '\\\\',
140 ' ' => '\\ ',
141 ));
142 }
143 $variables = implode(',', $variables);
144
145 $rule = array("# $name");
146
147 // method mismatch
148 if (0 < count($methods)) {
149 $allow = array();
150 foreach ($methods as $method) {
151 $allow[] = 'E=_ROUTING_allow_'.$method.':1';
152 }
153
154 if ($hostRegex = $compiledRoute->getHostRegex()) {
155 $rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_host_%s} =1", $hostRegexUnique);
156 }
157
158 $rule[] = "RewriteCond %{REQUEST_URI} $regex";
159 $rule[] = sprintf("RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]", implode('|', $methods));
160 $rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow));
161 }
162
163 // redirect with trailing slash appended
164 if ($hasTrailingSlash) {
165
166 if ($hostRegex = $compiledRoute->getHostRegex()) {
167 $rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_host_%s} =1", $hostRegexUnique);
168 }
169
170 $rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$';
171 $rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]';
172 }
173
174 // the main rule
175
176 if ($hostRegex = $compiledRoute->getHostRegex()) {
177 $rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_host_%s} =1", $hostRegexUnique);
178 }
179
180 $rule[] = "RewriteCond %{REQUEST_URI} $regex";
181 $rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]";
182
183 return implode("\n", $rule);
184 }
185
186 /**
187 * Returns methods allowed for a route
188 *
189 * @param Route $route The route
190 *
191 * @return array The methods
192 */
193 private function getRouteMethods(Route $route)
194 {
195 $methods = array();
196 if ($req = $route->getRequirement('_method')) {
197 $methods = explode('|', strtoupper($req));
198 // GET and HEAD are equivalent
199 if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
200 $methods[] = 'HEAD';
201 }
202 }
203
204 return $methods;
205 }
206
207 /**
208 * Converts a regex to make it suitable for mod_rewrite
209 *
210 * @param string $regex The regex
211 *
212 * @return string The converted regex
213 */
214 private function regexToApacheRegex($regex)
215 {
216 $regexPatternEnd = strrpos($regex, $regex[0]);
217
218 return preg_replace('/\?P<.+?>/', '', substr($regex, 1, $regexPatternEnd - 1));
219 }
220
221 /**
222 * Escapes a string.
223 *
224 * @param string $string The string to be escaped
225 * @param string $char The character to be escaped
226 * @param string $with The character to be used for escaping
227 *
228 * @return string The escaped string
229 */
230 private static function escape($string, $char, $with)
231 {
232 $escaped = false;
233 $output = '';
234 foreach (str_split($string) as $symbol) {
235 if ($escaped) {
236 $output .= $symbol;
237 $escaped = false;
238 continue;
239 }
240 if ($symbol === $char) {
241 $output .= $with.$char;
242 continue;
243 }
244 if ($symbol === $with) {
245 $escaped = true;
246 }
247 $output .= $symbol;
248 }
249
250 return $output;
251 }
252}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php
new file mode 100644
index 00000000..612ac0d2
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php
@@ -0,0 +1,159 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14/**
15 * Collection of routes.
16 *
17 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
18 */
19class DumperCollection implements \IteratorAggregate
20{
21 /**
22 * @var DumperCollection|null
23 */
24 private $parent;
25
26 /**
27 * @var (DumperCollection|DumperRoute)[]
28 */
29 private $children = array();
30
31 /**
32 * @var array
33 */
34 private $attributes = array();
35
36 /**
37 * Returns the children routes and collections.
38 *
39 * @return (DumperCollection|DumperRoute)[] Array of DumperCollection|DumperRoute
40 */
41 public function all()
42 {
43 return $this->children;
44 }
45
46 /**
47 * Adds a route or collection
48 *
49 * @param DumperRoute|DumperCollection The route or collection
50 */
51 public function add($child)
52 {
53 if ($child instanceof DumperCollection) {
54 $child->setParent($this);
55 }
56 $this->children[] = $child;
57 }
58
59 /**
60 * Sets children.
61 *
62 * @param array $children The children
63 */
64 public function setAll(array $children)
65 {
66 foreach ($children as $child) {
67 if ($child instanceof DumperCollection) {
68 $child->setParent($this);
69 }
70 }
71 $this->children = $children;
72 }
73
74 /**
75 * Returns an iterator over the children.
76 *
77 * @return \Iterator The iterator
78 */
79 public function getIterator()
80 {
81 return new \ArrayIterator($this->children);
82 }
83
84 /**
85 * Returns the root of the collection.
86 *
87 * @return DumperCollection The root collection
88 */
89 public function getRoot()
90 {
91 return (null !== $this->parent) ? $this->parent->getRoot() : $this;
92 }
93
94 /**
95 * Returns the parent collection.
96 *
97 * @return DumperCollection|null The parent collection or null if the collection has no parent
98 */
99 protected function getParent()
100 {
101 return $this->parent;
102 }
103
104 /**
105 * Sets the parent collection.
106 *
107 * @param DumperCollection $parent The parent collection
108 */
109 protected function setParent(DumperCollection $parent)
110 {
111 $this->parent = $parent;
112 }
113
114 /**
115 * Returns true if the attribute is defined.
116 *
117 * @param string $name The attribute name
118 *
119 * @return Boolean true if the attribute is defined, false otherwise
120 */
121 public function hasAttribute($name)
122 {
123 return array_key_exists($name, $this->attributes);
124 }
125
126 /**
127 * Returns an attribute by name.
128 *
129 * @param string $name The attribute name
130 * @param mixed $default Default value is the attribute doesn't exist
131 *
132 * @return mixed The attribute value
133 */
134 public function getAttribute($name, $default = null)
135 {
136 return $this->hasAttribute($name) ? $this->attributes[$name] : $default;
137 }
138
139 /**
140 * Sets an attribute by name.
141 *
142 * @param string $name The attribute name
143 * @param mixed $value The attribute value
144 */
145 public function setAttribute($name, $value)
146 {
147 $this->attributes[$name] = $value;
148 }
149
150 /**
151 * Sets multiple attributes.
152 *
153 * @param array $attributes The attributes
154 */
155 public function setAttributes($attributes)
156 {
157 $this->attributes = $attributes;
158 }
159}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperPrefixCollection.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperPrefixCollection.php
new file mode 100644
index 00000000..26382b0b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperPrefixCollection.php
@@ -0,0 +1,108 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14/**
15 * Prefix tree of routes preserving routes order.
16 *
17 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
18 */
19class DumperPrefixCollection extends DumperCollection
20{
21 /**
22 * @var string
23 */
24 private $prefix = '';
25
26 /**
27 * Returns the prefix.
28 *
29 * @return string The prefix
30 */
31 public function getPrefix()
32 {
33 return $this->prefix;
34 }
35
36 /**
37 * Sets the prefix.
38 *
39 * @param string $prefix The prefix
40 */
41 public function setPrefix($prefix)
42 {
43 $this->prefix = $prefix;
44 }
45
46 /**
47 * Adds a route in the tree.
48 *
49 * @param DumperRoute $route The route
50 *
51 * @return DumperPrefixCollection The node the route was added to
52 *
53 * @throws \LogicException
54 */
55 public function addPrefixRoute(DumperRoute $route)
56 {
57 $prefix = $route->getRoute()->compile()->getStaticPrefix();
58
59 // Same prefix, add to current leave
60 if ($this->prefix === $prefix) {
61 $this->add($route);
62
63 return $this;
64 }
65
66 // Prefix starts with route's prefix
67 if ('' === $this->prefix || 0 === strpos($prefix, $this->prefix)) {
68 $collection = new DumperPrefixCollection();
69 $collection->setPrefix(substr($prefix, 0, strlen($this->prefix)+1));
70 $this->add($collection);
71
72 return $collection->addPrefixRoute($route);
73 }
74
75 // No match, fallback to parent (recursively)
76
77 if (null === $parent = $this->getParent()) {
78 throw new \LogicException("The collection root must not have a prefix");
79 }
80
81 return $parent->addPrefixRoute($route);
82 }
83
84 /**
85 * Merges nodes whose prefix ends with a slash
86 *
87 * Children of a node whose prefix ends with a slash are moved to the parent node
88 */
89 public function mergeSlashNodes()
90 {
91 $children = array();
92
93 foreach ($this as $child) {
94 if ($child instanceof self) {
95 $child->mergeSlashNodes();
96 if ('/' === substr($child->prefix, -1)) {
97 $children = array_merge($children, $child->all());
98 } else {
99 $children[] = $child;
100 }
101 } else {
102 $children[] = $child;
103 }
104 }
105
106 $this->setAll($children);
107 }
108}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperRoute.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperRoute.php
new file mode 100644
index 00000000..2928cdcc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperRoute.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15
16/**
17 * Container for a Route.
18 *
19 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
20 */
21class DumperRoute
22{
23 /**
24 * @var string
25 */
26 private $name;
27
28 /**
29 * @var Route
30 */
31 private $route;
32
33 /**
34 * Constructor.
35 *
36 * @param string $name The route name
37 * @param Route $route The route
38 */
39 public function __construct($name, Route $route)
40 {
41 $this->name = $name;
42 $this->route = $route;
43 }
44
45 /**
46 * Returns the route name.
47 *
48 * @return string The route name
49 */
50 public function getName()
51 {
52 return $this->name;
53 }
54
55 /**
56 * Returns the route.
57 *
58 * @return Route The route
59 */
60 public function getRoute()
61 {
62 return $this->route;
63 }
64}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php
new file mode 100644
index 00000000..52edc017
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14use Symfony\Component\Routing\RouteCollection;
15
16/**
17 * MatcherDumper is the abstract class for all built-in matcher dumpers.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21abstract class MatcherDumper implements MatcherDumperInterface
22{
23 /**
24 * @var RouteCollection
25 */
26 private $routes;
27
28 /**
29 * Constructor.
30 *
31 * @param RouteCollection $routes The RouteCollection to dump
32 */
33 public function __construct(RouteCollection $routes)
34 {
35 $this->routes = $routes;
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getRoutes()
42 {
43 return $this->routes;
44 }
45}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php
new file mode 100644
index 00000000..f85e4cef
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php
@@ -0,0 +1,37 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14/**
15 * MatcherDumperInterface is the interface that all matcher dumper classes must implement.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19interface MatcherDumperInterface
20{
21 /**
22 * Dumps a set of routes to a string representation of executable code
23 * that can then be used to match a request against these routes.
24 *
25 * @param array $options An array of options
26 *
27 * @return string Executable code
28 */
29 public function dump(array $options = array());
30
31 /**
32 * Gets the routes to dump.
33 *
34 * @return RouteCollection A RouteCollection instance
35 */
36 public function getRoutes();
37}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
new file mode 100644
index 00000000..dc17ffbe
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
@@ -0,0 +1,378 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\RouteCollection;
16
17/**
18 * PhpMatcherDumper creates a PHP class able to match URLs for a given set of routes.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 * @author Tobias Schultze <http://tobion.de>
22 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
23 */
24class PhpMatcherDumper extends MatcherDumper
25{
26 /**
27 * Dumps a set of routes to a PHP class.
28 *
29 * Available options:
30 *
31 * * class: The class name
32 * * base_class: The base class name
33 *
34 * @param array $options An array of options
35 *
36 * @return string A PHP class representing the matcher class
37 */
38 public function dump(array $options = array())
39 {
40 $options = array_replace(array(
41 'class' => 'ProjectUrlMatcher',
42 'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
43 ), $options);
44
45 // trailing slash support is only enabled if we know how to redirect the user
46 $interfaces = class_implements($options['base_class']);
47 $supportsRedirections = isset($interfaces['Symfony\\Component\\Routing\\Matcher\\RedirectableUrlMatcherInterface']);
48
49 return <<<EOF
50<?php
51
52use Symfony\Component\Routing\Exception\MethodNotAllowedException;
53use Symfony\Component\Routing\Exception\ResourceNotFoundException;
54use Symfony\Component\Routing\RequestContext;
55
56/**
57 * {$options['class']}
58 *
59 * This class has been auto-generated
60 * by the Symfony Routing Component.
61 */
62class {$options['class']} extends {$options['base_class']}
63{
64 /**
65 * Constructor.
66 */
67 public function __construct(RequestContext \$context)
68 {
69 \$this->context = \$context;
70 }
71
72{$this->generateMatchMethod($supportsRedirections)}
73}
74
75EOF;
76 }
77
78 /**
79 * Generates the code for the match method implementing UrlMatcherInterface.
80 *
81 * @param Boolean $supportsRedirections Whether redirections are supported by the base class
82 *
83 * @return string Match method as PHP code
84 */
85 private function generateMatchMethod($supportsRedirections)
86 {
87 $code = rtrim($this->compileRoutes($this->getRoutes(), $supportsRedirections), "\n");
88
89 return <<<EOF
90 public function match(\$pathinfo)
91 {
92 \$allow = array();
93 \$pathinfo = rawurldecode(\$pathinfo);
94
95$code
96
97 throw 0 < count(\$allow) ? new MethodNotAllowedException(array_unique(\$allow)) : new ResourceNotFoundException();
98 }
99EOF;
100 }
101
102 /**
103 * Generates PHP code to match a RouteCollection with all its routes.
104 *
105 * @param RouteCollection $routes A RouteCollection instance
106 * @param Boolean $supportsRedirections Whether redirections are supported by the base class
107 *
108 * @return string PHP code
109 */
110 private function compileRoutes(RouteCollection $routes, $supportsRedirections)
111 {
112 $fetchedHost = false;
113
114 $groups = $this->groupRoutesByHostRegex($routes);
115 $code = '';
116
117 foreach ($groups as $collection) {
118 if (null !== $regex = $collection->getAttribute('host_regex')) {
119 if (!$fetchedHost) {
120 $code .= " \$host = \$this->context->getHost();\n\n";
121 $fetchedHost = true;
122 }
123
124 $code .= sprintf(" if (preg_match(%s, \$host, \$hostMatches)) {\n", var_export($regex, true));
125 }
126
127 $tree = $this->buildPrefixTree($collection);
128 $groupCode = $this->compilePrefixRoutes($tree, $supportsRedirections);
129
130 if (null !== $regex) {
131 // apply extra indention at each line (except empty ones)
132 $groupCode = preg_replace('/^.{2,}$/m', ' $0', $groupCode);
133 $code .= $groupCode;
134 $code .= " }\n\n";
135 } else {
136 $code .= $groupCode;
137 }
138 }
139
140 return $code;
141 }
142
143 /**
144 * Generates PHP code recursively to match a tree of routes
145 *
146 * @param DumperPrefixCollection $collection A DumperPrefixCollection instance
147 * @param Boolean $supportsRedirections Whether redirections are supported by the base class
148 * @param string $parentPrefix Prefix of the parent collection
149 *
150 * @return string PHP code
151 */
152 private function compilePrefixRoutes(DumperPrefixCollection $collection, $supportsRedirections, $parentPrefix = '')
153 {
154 $code = '';
155 $prefix = $collection->getPrefix();
156 $optimizable = 1 < strlen($prefix) && 1 < count($collection->all());
157 $optimizedPrefix = $parentPrefix;
158
159 if ($optimizable) {
160 $optimizedPrefix = $prefix;
161
162 $code .= sprintf(" if (0 === strpos(\$pathinfo, %s)) {\n", var_export($prefix, true));
163 }
164
165 foreach ($collection as $route) {
166 if ($route instanceof DumperCollection) {
167 $code .= $this->compilePrefixRoutes($route, $supportsRedirections, $optimizedPrefix);
168 } else {
169 $code .= $this->compileRoute($route->getRoute(), $route->getName(), $supportsRedirections, $optimizedPrefix)."\n";
170 }
171 }
172
173 if ($optimizable) {
174 $code .= " }\n\n";
175 // apply extra indention at each line (except empty ones)
176 $code = preg_replace('/^.{2,}$/m', ' $0', $code);
177 }
178
179 return $code;
180 }
181
182 /**
183 * Compiles a single Route to PHP code used to match it against the path info.
184 *
185 * @param Route $route A Route instance
186 * @param string $name The name of the Route
187 * @param Boolean $supportsRedirections Whether redirections are supported by the base class
188 * @param string|null $parentPrefix The prefix of the parent collection used to optimize the code
189 *
190 * @return string PHP code
191 *
192 * @throws \LogicException
193 */
194 private function compileRoute(Route $route, $name, $supportsRedirections, $parentPrefix = null)
195 {
196 $code = '';
197 $compiledRoute = $route->compile();
198 $conditions = array();
199 $hasTrailingSlash = false;
200 $matches = false;
201 $hostMatches = false;
202 $methods = array();
203
204 if ($req = $route->getRequirement('_method')) {
205 $methods = explode('|', strtoupper($req));
206 // GET and HEAD are equivalent
207 if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
208 $methods[] = 'HEAD';
209 }
210 }
211
212 $supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('HEAD', $methods));
213
214 if (!count($compiledRoute->getPathVariables()) && false !== preg_match('#^(.)\^(?P<url>.*?)\$\1#', $compiledRoute->getRegex(), $m)) {
215 if ($supportsTrailingSlash && substr($m['url'], -1) === '/') {
216 $conditions[] = sprintf("rtrim(\$pathinfo, '/') === %s", var_export(rtrim(str_replace('\\', '', $m['url']), '/'), true));
217 $hasTrailingSlash = true;
218 } else {
219 $conditions[] = sprintf("\$pathinfo === %s", var_export(str_replace('\\', '', $m['url']), true));
220 }
221 } else {
222 if ($compiledRoute->getStaticPrefix() && $compiledRoute->getStaticPrefix() !== $parentPrefix) {
223 $conditions[] = sprintf("0 === strpos(\$pathinfo, %s)", var_export($compiledRoute->getStaticPrefix(), true));
224 }
225
226 $regex = $compiledRoute->getRegex();
227 if ($supportsTrailingSlash && $pos = strpos($regex, '/$')) {
228 $regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
229 $hasTrailingSlash = true;
230 }
231 $conditions[] = sprintf("preg_match(%s, \$pathinfo, \$matches)", var_export($regex, true));
232
233 $matches = true;
234 }
235
236 if ($compiledRoute->getHostVariables()) {
237 $hostMatches = true;
238 }
239
240 $conditions = implode(' && ', $conditions);
241
242 $code .= <<<EOF
243 // $name
244 if ($conditions) {
245
246EOF;
247
248 if ($methods) {
249 $gotoname = 'not_'.preg_replace('/[^A-Za-z0-9_]/', '', $name);
250
251 if (1 === count($methods)) {
252 $code .= <<<EOF
253 if (\$this->context->getMethod() != '$methods[0]') {
254 \$allow[] = '$methods[0]';
255 goto $gotoname;
256 }
257
258
259EOF;
260 } else {
261 $methods = implode("', '", $methods);
262 $code .= <<<EOF
263 if (!in_array(\$this->context->getMethod(), array('$methods'))) {
264 \$allow = array_merge(\$allow, array('$methods'));
265 goto $gotoname;
266 }
267
268
269EOF;
270 }
271 }
272
273 if ($hasTrailingSlash) {
274 $code .= <<<EOF
275 if (substr(\$pathinfo, -1) !== '/') {
276 return \$this->redirect(\$pathinfo.'/', '$name');
277 }
278
279
280EOF;
281 }
282
283 if ($scheme = $route->getRequirement('_scheme')) {
284 if (!$supportsRedirections) {
285 throw new \LogicException('The "_scheme" requirement is only supported for URL matchers that implement RedirectableUrlMatcherInterface.');
286 }
287
288 $code .= <<<EOF
289 if (\$this->context->getScheme() !== '$scheme') {
290 return \$this->redirect(\$pathinfo, '$name', '$scheme');
291 }
292
293
294EOF;
295 }
296
297 // optimize parameters array
298 if ($matches || $hostMatches) {
299 $vars = array();
300 if ($hostMatches) {
301 $vars[] = '$hostMatches';
302 }
303 if ($matches) {
304 $vars[] = '$matches';
305 }
306 $vars[] = "array('_route' => '$name')";
307
308 $code .= sprintf(" return \$this->mergeDefaults(array_replace(%s), %s);\n"
309 , implode(', ', $vars), str_replace("\n", '', var_export($route->getDefaults(), true)));
310
311 } elseif ($route->getDefaults()) {
312 $code .= sprintf(" return %s;\n", str_replace("\n", '', var_export(array_replace($route->getDefaults(), array('_route' => $name)), true)));
313 } else {
314 $code .= sprintf(" return array('_route' => '%s');\n", $name);
315 }
316 $code .= " }\n";
317
318 if ($methods) {
319 $code .= " $gotoname:\n";
320 }
321
322 return $code;
323 }
324
325 /**
326 * Groups consecutive routes having the same host regex.
327 *
328 * The result is a collection of collections of routes having the same host regex.
329 *
330 * @param RouteCollection $routes A flat RouteCollection
331 *
332 * @return DumperCollection A collection with routes grouped by host regex in sub-collections
333 */
334 private function groupRoutesByHostRegex(RouteCollection $routes)
335 {
336 $groups = new DumperCollection();
337
338 $currentGroup = new DumperCollection();
339 $currentGroup->setAttribute('host_regex', null);
340 $groups->add($currentGroup);
341
342 foreach ($routes as $name => $route) {
343 $hostRegex = $route->compile()->getHostRegex();
344 if ($currentGroup->getAttribute('host_regex') !== $hostRegex) {
345 $currentGroup = new DumperCollection();
346 $currentGroup->setAttribute('host_regex', $hostRegex);
347 $groups->add($currentGroup);
348 }
349 $currentGroup->add(new DumperRoute($name, $route));
350 }
351
352 return $groups;
353 }
354
355 /**
356 * Organizes the routes into a prefix tree.
357 *
358 * Routes order is preserved such that traversing the tree will traverse the
359 * routes in the origin order.
360 *
361 * @param DumperCollection $collection A collection of routes
362 *
363 * @return DumperPrefixCollection
364 */
365 private function buildPrefixTree(DumperCollection $collection)
366 {
367 $tree = new DumperPrefixCollection();
368 $current = $tree;
369
370 foreach ($collection as $route) {
371 $current = $current->addPrefixRoute($route);
372 }
373
374 $tree->mergeSlashNodes();
375
376 return $tree;
377 }
378}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php
new file mode 100644
index 00000000..51e80057
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\Exception\ResourceNotFoundException;
15use Symfony\Component\Routing\Route;
16
17/**
18 * @author Fabien Potencier <fabien@symfony.com>
19 *
20 * @api
21 */
22abstract class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
23{
24 /**
25 * {@inheritdoc}
26 */
27 public function match($pathinfo)
28 {
29 try {
30 $parameters = parent::match($pathinfo);
31 } catch (ResourceNotFoundException $e) {
32 if ('/' === substr($pathinfo, -1) || !in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
33 throw $e;
34 }
35
36 try {
37 parent::match($pathinfo.'/');
38
39 return $this->redirect($pathinfo.'/', null);
40 } catch (ResourceNotFoundException $e2) {
41 throw $e;
42 }
43 }
44
45 return $parameters;
46 }
47
48 /**
49 * {@inheritDoc}
50 */
51 protected function handleRouteRequirements($pathinfo, $name, Route $route)
52 {
53 // check HTTP scheme requirement
54 $scheme = $route->getRequirement('_scheme');
55 if ($scheme && $this->context->getScheme() !== $scheme) {
56 return array(self::ROUTE_MATCH, $this->redirect($pathinfo, $name, $scheme));
57 }
58
59 return array(self::REQUIREMENT_MATCH, null);
60 }
61}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php
new file mode 100644
index 00000000..ea91e075
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php
@@ -0,0 +1,35 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher;
13
14/**
15 * RedirectableUrlMatcherInterface knows how to redirect the user.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 *
19 * @api
20 */
21interface RedirectableUrlMatcherInterface
22{
23 /**
24 * Redirects the user to another URL.
25 *
26 * @param string $path The path info to redirect to.
27 * @param string $route The route name that matched
28 * @param string|null $scheme The URL scheme (null to keep the current one)
29 *
30 * @return array An array of parameters
31 *
32 * @api
33 */
34 public function redirect($path, $route, $scheme = null);
35}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php
new file mode 100644
index 00000000..b5def3d4
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\HttpFoundation\Request;
15use Symfony\Component\Routing\Exception\ResourceNotFoundException;
16use Symfony\Component\Routing\Exception\MethodNotAllowedException;
17
18/**
19 * RequestMatcherInterface is the interface that all request matcher classes must implement.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 */
23interface RequestMatcherInterface
24{
25 /**
26 * Tries to match a request with a set of routes.
27 *
28 * If the matcher can not find information, it must throw one of the exceptions documented
29 * below.
30 *
31 * @param Request $request The request to match
32 *
33 * @return array An array of parameters
34 *
35 * @throws ResourceNotFoundException If no matching resource could be found
36 * @throws MethodNotAllowedException If a matching resource was found but the request method is not allowed
37 */
38 public function matchRequest(Request $request);
39}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php
new file mode 100644
index 00000000..c09f83e8
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php
@@ -0,0 +1,121 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\Exception\ExceptionInterface;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\RouteCollection;
17use Symfony\Component\Routing\Matcher\UrlMatcher;
18
19/**
20 * TraceableUrlMatcher helps debug path info matching by tracing the match.
21 *
22 * @author Fabien Potencier <fabien@symfony.com>
23 */
24class TraceableUrlMatcher extends UrlMatcher
25{
26 const ROUTE_DOES_NOT_MATCH = 0;
27 const ROUTE_ALMOST_MATCHES = 1;
28 const ROUTE_MATCHES = 2;
29
30 protected $traces;
31
32 public function getTraces($pathinfo)
33 {
34 $this->traces = array();
35
36 try {
37 $this->match($pathinfo);
38 } catch (ExceptionInterface $e) {
39 }
40
41 return $this->traces;
42 }
43
44 protected function matchCollection($pathinfo, RouteCollection $routes)
45 {
46 foreach ($routes as $name => $route) {
47 $compiledRoute = $route->compile();
48
49 if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
50 // does it match without any requirements?
51 $r = new Route($route->getPath(), $route->getDefaults(), array(), $route->getOptions());
52 $cr = $r->compile();
53 if (!preg_match($cr->getRegex(), $pathinfo)) {
54 $this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
55
56 continue;
57 }
58
59 foreach ($route->getRequirements() as $n => $regex) {
60 $r = new Route($route->getPath(), $route->getDefaults(), array($n => $regex), $route->getOptions());
61 $cr = $r->compile();
62
63 if (in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) {
64 $this->addTrace(sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route);
65
66 continue 2;
67 }
68 }
69
70 continue;
71 }
72
73 // check host requirement
74 $hostMatches = array();
75 if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
76 $this->addTrace(sprintf('Host "%s" does not match the requirement ("%s")', $this->context->getHost(), $route->getHost()), self::ROUTE_ALMOST_MATCHES, $name, $route);
77
78 return true;
79 }
80
81 // check HTTP method requirement
82 if ($req = $route->getRequirement('_method')) {
83 // HEAD and GET are equivalent as per RFC
84 if ('HEAD' === $method = $this->context->getMethod()) {
85 $method = 'GET';
86 }
87
88 if (!in_array($method, $req = explode('|', strtoupper($req)))) {
89 $this->allow = array_merge($this->allow, $req);
90
91 $this->addTrace(sprintf('Method "%s" does not match the requirement ("%s")', $this->context->getMethod(), implode(', ', $req)), self::ROUTE_ALMOST_MATCHES, $name, $route);
92
93 continue;
94 }
95 }
96
97 // check HTTP scheme requirement
98 if ($scheme = $route->getRequirement('_scheme')) {
99 if ($this->context->getScheme() !== $scheme) {
100 $this->addTrace(sprintf('Scheme "%s" does not match the requirement ("%s"); the user will be redirected', $this->context->getScheme(), $scheme), self::ROUTE_ALMOST_MATCHES, $name, $route);
101
102 return true;
103 }
104 }
105
106 $this->addTrace('Route matches!', self::ROUTE_MATCHES, $name, $route);
107
108 return true;
109 }
110 }
111
112 private function addTrace($log, $level = self::ROUTE_DOES_NOT_MATCH, $name = null, $route = null)
113 {
114 $this->traces[] = array(
115 'log' => $log,
116 'name' => $name,
117 'level' => $level,
118 'path' => null !== $route ? $route->getPath() : null,
119 );
120 }
121}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php
new file mode 100644
index 00000000..db18ec4e
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php
@@ -0,0 +1,208 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15use Symfony\Component\Routing\Exception\ResourceNotFoundException;
16use Symfony\Component\Routing\RouteCollection;
17use Symfony\Component\Routing\RequestContext;
18use Symfony\Component\Routing\Route;
19
20/**
21 * UrlMatcher matches URL based on a set of routes.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 *
25 * @api
26 */
27class UrlMatcher implements UrlMatcherInterface
28{
29 const REQUIREMENT_MATCH = 0;
30 const REQUIREMENT_MISMATCH = 1;
31 const ROUTE_MATCH = 2;
32
33 /**
34 * @var RequestContext
35 */
36 protected $context;
37
38 /**
39 * @var array
40 */
41 protected $allow = array();
42
43 /**
44 * @var RouteCollection
45 */
46 protected $routes;
47
48 /**
49 * Constructor.
50 *
51 * @param RouteCollection $routes A RouteCollection instance
52 * @param RequestContext $context The context
53 *
54 * @api
55 */
56 public function __construct(RouteCollection $routes, RequestContext $context)
57 {
58 $this->routes = $routes;
59 $this->context = $context;
60 }
61
62 /**
63 * {@inheritdoc}
64 */
65 public function setContext(RequestContext $context)
66 {
67 $this->context = $context;
68 }
69
70 /**
71 * {@inheritdoc}
72 */
73 public function getContext()
74 {
75 return $this->context;
76 }
77
78 /**
79 * {@inheritdoc}
80 */
81 public function match($pathinfo)
82 {
83 $this->allow = array();
84
85 if ($ret = $this->matchCollection(rawurldecode($pathinfo), $this->routes)) {
86 return $ret;
87 }
88
89 throw 0 < count($this->allow)
90 ? new MethodNotAllowedException(array_unique(array_map('strtoupper', $this->allow)))
91 : new ResourceNotFoundException();
92 }
93
94 /**
95 * Tries to match a URL with a set of routes.
96 *
97 * @param string $pathinfo The path info to be parsed
98 * @param RouteCollection $routes The set of routes
99 *
100 * @return array An array of parameters
101 *
102 * @throws ResourceNotFoundException If the resource could not be found
103 * @throws MethodNotAllowedException If the resource was found but the request method is not allowed
104 */
105 protected function matchCollection($pathinfo, RouteCollection $routes)
106 {
107 foreach ($routes as $name => $route) {
108 $compiledRoute = $route->compile();
109
110 // check the static prefix of the URL first. Only use the more expensive preg_match when it matches
111 if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute->getStaticPrefix())) {
112 continue;
113 }
114
115 if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
116 continue;
117 }
118
119 $hostMatches = array();
120 if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
121 continue;
122 }
123
124 // check HTTP method requirement
125 if ($req = $route->getRequirement('_method')) {
126 // HEAD and GET are equivalent as per RFC
127 if ('HEAD' === $method = $this->context->getMethod()) {
128 $method = 'GET';
129 }
130
131 if (!in_array($method, $req = explode('|', strtoupper($req)))) {
132 $this->allow = array_merge($this->allow, $req);
133
134 continue;
135 }
136 }
137
138 $status = $this->handleRouteRequirements($pathinfo, $name, $route);
139
140 if (self::ROUTE_MATCH === $status[0]) {
141 return $status[1];
142 }
143
144 if (self::REQUIREMENT_MISMATCH === $status[0]) {
145 continue;
146 }
147
148 return $this->getAttributes($route, $name, array_replace($matches, $hostMatches));
149 }
150 }
151
152 /**
153 * Returns an array of values to use as request attributes.
154 *
155 * As this method requires the Route object, it is not available
156 * in matchers that do not have access to the matched Route instance
157 * (like the PHP and Apache matcher dumpers).
158 *
159 * @param Route $route The route we are matching against
160 * @param string $name The name of the route
161 * @param array $attributes An array of attributes from the matcher
162 *
163 * @return array An array of parameters
164 */
165 protected function getAttributes(Route $route, $name, array $attributes)
166 {
167 $attributes['_route'] = $name;
168
169 return $this->mergeDefaults($attributes, $route->getDefaults());
170 }
171
172 /**
173 * Handles specific route requirements.
174 *
175 * @param string $pathinfo The path
176 * @param string $name The route name
177 * @param Route $route The route
178 *
179 * @return array The first element represents the status, the second contains additional information
180 */
181 protected function handleRouteRequirements($pathinfo, $name, Route $route)
182 {
183 // check HTTP scheme requirement
184 $scheme = $route->getRequirement('_scheme');
185 $status = $scheme && $scheme !== $this->context->getScheme() ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH;
186
187 return array($status, null);
188 }
189
190 /**
191 * Get merged default parameters.
192 *
193 * @param array $params The parameters
194 * @param array $defaults The defaults
195 *
196 * @return array Merged default parameters
197 */
198 protected function mergeDefaults($params, $defaults)
199 {
200 foreach ($params as $key => $value) {
201 if (!is_int($key)) {
202 $defaults[$key] = $value;
203 }
204 }
205
206 return $defaults;
207 }
208}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php
new file mode 100644
index 00000000..dd718b15
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php
@@ -0,0 +1,43 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\RequestContextAwareInterface;
15use Symfony\Component\Routing\Exception\ResourceNotFoundException;
16use Symfony\Component\Routing\Exception\MethodNotAllowedException;
17
18/**
19 * UrlMatcherInterface is the interface that all URL matcher classes must implement.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 *
23 * @api
24 */
25interface UrlMatcherInterface extends RequestContextAwareInterface
26{
27 /**
28 * Tries to match a URL path with a set of routes.
29 *
30 * If the matcher can not find information, it must throw one of the exceptions documented
31 * below.
32 *
33 * @param string $pathinfo The path info to be parsed (raw format, i.e. not urldecoded)
34 *
35 * @return array An array of parameters
36 *
37 * @throws ResourceNotFoundException If the resource could not be found
38 * @throws MethodNotAllowedException If the resource was found but the request method is not allowed
39 *
40 * @api
41 */
42 public function match($pathinfo);
43}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/README.md b/vendor/symfony/routing/Symfony/Component/Routing/README.md
new file mode 100644
index 00000000..663844a6
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/README.md
@@ -0,0 +1,34 @@
1Routing Component
2=================
3
4Routing associates a request with the code that will convert it to a response.
5
6The example below demonstrates how you can set up a fully working routing
7system:
8
9 use Symfony\Component\HttpFoundation\Request;
10 use Symfony\Component\Routing\Matcher\UrlMatcher;
11 use Symfony\Component\Routing\RequestContext;
12 use Symfony\Component\Routing\RouteCollection;
13 use Symfony\Component\Routing\Route;
14
15 $routes = new RouteCollection();
16 $routes->add('hello', new Route('/hello', array('controller' => 'foo')));
17
18 $context = new RequestContext();
19
20 // this is optional and can be done without a Request instance
21 $context->fromRequest(Request::createFromGlobals());
22
23 $matcher = new UrlMatcher($routes, $context);
24
25 $parameters = $matcher->match('/hello');
26
27Resources
28---------
29
30You can run the unit tests with the following command:
31
32 $ cd path/to/Symfony/Component/Routing/
33 $ composer.phar install --dev
34 $ phpunit
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RequestContext.php b/vendor/symfony/routing/Symfony/Component/Routing/RequestContext.php
new file mode 100644
index 00000000..cb536968
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RequestContext.php
@@ -0,0 +1,315 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing;
13
14use Symfony\Component\HttpFoundation\Request;
15
16/**
17 * Holds information about the current request.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 *
21 * @api
22 */
23class RequestContext
24{
25 private $baseUrl;
26 private $pathInfo;
27 private $method;
28 private $host;
29 private $scheme;
30 private $httpPort;
31 private $httpsPort;
32 private $queryString;
33
34 /**
35 * @var array
36 */
37 private $parameters = array();
38
39 /**
40 * Constructor.
41 *
42 * @param string $baseUrl The base URL
43 * @param string $method The HTTP method
44 * @param string $host The HTTP host name
45 * @param string $scheme The HTTP scheme
46 * @param integer $httpPort The HTTP port
47 * @param integer $httpsPort The HTTPS port
48 * @param string $path The path
49 * @param string $queryString The query string
50 *
51 * @api
52 */
53 public function __construct($baseUrl = '', $method = 'GET', $host = 'localhost', $scheme = 'http', $httpPort = 80, $httpsPort = 443, $path = '/', $queryString = '')
54 {
55 $this->baseUrl = $baseUrl;
56 $this->method = strtoupper($method);
57 $this->host = $host;
58 $this->scheme = strtolower($scheme);
59 $this->httpPort = $httpPort;
60 $this->httpsPort = $httpsPort;
61 $this->pathInfo = $path;
62 $this->queryString = $queryString;
63 }
64
65 public function fromRequest(Request $request)
66 {
67 $this->setBaseUrl($request->getBaseUrl());
68 $this->setPathInfo($request->getPathInfo());
69 $this->setMethod($request->getMethod());
70 $this->setHost($request->getHost());
71 $this->setScheme($request->getScheme());
72 $this->setHttpPort($request->isSecure() ? $this->httpPort : $request->getPort());
73 $this->setHttpsPort($request->isSecure() ? $request->getPort() : $this->httpsPort);
74 $this->setQueryString($request->server->get('QUERY_STRING'));
75 }
76
77 /**
78 * Gets the base URL.
79 *
80 * @return string The base URL
81 */
82 public function getBaseUrl()
83 {
84 return $this->baseUrl;
85 }
86
87 /**
88 * Sets the base URL.
89 *
90 * @param string $baseUrl The base URL
91 *
92 * @api
93 */
94 public function setBaseUrl($baseUrl)
95 {
96 $this->baseUrl = $baseUrl;
97 }
98
99 /**
100 * Gets the path info.
101 *
102 * @return string The path info
103 */
104 public function getPathInfo()
105 {
106 return $this->pathInfo;
107 }
108
109 /**
110 * Sets the path info.
111 *
112 * @param string $pathInfo The path info
113 */
114 public function setPathInfo($pathInfo)
115 {
116 $this->pathInfo = $pathInfo;
117 }
118
119 /**
120 * Gets the HTTP method.
121 *
122 * The method is always an uppercased string.
123 *
124 * @return string The HTTP method
125 */
126 public function getMethod()
127 {
128 return $this->method;
129 }
130
131 /**
132 * Sets the HTTP method.
133 *
134 * @param string $method The HTTP method
135 *
136 * @api
137 */
138 public function setMethod($method)
139 {
140 $this->method = strtoupper($method);
141 }
142
143 /**
144 * Gets the HTTP host.
145 *
146 * @return string The HTTP host
147 */
148 public function getHost()
149 {
150 return $this->host;
151 }
152
153 /**
154 * Sets the HTTP host.
155 *
156 * @param string $host The HTTP host
157 *
158 * @api
159 */
160 public function setHost($host)
161 {
162 $this->host = $host;
163 }
164
165 /**
166 * Gets the HTTP scheme.
167 *
168 * @return string The HTTP scheme
169 */
170 public function getScheme()
171 {
172 return $this->scheme;
173 }
174
175 /**
176 * Sets the HTTP scheme.
177 *
178 * @param string $scheme The HTTP scheme
179 *
180 * @api
181 */
182 public function setScheme($scheme)
183 {
184 $this->scheme = strtolower($scheme);
185 }
186
187 /**
188 * Gets the HTTP port.
189 *
190 * @return string The HTTP port
191 */
192 public function getHttpPort()
193 {
194 return $this->httpPort;
195 }
196
197 /**
198 * Sets the HTTP port.
199 *
200 * @param string $httpPort The HTTP port
201 *
202 * @api
203 */
204 public function setHttpPort($httpPort)
205 {
206 $this->httpPort = $httpPort;
207 }
208
209 /**
210 * Gets the HTTPS port.
211 *
212 * @return string The HTTPS port
213 */
214 public function getHttpsPort()
215 {
216 return $this->httpsPort;
217 }
218
219 /**
220 * Sets the HTTPS port.
221 *
222 * @param string $httpsPort The HTTPS port
223 *
224 * @api
225 */
226 public function setHttpsPort($httpsPort)
227 {
228 $this->httpsPort = $httpsPort;
229 }
230
231 /**
232 * Gets the query string.
233 *
234 * @return string The query string
235 */
236 public function getQueryString()
237 {
238 return $this->queryString;
239 }
240
241 /**
242 * Sets the query string.
243 *
244 * @param string $queryString The query string
245 *
246 * @api
247 */
248 public function setQueryString($queryString)
249 {
250 $this->queryString = $queryString;
251 }
252
253 /**
254 * Returns the parameters.
255 *
256 * @return array The parameters
257 */
258 public function getParameters()
259 {
260 return $this->parameters;
261 }
262
263 /**
264 * Sets the parameters.
265 *
266 * This method implements a fluent interface.
267 *
268 * @param array $parameters The parameters
269 *
270 * @return Route The current Route instance
271 */
272 public function setParameters(array $parameters)
273 {
274 $this->parameters = $parameters;
275
276 return $this;
277 }
278
279 /**
280 * Gets a parameter value.
281 *
282 * @param string $name A parameter name
283 *
284 * @return mixed The parameter value
285 */
286 public function getParameter($name)
287 {
288 return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
289 }
290
291 /**
292 * Checks if a parameter value is set for the given parameter.
293 *
294 * @param string $name A parameter name
295 *
296 * @return Boolean true if the parameter value is set, false otherwise
297 */
298 public function hasParameter($name)
299 {
300 return array_key_exists($name, $this->parameters);
301 }
302
303 /**
304 * Sets a parameter value.
305 *
306 * @param string $name A parameter name
307 * @param mixed $parameter The parameter value
308 *
309 * @api
310 */
311 public function setParameter($name, $parameter)
312 {
313 $this->parameters[$name] = $parameter;
314 }
315}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php
new file mode 100644
index 00000000..daf52549
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php
@@ -0,0 +1,36 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing;
13
14/**
15 * @api
16 */
17interface RequestContextAwareInterface
18{
19 /**
20 * Sets the request context.
21 *
22 * @param RequestContext $context The context
23 *
24 * @api
25 */
26 public function setContext(RequestContext $context);
27
28 /**
29 * Gets the request context.
30 *
31 * @return RequestContext The context
32 *
33 * @api
34 */
35 public function getContext();
36}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Route.php b/vendor/symfony/routing/Symfony/Component/Routing/Route.php
new file mode 100644
index 00000000..060e9781
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Route.php
@@ -0,0 +1,594 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing;
13
14/**
15 * A Route describes a route and its parameters.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @author Tobias Schultze <http://tobion.de>
19 *
20 * @api
21 */
22class Route implements \Serializable
23{
24 /**
25 * @var string
26 */
27 private $path = '/';
28
29 /**
30 * @var string
31 */
32 private $host = '';
33
34 /**
35 * @var array
36 */
37 private $schemes = array();
38
39 /**
40 * @var array
41 */
42 private $methods = array();
43
44 /**
45 * @var array
46 */
47 private $defaults = array();
48
49 /**
50 * @var array
51 */
52 private $requirements = array();
53
54 /**
55 * @var array
56 */
57 private $options = array();
58
59 /**
60 * @var null|RouteCompiler
61 */
62 private $compiled;
63
64 /**
65 * Constructor.
66 *
67 * Available options:
68 *
69 * * compiler_class: A class name able to compile this route instance (RouteCompiler by default)
70 *
71 * @param string $path The path pattern to match
72 * @param array $defaults An array of default parameter values
73 * @param array $requirements An array of requirements for parameters (regexes)
74 * @param array $options An array of options
75 * @param string $host The host pattern to match
76 * @param string|array $schemes A required URI scheme or an array of restricted schemes
77 * @param string|array $methods A required HTTP method or an array of restricted methods
78 *
79 * @api
80 */
81 public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $host = '', $schemes = array(), $methods = array())
82 {
83 $this->setPath($path);
84 $this->setDefaults($defaults);
85 $this->setRequirements($requirements);
86 $this->setOptions($options);
87 $this->setHost($host);
88 // The conditions make sure that an initial empty $schemes/$methods does not override the corresponding requirement.
89 // They can be removed when the BC layer is removed.
90 if ($schemes) {
91 $this->setSchemes($schemes);
92 }
93 if ($methods) {
94 $this->setMethods($methods);
95 }
96 }
97
98 public function serialize()
99 {
100 return serialize(array(
101 'path' => $this->path,
102 'host' => $this->host,
103 'defaults' => $this->defaults,
104 'requirements' => $this->requirements,
105 'options' => $this->options,
106 'schemes' => $this->schemes,
107 'methods' => $this->methods,
108 ));
109 }
110
111 public function unserialize($data)
112 {
113 $data = unserialize($data);
114 $this->path = $data['path'];
115 $this->host = $data['host'];
116 $this->defaults = $data['defaults'];
117 $this->requirements = $data['requirements'];
118 $this->options = $data['options'];
119 $this->schemes = $data['schemes'];
120 $this->methods = $data['methods'];
121 }
122
123 /**
124 * Returns the pattern for the path.
125 *
126 * @return string The pattern
127 *
128 * @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead.
129 */
130 public function getPattern()
131 {
132 return $this->path;
133 }
134
135 /**
136 * Sets the pattern for the path.
137 *
138 * This method implements a fluent interface.
139 *
140 * @param string $pattern The path pattern
141 *
142 * @return Route The current Route instance
143 *
144 * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead.
145 */
146 public function setPattern($pattern)
147 {
148 return $this->setPath($pattern);
149 }
150
151 /**
152 * Returns the pattern for the path.
153 *
154 * @return string The path pattern
155 */
156 public function getPath()
157 {
158 return $this->path;
159 }
160
161 /**
162 * Sets the pattern for the path.
163 *
164 * This method implements a fluent interface.
165 *
166 * @param string $pattern The path pattern
167 *
168 * @return Route The current Route instance
169 */
170 public function setPath($pattern)
171 {
172 // A pattern must start with a slash and must not have multiple slashes at the beginning because the
173 // generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
174 $this->path = '/'.ltrim(trim($pattern), '/');
175 $this->compiled = null;
176
177 return $this;
178 }
179
180 /**
181 * Returns the pattern for the host.
182 *
183 * @return string The host pattern
184 */
185 public function getHost()
186 {
187 return $this->host;
188 }
189
190 /**
191 * Sets the pattern for the host.
192 *
193 * This method implements a fluent interface.
194 *
195 * @param string $pattern The host pattern
196 *
197 * @return Route The current Route instance
198 */
199 public function setHost($pattern)
200 {
201 $this->host = (string) $pattern;
202 $this->compiled = null;
203
204 return $this;
205 }
206
207 /**
208 * Returns the lowercased schemes this route is restricted to.
209 * So an empty array means that any scheme is allowed.
210 *
211 * @return array The schemes
212 */
213 public function getSchemes()
214 {
215 return $this->schemes;
216 }
217
218 /**
219 * Sets the schemes (e.g. 'https') this route is restricted to.
220 * So an empty array means that any scheme is allowed.
221 *
222 * This method implements a fluent interface.
223 *
224 * @param string|array $schemes The scheme or an array of schemes
225 *
226 * @return Route The current Route instance
227 */
228 public function setSchemes($schemes)
229 {
230 $this->schemes = array_map('strtolower', (array) $schemes);
231
232 // this is to keep BC and will be removed in a future version
233 if ($this->schemes) {
234 $this->requirements['_scheme'] = implode('|', $this->schemes);
235 } else {
236 unset($this->requirements['_scheme']);
237 }
238
239 $this->compiled = null;
240
241 return $this;
242 }
243
244 /**
245 * Returns the uppercased HTTP methods this route is restricted to.
246 * So an empty array means that any method is allowed.
247 *
248 * @return array The schemes
249 */
250 public function getMethods()
251 {
252 return $this->methods;
253 }
254
255 /**
256 * Sets the HTTP methods (e.g. 'POST') this route is restricted to.
257 * So an empty array means that any method is allowed.
258 *
259 * This method implements a fluent interface.
260 *
261 * @param string|array $methods The method or an array of methods
262 *
263 * @return Route The current Route instance
264 */
265 public function setMethods($methods)
266 {
267 $this->methods = array_map('strtoupper', (array) $methods);
268
269 // this is to keep BC and will be removed in a future version
270 if ($this->methods) {
271 $this->requirements['_method'] = implode('|', $this->methods);
272 } else {
273 unset($this->requirements['_method']);
274 }
275
276 $this->compiled = null;
277
278 return $this;
279 }
280
281 /**
282 * Returns the options.
283 *
284 * @return array The options
285 */
286 public function getOptions()
287 {
288 return $this->options;
289 }
290
291 /**
292 * Sets the options.
293 *
294 * This method implements a fluent interface.
295 *
296 * @param array $options The options
297 *
298 * @return Route The current Route instance
299 */
300 public function setOptions(array $options)
301 {
302 $this->options = array(
303 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
304 );
305
306 return $this->addOptions($options);
307 }
308
309 /**
310 * Adds options.
311 *
312 * This method implements a fluent interface.
313 *
314 * @param array $options The options
315 *
316 * @return Route The current Route instance
317 */
318 public function addOptions(array $options)
319 {
320 foreach ($options as $name => $option) {
321 $this->options[$name] = $option;
322 }
323 $this->compiled = null;
324
325 return $this;
326 }
327
328 /**
329 * Sets an option value.
330 *
331 * This method implements a fluent interface.
332 *
333 * @param string $name An option name
334 * @param mixed $value The option value
335 *
336 * @return Route The current Route instance
337 *
338 * @api
339 */
340 public function setOption($name, $value)
341 {
342 $this->options[$name] = $value;
343 $this->compiled = null;
344
345 return $this;
346 }
347
348 /**
349 * Get an option value.
350 *
351 * @param string $name An option name
352 *
353 * @return mixed The option value or null when not given
354 */
355 public function getOption($name)
356 {
357 return isset($this->options[$name]) ? $this->options[$name] : null;
358 }
359
360 /**
361 * Checks if an option has been set
362 *
363 * @param string $name An option name
364 *
365 * @return Boolean true if the option is set, false otherwise
366 */
367 public function hasOption($name)
368 {
369 return array_key_exists($name, $this->options);
370 }
371
372 /**
373 * Returns the defaults.
374 *
375 * @return array The defaults
376 */
377 public function getDefaults()
378 {
379 return $this->defaults;
380 }
381
382 /**
383 * Sets the defaults.
384 *
385 * This method implements a fluent interface.
386 *
387 * @param array $defaults The defaults
388 *
389 * @return Route The current Route instance
390 */
391 public function setDefaults(array $defaults)
392 {
393 $this->defaults = array();
394
395 return $this->addDefaults($defaults);
396 }
397
398 /**
399 * Adds defaults.
400 *
401 * This method implements a fluent interface.
402 *
403 * @param array $defaults The defaults
404 *
405 * @return Route The current Route instance
406 */
407 public function addDefaults(array $defaults)
408 {
409 foreach ($defaults as $name => $default) {
410 $this->defaults[$name] = $default;
411 }
412 $this->compiled = null;
413
414 return $this;
415 }
416
417 /**
418 * Gets a default value.
419 *
420 * @param string $name A variable name
421 *
422 * @return mixed The default value or null when not given
423 */
424 public function getDefault($name)
425 {
426 return isset($this->defaults[$name]) ? $this->defaults[$name] : null;
427 }
428
429 /**
430 * Checks if a default value is set for the given variable.
431 *
432 * @param string $name A variable name
433 *
434 * @return Boolean true if the default value is set, false otherwise
435 */
436 public function hasDefault($name)
437 {
438 return array_key_exists($name, $this->defaults);
439 }
440
441 /**
442 * Sets a default value.
443 *
444 * @param string $name A variable name
445 * @param mixed $default The default value
446 *
447 * @return Route The current Route instance
448 *
449 * @api
450 */
451 public function setDefault($name, $default)
452 {
453 $this->defaults[$name] = $default;
454 $this->compiled = null;
455
456 return $this;
457 }
458
459 /**
460 * Returns the requirements.
461 *
462 * @return array The requirements
463 */
464 public function getRequirements()
465 {
466 return $this->requirements;
467 }
468
469 /**
470 * Sets the requirements.
471 *
472 * This method implements a fluent interface.
473 *
474 * @param array $requirements The requirements
475 *
476 * @return Route The current Route instance
477 */
478 public function setRequirements(array $requirements)
479 {
480 $this->requirements = array();
481
482 return $this->addRequirements($requirements);
483 }
484
485 /**
486 * Adds requirements.
487 *
488 * This method implements a fluent interface.
489 *
490 * @param array $requirements The requirements
491 *
492 * @return Route The current Route instance
493 */
494 public function addRequirements(array $requirements)
495 {
496 foreach ($requirements as $key => $regex) {
497 $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
498 }
499 $this->compiled = null;
500
501 return $this;
502 }
503
504 /**
505 * Returns the requirement for the given key.
506 *
507 * @param string $key The key
508 *
509 * @return string|null The regex or null when not given
510 */
511 public function getRequirement($key)
512 {
513 return isset($this->requirements[$key]) ? $this->requirements[$key] : null;
514 }
515
516 /**
517 * Checks if a requirement is set for the given key.
518 *
519 * @param string $key A variable name
520 *
521 * @return Boolean true if a requirement is specified, false otherwise
522 */
523 public function hasRequirement($key)
524 {
525 return array_key_exists($key, $this->requirements);
526 }
527
528 /**
529 * Sets a requirement for the given key.
530 *
531 * @param string $key The key
532 * @param string $regex The regex
533 *
534 * @return Route The current Route instance
535 *
536 * @api
537 */
538 public function setRequirement($key, $regex)
539 {
540 $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
541 $this->compiled = null;
542
543 return $this;
544 }
545
546 /**
547 * Compiles the route.
548 *
549 * @return CompiledRoute A CompiledRoute instance
550 *
551 * @throws \LogicException If the Route cannot be compiled because the
552 * path or host pattern is invalid
553 *
554 * @see RouteCompiler which is responsible for the compilation process
555 */
556 public function compile()
557 {
558 if (null !== $this->compiled) {
559 return $this->compiled;
560 }
561
562 $class = $this->getOption('compiler_class');
563
564 return $this->compiled = $class::compile($this);
565 }
566
567 private function sanitizeRequirement($key, $regex)
568 {
569 if (!is_string($regex)) {
570 throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" must be a string.', $key));
571 }
572
573 if ('' !== $regex && '^' === $regex[0]) {
574 $regex = (string) substr($regex, 1); // returns false for a single character
575 }
576
577 if ('$' === substr($regex, -1)) {
578 $regex = substr($regex, 0, -1);
579 }
580
581 if ('' === $regex) {
582 throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key));
583 }
584
585 // this is to keep BC and will be removed in a future version
586 if ('_scheme' === $key) {
587 $this->setSchemes(explode('|', $regex));
588 } elseif ('_method' === $key) {
589 $this->setMethods(explode('|', $regex));
590 }
591
592 return $regex;
593 }
594}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RouteCollection.php b/vendor/symfony/routing/Symfony/Component/Routing/RouteCollection.php
new file mode 100644
index 00000000..499fe0f0
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RouteCollection.php
@@ -0,0 +1,271 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing;
13
14use Symfony\Component\Config\Resource\ResourceInterface;
15
16/**
17 * A RouteCollection represents a set of Route instances.
18 *
19 * When adding a route at the end of the collection, an existing route
20 * with the same name is removed first. So there can only be one route
21 * with a given name.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 * @author Tobias Schultze <http://tobion.de>
25 *
26 * @api
27 */
28class RouteCollection implements \IteratorAggregate, \Countable
29{
30 /**
31 * @var Route[]
32 */
33 private $routes = array();
34
35 /**
36 * @var array
37 */
38 private $resources = array();
39
40 public function __clone()
41 {
42 foreach ($this->routes as $name => $route) {
43 $this->routes[$name] = clone $route;
44 }
45 }
46
47 /**
48 * Gets the current RouteCollection as an Iterator that includes all routes.
49 *
50 * It implements \IteratorAggregate.
51 *
52 * @see all()
53 *
54 * @return \ArrayIterator An \ArrayIterator object for iterating over routes
55 */
56 public function getIterator()
57 {
58 return new \ArrayIterator($this->routes);
59 }
60
61 /**
62 * Gets the number of Routes in this collection.
63 *
64 * @return int The number of routes
65 */
66 public function count()
67 {
68 return count($this->routes);
69 }
70
71 /**
72 * Adds a route.
73 *
74 * @param string $name The route name
75 * @param Route $route A Route instance
76 *
77 * @api
78 */
79 public function add($name, Route $route)
80 {
81 unset($this->routes[$name]);
82
83 $this->routes[$name] = $route;
84 }
85
86 /**
87 * Returns all routes in this collection.
88 *
89 * @return Route[] An array of routes
90 */
91 public function all()
92 {
93 return $this->routes;
94 }
95
96 /**
97 * Gets a route by name.
98 *
99 * @param string $name The route name
100 *
101 * @return Route|null A Route instance or null when not found
102 */
103 public function get($name)
104 {
105 return isset($this->routes[$name]) ? $this->routes[$name] : null;
106 }
107
108 /**
109 * Removes a route or an array of routes by name from the collection
110 *
111 * @param string|array $name The route name or an array of route names
112 */
113 public function remove($name)
114 {
115 foreach ((array) $name as $n) {
116 unset($this->routes[$n]);
117 }
118 }
119
120 /**
121 * Adds a route collection at the end of the current set by appending all
122 * routes of the added collection.
123 *
124 * @param RouteCollection $collection A RouteCollection instance
125 *
126 * @api
127 */
128 public function addCollection(RouteCollection $collection)
129 {
130 // we need to remove all routes with the same names first because just replacing them
131 // would not place the new route at the end of the merged array
132 foreach ($collection->all() as $name => $route) {
133 unset($this->routes[$name]);
134 $this->routes[$name] = $route;
135 }
136
137 $this->resources = array_merge($this->resources, $collection->getResources());
138 }
139
140 /**
141 * Adds a prefix to the path of all child routes.
142 *
143 * @param string $prefix An optional prefix to add before each pattern of the route collection
144 * @param array $defaults An array of default values
145 * @param array $requirements An array of requirements
146 *
147 * @api
148 */
149 public function addPrefix($prefix, array $defaults = array(), array $requirements = array())
150 {
151 $prefix = trim(trim($prefix), '/');
152
153 if ('' === $prefix) {
154 return;
155 }
156
157 foreach ($this->routes as $route) {
158 $route->setPath('/'.$prefix.$route->getPath());
159 $route->addDefaults($defaults);
160 $route->addRequirements($requirements);
161 }
162 }
163
164 /**
165 * Sets the host pattern on all routes.
166 *
167 * @param string $pattern The pattern
168 * @param array $defaults An array of default values
169 * @param array $requirements An array of requirements
170 */
171 public function setHost($pattern, array $defaults = array(), array $requirements = array())
172 {
173 foreach ($this->routes as $route) {
174 $route->setHost($pattern);
175 $route->addDefaults($defaults);
176 $route->addRequirements($requirements);
177 }
178 }
179
180 /**
181 * Adds defaults to all routes.
182 *
183 * An existing default value under the same name in a route will be overridden.
184 *
185 * @param array $defaults An array of default values
186 */
187 public function addDefaults(array $defaults)
188 {
189 if ($defaults) {
190 foreach ($this->routes as $route) {
191 $route->addDefaults($defaults);
192 }
193 }
194 }
195
196 /**
197 * Adds requirements to all routes.
198 *
199 * An existing requirement under the same name in a route will be overridden.
200 *
201 * @param array $requirements An array of requirements
202 */
203 public function addRequirements(array $requirements)
204 {
205 if ($requirements) {
206 foreach ($this->routes as $route) {
207 $route->addRequirements($requirements);
208 }
209 }
210 }
211
212 /**
213 * Adds options to all routes.
214 *
215 * An existing option value under the same name in a route will be overridden.
216 *
217 * @param array $options An array of options
218 */
219 public function addOptions(array $options)
220 {
221 if ($options) {
222 foreach ($this->routes as $route) {
223 $route->addOptions($options);
224 }
225 }
226 }
227
228 /**
229 * Sets the schemes (e.g. 'https') all child routes are restricted to.
230 *
231 * @param string|array $schemes The scheme or an array of schemes
232 */
233 public function setSchemes($schemes)
234 {
235 foreach ($this->routes as $route) {
236 $route->setSchemes($schemes);
237 }
238 }
239
240 /**
241 * Sets the HTTP methods (e.g. 'POST') all child routes are restricted to.
242 *
243 * @param string|array $methods The method or an array of methods
244 */
245 public function setMethods($methods)
246 {
247 foreach ($this->routes as $route) {
248 $route->setMethods($methods);
249 }
250 }
251
252 /**
253 * Returns an array of resources loaded to build this collection.
254 *
255 * @return ResourceInterface[] An array of resources
256 */
257 public function getResources()
258 {
259 return array_unique($this->resources);
260 }
261
262 /**
263 * Adds a resource for this collection.
264 *
265 * @param ResourceInterface $resource A resource instance
266 */
267 public function addResource(ResourceInterface $resource)
268 {
269 $this->resources[] = $resource;
270 }
271}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RouteCompiler.php b/vendor/symfony/routing/Symfony/Component/Routing/RouteCompiler.php
new file mode 100644
index 00000000..7ced4b3a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RouteCompiler.php
@@ -0,0 +1,233 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing;
13
14/**
15 * RouteCompiler compiles Route instances to CompiledRoute instances.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @author Tobias Schultze <http://tobion.de>
19 */
20class RouteCompiler implements RouteCompilerInterface
21{
22 const REGEX_DELIMITER = '#';
23
24 /**
25 * This string defines the characters that are automatically considered separators in front of
26 * optional placeholders (with default and no static text following). Such a single separator
27 * can be left out together with the optional placeholder from matching and generating URLs.
28 */
29 const SEPARATORS = '/,;.:-_~+*=@|';
30
31 /**
32 * {@inheritDoc}
33 *
34 * @throws \LogicException If a variable is referenced more than once
35 * @throws \DomainException If a variable name is numeric because PHP raises an error for such
36 * subpatterns in PCRE and thus would break matching, e.g. "(?P<123>.+)".
37 */
38 public static function compile(Route $route)
39 {
40 $staticPrefix = null;
41 $hostVariables = array();
42 $pathVariables = array();
43 $variables = array();
44 $tokens = array();
45 $regex = null;
46 $hostRegex = null;
47 $hostTokens = array();
48
49 if ('' !== $host = $route->getHost()) {
50 $result = self::compilePattern($route, $host, true);
51
52 $hostVariables = $result['variables'];
53 $variables = array_merge($variables, $hostVariables);
54
55 $hostTokens = $result['tokens'];
56 $hostRegex = $result['regex'];
57 }
58
59 $path = $route->getPath();
60
61 $result = self::compilePattern($route, $path, false);
62
63 $staticPrefix = $result['staticPrefix'];
64
65 $pathVariables = $result['variables'];
66 $variables = array_merge($variables, $pathVariables);
67
68 $tokens = $result['tokens'];
69 $regex = $result['regex'];
70
71 return new CompiledRoute(
72 $staticPrefix,
73 $regex,
74 $tokens,
75 $pathVariables,
76 $hostRegex,
77 $hostTokens,
78 $hostVariables,
79 array_unique($variables)
80 );
81 }
82
83 private static function compilePattern(Route $route, $pattern, $isHost)
84 {
85 $tokens = array();
86 $variables = array();
87 $matches = array();
88 $pos = 0;
89 $defaultSeparator = $isHost ? '.' : '/';
90
91 // Match all variables enclosed in "{}" and iterate over them. But we only want to match the innermost variable
92 // in case of nested "{}", e.g. {foo{bar}}. This in ensured because \w does not match "{" or "}" itself.
93 preg_match_all('#\{\w+\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
94 foreach ($matches as $match) {
95 $varName = substr($match[0][0], 1, -1);
96 // get all static text preceding the current variable
97 $precedingText = substr($pattern, $pos, $match[0][1] - $pos);
98 $pos = $match[0][1] + strlen($match[0][0]);
99 $precedingChar = strlen($precedingText) > 0 ? substr($precedingText, -1) : '';
100 $isSeparator = '' !== $precedingChar && false !== strpos(static::SEPARATORS, $precedingChar);
101
102 if (is_numeric($varName)) {
103 throw new \DomainException(sprintf('Variable name "%s" cannot be numeric in route pattern "%s". Please use a different name.', $varName, $pattern));
104 }
105 if (in_array($varName, $variables)) {
106 throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName));
107 }
108
109 if ($isSeparator && strlen($precedingText) > 1) {
110 $tokens[] = array('text', substr($precedingText, 0, -1));
111 } elseif (!$isSeparator && strlen($precedingText) > 0) {
112 $tokens[] = array('text', $precedingText);
113 }
114
115 $regexp = $route->getRequirement($varName);
116 if (null === $regexp) {
117 $followingPattern = (string) substr($pattern, $pos);
118 // Find the next static character after the variable that functions as a separator. By default, this separator and '/'
119 // are disallowed for the variable. This default requirement makes sure that optional variables can be matched at all
120 // and that the generating-matching-combination of URLs unambiguous, i.e. the params used for generating the URL are
121 // the same that will be matched. Example: new Route('/{page}.{_format}', array('_format' => 'html'))
122 // If {page} would also match the separating dot, {_format} would never match as {page} will eagerly consume everything.
123 // Also even if {_format} was not optional the requirement prevents that {page} matches something that was originally
124 // part of {_format} when generating the URL, e.g. _format = 'mobile.html'.
125 $nextSeparator = self::findNextSeparator($followingPattern);
126 $regexp = sprintf(
127 '[^%s%s]+',
128 preg_quote($defaultSeparator, self::REGEX_DELIMITER),
129 $defaultSeparator !== $nextSeparator && '' !== $nextSeparator ? preg_quote($nextSeparator, self::REGEX_DELIMITER) : ''
130 );
131 if (('' !== $nextSeparator && !preg_match('#^\{\w+\}#', $followingPattern)) || '' === $followingPattern) {
132 // When we have a separator, which is disallowed for the variable, we can optimize the regex with a possessive
133 // quantifier. This prevents useless backtracking of PCRE and improves performance by 20% for matching those patterns.
134 // Given the above example, there is no point in backtracking into {page} (that forbids the dot) when a dot must follow
135 // after it. This optimization cannot be applied when the next char is no real separator or when the next variable is
136 // directly adjacent, e.g. '/{x}{y}'.
137 $regexp .= '+';
138 }
139 }
140
141 $tokens[] = array('variable', $isSeparator ? $precedingChar : '', $regexp, $varName);
142 $variables[] = $varName;
143 }
144
145 if ($pos < strlen($pattern)) {
146 $tokens[] = array('text', substr($pattern, $pos));
147 }
148
149 // find the first optional token
150 $firstOptional = PHP_INT_MAX;
151 if (!$isHost) {
152 for ($i = count($tokens) - 1; $i >= 0; $i--) {
153 $token = $tokens[$i];
154 if ('variable' === $token[0] && $route->hasDefault($token[3])) {
155 $firstOptional = $i;
156 } else {
157 break;
158 }
159 }
160 }
161
162 // compute the matching regexp
163 $regexp = '';
164 for ($i = 0, $nbToken = count($tokens); $i < $nbToken; $i++) {
165 $regexp .= self::computeRegexp($tokens, $i, $firstOptional);
166 }
167
168 return array(
169 'staticPrefix' => 'text' === $tokens[0][0] ? $tokens[0][1] : '',
170 'regex' => self::REGEX_DELIMITER.'^'.$regexp.'$'.self::REGEX_DELIMITER.'s',
171 'tokens' => array_reverse($tokens),
172 'variables' => $variables,
173 );
174 }
175
176 /**
177 * Returns the next static character in the Route pattern that will serve as a separator.
178 *
179 * @param string $pattern The route pattern
180 *
181 * @return string The next static character that functions as separator (or empty string when none available)
182 */
183 private static function findNextSeparator($pattern)
184 {
185 if ('' == $pattern) {
186 // return empty string if pattern is empty or false (false which can be returned by substr)
187 return '';
188 }
189 // first remove all placeholders from the pattern so we can find the next real static character
190 $pattern = preg_replace('#\{\w+\}#', '', $pattern);
191
192 return isset($pattern[0]) && false !== strpos(static::SEPARATORS, $pattern[0]) ? $pattern[0] : '';
193 }
194
195 /**
196 * Computes the regexp used to match a specific token. It can be static text or a subpattern.
197 *
198 * @param array $tokens The route tokens
199 * @param integer $index The index of the current token
200 * @param integer $firstOptional The index of the first optional token
201 *
202 * @return string The regexp pattern for a single token
203 */
204 private static function computeRegexp(array $tokens, $index, $firstOptional)
205 {
206 $token = $tokens[$index];
207 if ('text' === $token[0]) {
208 // Text tokens
209 return preg_quote($token[1], self::REGEX_DELIMITER);
210 } else {
211 // Variable tokens
212 if (0 === $index && 0 === $firstOptional) {
213 // When the only token is an optional variable token, the separator is required
214 return sprintf('%s(?P<%s>%s)?', preg_quote($token[1], self::REGEX_DELIMITER), $token[3], $token[2]);
215 } else {
216 $regexp = sprintf('%s(?P<%s>%s)', preg_quote($token[1], self::REGEX_DELIMITER), $token[3], $token[2]);
217 if ($index >= $firstOptional) {
218 // Enclose each optional token in a subpattern to make it optional.
219 // "?:" means it is non-capturing, i.e. the portion of the subject string that
220 // matched the optional subpattern is not passed back.
221 $regexp = "(?:$regexp";
222 $nbTokens = count($tokens);
223 if ($nbTokens - 1 == $index) {
224 // Close the optional subpatterns
225 $regexp .= str_repeat(")?", $nbTokens - $firstOptional - (0 === $firstOptional ? 1 : 0));
226 }
227 }
228
229 return $regexp;
230 }
231 }
232 }
233}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php
new file mode 100644
index 00000000..e6f8ee6d
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing;
13
14/**
15 * RouteCompilerInterface is the interface that all RouteCompiler classes must implement.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19interface RouteCompilerInterface
20{
21 /**
22 * Compiles the current route instance.
23 *
24 * @param Route $route A Route instance
25 *
26 * @return CompiledRoute A CompiledRoute instance
27 *
28 * @throws \LogicException If the Route cannot be compiled because the
29 * path or host pattern is invalid
30 */
31 public static function compile(Route $route);
32}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Router.php b/vendor/symfony/routing/Symfony/Component/Routing/Router.php
new file mode 100644
index 00000000..d1e28979
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Router.php
@@ -0,0 +1,289 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing;
13
14use Symfony\Component\Config\Loader\LoaderInterface;
15use Symfony\Component\Config\ConfigCache;
16use Psr\Log\LoggerInterface;
17use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface;
18use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
19use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
20
21/**
22 * The Router class is an example of the integration of all pieces of the
23 * routing system for easier use.
24 *
25 * @author Fabien Potencier <fabien@symfony.com>
26 */
27class Router implements RouterInterface
28{
29 /**
30 * @var UrlMatcherInterface|null
31 */
32 protected $matcher;
33
34 /**
35 * @var UrlGeneratorInterface|null
36 */
37 protected $generator;
38
39 /**
40 * @var RequestContext
41 */
42 protected $context;
43
44 /**
45 * @var LoaderInterface
46 */
47 protected $loader;
48
49 /**
50 * @var RouteCollection|null
51 */
52 protected $collection;
53
54 /**
55 * @var mixed
56 */
57 protected $resource;
58
59 /**
60 * @var array
61 */
62 protected $options = array();
63
64 /**
65 * @var LoggerInterface|null
66 */
67 protected $logger;
68
69 /**
70 * Constructor.
71 *
72 * @param LoaderInterface $loader A LoaderInterface instance
73 * @param mixed $resource The main resource to load
74 * @param array $options An array of options
75 * @param RequestContext $context The context
76 * @param LoggerInterface $logger A logger instance
77 */
78 public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null, LoggerInterface $logger = null)
79 {
80 $this->loader = $loader;
81 $this->resource = $resource;
82 $this->logger = $logger;
83 $this->context = null === $context ? new RequestContext() : $context;
84 $this->setOptions($options);
85 }
86
87 /**
88 * Sets options.
89 *
90 * Available options:
91 *
92 * * cache_dir: The cache directory (or null to disable caching)
93 * * debug: Whether to enable debugging or not (false by default)
94 * * resource_type: Type hint for the main resource (optional)
95 *
96 * @param array $options An array of options
97 *
98 * @throws \InvalidArgumentException When unsupported option is provided
99 */
100 public function setOptions(array $options)
101 {
102 $this->options = array(
103 'cache_dir' => null,
104 'debug' => false,
105 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
106 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
107 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper',
108 'generator_cache_class' => 'ProjectUrlGenerator',
109 'matcher_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
110 'matcher_base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
111 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper',
112 'matcher_cache_class' => 'ProjectUrlMatcher',
113 'resource_type' => null,
114 'strict_requirements' => true,
115 );
116
117 // check option names and live merge, if errors are encountered Exception will be thrown
118 $invalid = array();
119 foreach ($options as $key => $value) {
120 if (array_key_exists($key, $this->options)) {
121 $this->options[$key] = $value;
122 } else {
123 $invalid[] = $key;
124 }
125 }
126
127 if ($invalid) {
128 throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid)));
129 }
130 }
131
132 /**
133 * Sets an option.
134 *
135 * @param string $key The key
136 * @param mixed $value The value
137 *
138 * @throws \InvalidArgumentException
139 */
140 public function setOption($key, $value)
141 {
142 if (!array_key_exists($key, $this->options)) {
143 throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
144 }
145
146 $this->options[$key] = $value;
147 }
148
149 /**
150 * Gets an option value.
151 *
152 * @param string $key The key
153 *
154 * @return mixed The value
155 *
156 * @throws \InvalidArgumentException
157 */
158 public function getOption($key)
159 {
160 if (!array_key_exists($key, $this->options)) {
161 throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
162 }
163
164 return $this->options[$key];
165 }
166
167 /**
168 * {@inheritdoc}
169 */
170 public function getRouteCollection()
171 {
172 if (null === $this->collection) {
173 $this->collection = $this->loader->load($this->resource, $this->options['resource_type']);
174 }
175
176 return $this->collection;
177 }
178
179 /**
180 * {@inheritdoc}
181 */
182 public function setContext(RequestContext $context)
183 {
184 $this->context = $context;
185
186 if (null !== $this->matcher) {
187 $this->getMatcher()->setContext($context);
188 }
189 if (null !== $this->generator) {
190 $this->getGenerator()->setContext($context);
191 }
192 }
193
194 /**
195 * {@inheritdoc}
196 */
197 public function getContext()
198 {
199 return $this->context;
200 }
201
202 /**
203 * {@inheritdoc}
204 */
205 public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
206 {
207 return $this->getGenerator()->generate($name, $parameters, $referenceType);
208 }
209
210 /**
211 * {@inheritdoc}
212 */
213 public function match($pathinfo)
214 {
215 return $this->getMatcher()->match($pathinfo);
216 }
217
218 /**
219 * Gets the UrlMatcher instance associated with this Router.
220 *
221 * @return UrlMatcherInterface A UrlMatcherInterface instance
222 */
223 public function getMatcher()
224 {
225 if (null !== $this->matcher) {
226 return $this->matcher;
227 }
228
229 if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) {
230 return $this->matcher = new $this->options['matcher_class']($this->getRouteCollection(), $this->context);
231 }
232
233 $class = $this->options['matcher_cache_class'];
234 $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
235 if (!$cache->isFresh($class)) {
236 $dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection());
237
238 $options = array(
239 'class' => $class,
240 'base_class' => $this->options['matcher_base_class'],
241 );
242
243 $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
244 }
245
246 require_once $cache;
247
248 return $this->matcher = new $class($this->context);
249 }
250
251 /**
252 * Gets the UrlGenerator instance associated with this Router.
253 *
254 * @return UrlGeneratorInterface A UrlGeneratorInterface instance
255 */
256 public function getGenerator()
257 {
258 if (null !== $this->generator) {
259 return $this->generator;
260 }
261
262 if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) {
263 $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->logger);
264 } else {
265 $class = $this->options['generator_cache_class'];
266 $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
267 if (!$cache->isFresh($class)) {
268 $dumper = new $this->options['generator_dumper_class']($this->getRouteCollection());
269
270 $options = array(
271 'class' => $class,
272 'base_class' => $this->options['generator_base_class'],
273 );
274
275 $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
276 }
277
278 require_once $cache;
279
280 $this->generator = new $class($this->context, $this->logger);
281 }
282
283 if ($this->generator instanceof ConfigurableRequirementsInterface) {
284 $this->generator->setStrictRequirements($this->options['strict_requirements']);
285 }
286
287 return $this->generator;
288 }
289}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RouterInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/RouterInterface.php
new file mode 100644
index 00000000..a10ae34e
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RouterInterface.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing;
13
14use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
16
17/**
18 * RouterInterface is the interface that all Router classes must implement.
19 *
20 * This interface is the concatenation of UrlMatcherInterface and UrlGeneratorInterface.
21 *
22 * @author Fabien Potencier <fabien@symfony.com>
23 */
24interface RouterInterface extends UrlMatcherInterface, UrlGeneratorInterface
25{
26 /**
27 * Gets the RouteCollection instance associated with this Router.
28 *
29 * @return RouteCollection A RouteCollection instance
30 */
31 public function getRouteCollection();
32}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Annotation/RouteTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
new file mode 100644
index 00000000..b58869f7
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
@@ -0,0 +1,49 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Annotation;
13
14use Symfony\Component\Routing\Annotation\Route;
15
16class RouteTest extends \PHPUnit_Framework_TestCase
17{
18 /**
19 * @expectedException \BadMethodCallException
20 */
21 public function testInvalidRouteParameter()
22 {
23 $route = new Route(array('foo' => 'bar'));
24 }
25
26 /**
27 * @dataProvider getValidParameters
28 */
29 public function testRouteParameters($parameter, $value, $getter)
30 {
31 $route = new Route(array($parameter => $value));
32 $this->assertEquals($route->$getter(), $value);
33 }
34
35 public function getValidParameters()
36 {
37 return array(
38 array('value', '/Blog', 'getPattern'),
39 array('value', '/Blog', 'getPath'),
40 array('requirements', array('_method' => 'GET'), 'getRequirements'),
41 array('options', array('compiler_class' => 'RouteCompiler'), 'getOptions'),
42 array('name', 'blog_index', 'getName'),
43 array('defaults', array('_controller' => 'MyBlogBundle:Blog:index'), 'getDefaults'),
44 array('schemes', array('https'), 'getSchemes'),
45 array('methods', array('GET', 'POST'), 'getMethods'),
46 array('host', array('{locale}.example.com'), 'getHost')
47 );
48 }
49}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/CompiledRouteTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/CompiledRouteTest.php
new file mode 100644
index 00000000..215ebb70
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/CompiledRouteTest.php
@@ -0,0 +1,26 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\CompiledRoute;
15
16class CompiledRouteTest extends \PHPUnit_Framework_TestCase
17{
18 public function testAccessors()
19 {
20 $compiled = new CompiledRoute('prefix', 'regex', array('tokens'), array(), array(), array(), array(), array('variables'));
21 $this->assertEquals('prefix', $compiled->getStaticPrefix(), '__construct() takes a static prefix as its second argument');
22 $this->assertEquals('regex', $compiled->getRegex(), '__construct() takes a regexp as its third argument');
23 $this->assertEquals(array('tokens'), $compiled->getTokens(), '__construct() takes an array of tokens as its fourth argument');
24 $this->assertEquals(array('variables'), $compiled->getVariables(), '__construct() takes an array of variables as its ninth argument');
25 }
26}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php
new file mode 100644
index 00000000..56bcab2a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php
@@ -0,0 +1,16 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
13
14abstract class AbstractClass
15{
16}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/BarClass.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/BarClass.php
new file mode 100644
index 00000000..a3882773
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/BarClass.php
@@ -0,0 +1,19 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
13
14class BarClass
15{
16 public function routeAction($arg1, $arg2 = 'defaultValue2', $arg3 = 'defaultValue3')
17 {
18 }
19}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooClass.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooClass.php
new file mode 100644
index 00000000..320dc350
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooClass.php
@@ -0,0 +1,16 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
13
14class FooClass
15{
16}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/CustomXmlFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/CustomXmlFileLoader.php
new file mode 100644
index 00000000..12a5bedb
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/CustomXmlFileLoader.php
@@ -0,0 +1,26 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Fixtures;
13
14use Symfony\Component\Routing\Loader\XmlFileLoader;
15use Symfony\Component\Config\Util\XmlUtils;
16
17/**
18 * XmlFileLoader with schema validation turned off
19 */
20class CustomXmlFileLoader extends XmlFileLoader
21{
22 protected function loadFile($file)
23 {
24 return XmlUtils::loadFile($file, function() { return true; });
25 }
26}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/RedirectableUrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/RedirectableUrlMatcher.php
new file mode 100644
index 00000000..e95c1f26
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/RedirectableUrlMatcher.php
@@ -0,0 +1,30 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Fixtures;
13
14use Symfony\Component\Routing\Matcher\UrlMatcher;
15use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface;
16
17/**
18 * @author Fabien Potencier <fabien@symfony.com>
19 */
20class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
21{
22 public function redirect($path, $route, $scheme = null)
23 {
24 return array(
25 '_controller' => 'Some controller reference...',
26 'path' => $path,
27 'scheme' => $scheme,
28 );
29 }
30}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/annotated.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/annotated.php
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/annotated.php
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache
new file mode 100644
index 00000000..26a561cc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache
@@ -0,0 +1,163 @@
1# skip "real" requests
2RewriteCond %{REQUEST_FILENAME} -f
3RewriteRule .* - [QSA,L]
4
5# foo
6RewriteCond %{REQUEST_URI} ^/foo/(baz|symfony)$
7RewriteRule .* app.php [QSA,L,E=_ROUTING_route:foo,E=_ROUTING_param_bar:%1,E=_ROUTING_default_def:test]
8
9# foobar
10RewriteCond %{REQUEST_URI} ^/foo(?:/([^/]++))?$
11RewriteRule .* app.php [QSA,L,E=_ROUTING_route:foobar,E=_ROUTING_param_bar:%1,E=_ROUTING_default_bar:toto]
12
13# bar
14RewriteCond %{REQUEST_URI} ^/bar/([^/]++)$
15RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC]
16RewriteRule .* - [S=1,E=_ROUTING_allow_GET:1,E=_ROUTING_allow_HEAD:1]
17RewriteCond %{REQUEST_URI} ^/bar/([^/]++)$
18RewriteRule .* app.php [QSA,L,E=_ROUTING_route:bar,E=_ROUTING_param_foo:%1]
19
20# baragain
21RewriteCond %{REQUEST_URI} ^/baragain/([^/]++)$
22RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$ [NC]
23RewriteRule .* - [S=1,E=_ROUTING_allow_GET:1,E=_ROUTING_allow_POST:1,E=_ROUTING_allow_HEAD:1]
24RewriteCond %{REQUEST_URI} ^/baragain/([^/]++)$
25RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baragain,E=_ROUTING_param_foo:%1]
26
27# baz
28RewriteCond %{REQUEST_URI} ^/test/baz$
29RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz]
30
31# baz2
32RewriteCond %{REQUEST_URI} ^/test/baz\.html$
33RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz2]
34
35# baz3
36RewriteCond %{REQUEST_URI} ^/test/baz3$
37RewriteRule .* $0/ [QSA,L,R=301]
38RewriteCond %{REQUEST_URI} ^/test/baz3/$
39RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz3]
40
41# baz4
42RewriteCond %{REQUEST_URI} ^/test/([^/]++)$
43RewriteRule .* $0/ [QSA,L,R=301]
44RewriteCond %{REQUEST_URI} ^/test/([^/]++)/$
45RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz4,E=_ROUTING_param_foo:%1]
46
47# baz5
48RewriteCond %{REQUEST_URI} ^/test/([^/]++)/$
49RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC]
50RewriteRule .* - [S=2,E=_ROUTING_allow_GET:1,E=_ROUTING_allow_HEAD:1]
51RewriteCond %{REQUEST_URI} ^/test/([^/]++)$
52RewriteRule .* $0/ [QSA,L,R=301]
53RewriteCond %{REQUEST_URI} ^/test/([^/]++)/$
54RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz5,E=_ROUTING_param_foo:%1]
55
56# baz5unsafe
57RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]++)/$
58RewriteCond %{REQUEST_METHOD} !^(POST)$ [NC]
59RewriteRule .* - [S=1,E=_ROUTING_allow_POST:1]
60RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]++)/$
61RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz5unsafe,E=_ROUTING_param_foo:%1]
62
63# baz6
64RewriteCond %{REQUEST_URI} ^/test/baz$
65RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz6,E=_ROUTING_default_foo:bar\ baz]
66
67# baz7
68RewriteCond %{REQUEST_URI} ^/te\ st/baz$
69RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz7]
70
71# baz8
72RewriteCond %{REQUEST_URI} ^/te\\\ st/baz$
73RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz8]
74
75# baz9
76RewriteCond %{REQUEST_URI} ^/test/(te\\\ st)$
77RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz9,E=_ROUTING_param_baz:%1]
78
79RewriteCond %{HTTP:Host} ^a\.example\.com$
80RewriteRule .? - [E=__ROUTING_host_1:1]
81
82# route1
83RewriteCond %{ENV:__ROUTING_host_1} =1
84RewriteCond %{REQUEST_URI} ^/route1$
85RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route1]
86
87# route2
88RewriteCond %{ENV:__ROUTING_host_1} =1
89RewriteCond %{REQUEST_URI} ^/c2/route2$
90RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route2]
91
92RewriteCond %{HTTP:Host} ^b\.example\.com$
93RewriteRule .? - [E=__ROUTING_host_2:1]
94
95# route3
96RewriteCond %{ENV:__ROUTING_host_2} =1
97RewriteCond %{REQUEST_URI} ^/c2/route3$
98RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route3]
99
100RewriteCond %{HTTP:Host} ^a\.example\.com$
101RewriteRule .? - [E=__ROUTING_host_3:1]
102
103# route4
104RewriteCond %{ENV:__ROUTING_host_3} =1
105RewriteCond %{REQUEST_URI} ^/route4$
106RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route4]
107
108RewriteCond %{HTTP:Host} ^c\.example\.com$
109RewriteRule .? - [E=__ROUTING_host_4:1]
110
111# route5
112RewriteCond %{ENV:__ROUTING_host_4} =1
113RewriteCond %{REQUEST_URI} ^/route5$
114RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route5]
115
116# route6
117RewriteCond %{REQUEST_URI} ^/route6$
118RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route6]
119
120RewriteCond %{HTTP:Host} ^([^\.]++)\.example\.com$
121RewriteRule .? - [E=__ROUTING_host_5:1,E=__ROUTING_host_5_var1:%1]
122
123# route11
124RewriteCond %{ENV:__ROUTING_host_5} =1
125RewriteCond %{REQUEST_URI} ^/route11$
126RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route11,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1}]
127
128# route12
129RewriteCond %{ENV:__ROUTING_host_5} =1
130RewriteCond %{REQUEST_URI} ^/route12$
131RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route12,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1},E=_ROUTING_default_var1:val]
132
133# route13
134RewriteCond %{ENV:__ROUTING_host_5} =1
135RewriteCond %{REQUEST_URI} ^/route13/([^/]++)$
136RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route13,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1},E=_ROUTING_param_name:%1]
137
138# route14
139RewriteCond %{ENV:__ROUTING_host_5} =1
140RewriteCond %{REQUEST_URI} ^/route14/([^/]++)$
141RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route14,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1},E=_ROUTING_param_name:%1,E=_ROUTING_default_var1:val]
142
143RewriteCond %{HTTP:Host} ^c\.example\.com$
144RewriteRule .? - [E=__ROUTING_host_6:1]
145
146# route15
147RewriteCond %{ENV:__ROUTING_host_6} =1
148RewriteCond %{REQUEST_URI} ^/route15/([^/]++)$
149RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route15,E=_ROUTING_param_name:%1]
150
151# route16
152RewriteCond %{REQUEST_URI} ^/route16/([^/]++)$
153RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route16,E=_ROUTING_param_name:%1,E=_ROUTING_default_var1:val]
154
155# route17
156RewriteCond %{REQUEST_URI} ^/route17$
157RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route17]
158
159# 405 Method Not Allowed
160RewriteCond %{ENV:_ROUTING__allow_GET} =1 [OR]
161RewriteCond %{ENV:_ROUTING__allow_HEAD} =1 [OR]
162RewriteCond %{ENV:_ROUTING__allow_POST} =1
163RewriteRule .* app.php [QSA,L]
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
new file mode 100644
index 00000000..e5f7665c
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
@@ -0,0 +1,310 @@
1<?php
2
3use Symfony\Component\Routing\Exception\MethodNotAllowedException;
4use Symfony\Component\Routing\Exception\ResourceNotFoundException;
5use Symfony\Component\Routing\RequestContext;
6
7/**
8 * ProjectUrlMatcher
9 *
10 * This class has been auto-generated
11 * by the Symfony Routing Component.
12 */
13class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
14{
15 /**
16 * Constructor.
17 */
18 public function __construct(RequestContext $context)
19 {
20 $this->context = $context;
21 }
22
23 public function match($pathinfo)
24 {
25 $allow = array();
26 $pathinfo = rawurldecode($pathinfo);
27
28 // foo
29 if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?P<bar>baz|symfony)$#s', $pathinfo, $matches)) {
30 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo')), array ( 'def' => 'test',));
31 }
32
33 if (0 === strpos($pathinfo, '/bar')) {
34 // bar
35 if (preg_match('#^/bar/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
36 if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
37 $allow = array_merge($allow, array('GET', 'HEAD'));
38 goto not_bar;
39 }
40
41 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar')), array ());
42 }
43 not_bar:
44
45 // barhead
46 if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
47 if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
48 $allow = array_merge($allow, array('GET', 'HEAD'));
49 goto not_barhead;
50 }
51
52 return $this->mergeDefaults(array_replace($matches, array('_route' => 'barhead')), array ());
53 }
54 not_barhead:
55
56 }
57
58 if (0 === strpos($pathinfo, '/test')) {
59 if (0 === strpos($pathinfo, '/test/baz')) {
60 // baz
61 if ($pathinfo === '/test/baz') {
62 return array('_route' => 'baz');
63 }
64
65 // baz2
66 if ($pathinfo === '/test/baz.html') {
67 return array('_route' => 'baz2');
68 }
69
70 // baz3
71 if ($pathinfo === '/test/baz3/') {
72 return array('_route' => 'baz3');
73 }
74
75 }
76
77 // baz4
78 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
79 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz4')), array ());
80 }
81
82 // baz5
83 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
84 if ($this->context->getMethod() != 'POST') {
85 $allow[] = 'POST';
86 goto not_baz5;
87 }
88
89 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz5')), array ());
90 }
91 not_baz5:
92
93 // baz.baz6
94 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
95 if ($this->context->getMethod() != 'PUT') {
96 $allow[] = 'PUT';
97 goto not_bazbaz6;
98 }
99
100 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz.baz6')), array ());
101 }
102 not_bazbaz6:
103
104 }
105
106 // foofoo
107 if ($pathinfo === '/foofoo') {
108 return array ( 'def' => 'test', '_route' => 'foofoo',);
109 }
110
111 // quoter
112 if (preg_match('#^/(?P<quoter>[\']+)$#s', $pathinfo, $matches)) {
113 return $this->mergeDefaults(array_replace($matches, array('_route' => 'quoter')), array ());
114 }
115
116 // space
117 if ($pathinfo === '/spa ce') {
118 return array('_route' => 'space');
119 }
120
121 if (0 === strpos($pathinfo, '/a')) {
122 if (0 === strpos($pathinfo, '/a/b\'b')) {
123 // foo1
124 if (preg_match('#^/a/b\'b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
125 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo1')), array ());
126 }
127
128 // bar1
129 if (preg_match('#^/a/b\'b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
130 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar1')), array ());
131 }
132
133 }
134
135 // overridden
136 if (preg_match('#^/a/(?P<var>.*)$#s', $pathinfo, $matches)) {
137 return $this->mergeDefaults(array_replace($matches, array('_route' => 'overridden')), array ());
138 }
139
140 if (0 === strpos($pathinfo, '/a/b\'b')) {
141 // foo2
142 if (preg_match('#^/a/b\'b/(?P<foo1>[^/]++)$#s', $pathinfo, $matches)) {
143 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo2')), array ());
144 }
145
146 // bar2
147 if (preg_match('#^/a/b\'b/(?P<bar1>[^/]++)$#s', $pathinfo, $matches)) {
148 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar2')), array ());
149 }
150
151 }
152
153 }
154
155 if (0 === strpos($pathinfo, '/multi')) {
156 // helloWorld
157 if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?P<who>[^/]++))?$#s', $pathinfo, $matches)) {
158 return $this->mergeDefaults(array_replace($matches, array('_route' => 'helloWorld')), array ( 'who' => 'World!',));
159 }
160
161 // overridden2
162 if ($pathinfo === '/multi/new') {
163 return array('_route' => 'overridden2');
164 }
165
166 // hey
167 if ($pathinfo === '/multi/hey/') {
168 return array('_route' => 'hey');
169 }
170
171 }
172
173 // foo3
174 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
175 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo3')), array ());
176 }
177
178 // bar3
179 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
180 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar3')), array ());
181 }
182
183 if (0 === strpos($pathinfo, '/aba')) {
184 // ababa
185 if ($pathinfo === '/ababa') {
186 return array('_route' => 'ababa');
187 }
188
189 // foo4
190 if (preg_match('#^/aba/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
191 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo4')), array ());
192 }
193
194 }
195
196 $host = $this->context->getHost();
197
198 if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
199 // route1
200 if ($pathinfo === '/route1') {
201 return array('_route' => 'route1');
202 }
203
204 // route2
205 if ($pathinfo === '/c2/route2') {
206 return array('_route' => 'route2');
207 }
208
209 }
210
211 if (preg_match('#^b\\.example\\.com$#s', $host, $hostMatches)) {
212 // route3
213 if ($pathinfo === '/c2/route3') {
214 return array('_route' => 'route3');
215 }
216
217 }
218
219 if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
220 // route4
221 if ($pathinfo === '/route4') {
222 return array('_route' => 'route4');
223 }
224
225 }
226
227 if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
228 // route5
229 if ($pathinfo === '/route5') {
230 return array('_route' => 'route5');
231 }
232
233 }
234
235 // route6
236 if ($pathinfo === '/route6') {
237 return array('_route' => 'route6');
238 }
239
240 if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#s', $host, $hostMatches)) {
241 if (0 === strpos($pathinfo, '/route1')) {
242 // route11
243 if ($pathinfo === '/route11') {
244 return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route11')), array ());
245 }
246
247 // route12
248 if ($pathinfo === '/route12') {
249 return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route12')), array ( 'var1' => 'val',));
250 }
251
252 // route13
253 if (0 === strpos($pathinfo, '/route13') && preg_match('#^/route13/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
254 return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route13')), array ());
255 }
256
257 // route14
258 if (0 === strpos($pathinfo, '/route14') && preg_match('#^/route14/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
259 return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route14')), array ( 'var1' => 'val',));
260 }
261
262 }
263
264 }
265
266 if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
267 // route15
268 if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
269 return $this->mergeDefaults(array_replace($matches, array('_route' => 'route15')), array ());
270 }
271
272 }
273
274 if (0 === strpos($pathinfo, '/route1')) {
275 // route16
276 if (0 === strpos($pathinfo, '/route16') && preg_match('#^/route16/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
277 return $this->mergeDefaults(array_replace($matches, array('_route' => 'route16')), array ( 'var1' => 'val',));
278 }
279
280 // route17
281 if ($pathinfo === '/route17') {
282 return array('_route' => 'route17');
283 }
284
285 }
286
287 if (0 === strpos($pathinfo, '/a')) {
288 // a
289 if ($pathinfo === '/a/a...') {
290 return array('_route' => 'a');
291 }
292
293 if (0 === strpos($pathinfo, '/a/b')) {
294 // b
295 if (preg_match('#^/a/b/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
296 return $this->mergeDefaults(array_replace($matches, array('_route' => 'b')), array ());
297 }
298
299 // c
300 if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
301 return $this->mergeDefaults(array_replace($matches, array('_route' => 'c')), array ());
302 }
303
304 }
305
306 }
307
308 throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
309 }
310}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.apache b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.apache
new file mode 100644
index 00000000..309f2ff0
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.apache
@@ -0,0 +1,7 @@
1# skip "real" requests
2RewriteCond %{REQUEST_FILENAME} -f
3RewriteRule .* - [QSA,L]
4
5# foo
6RewriteCond %{REQUEST_URI} ^/foo$
7RewriteRule .* ap\ p_d\ ev.php [QSA,L,E=_ROUTING_route:foo]
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
new file mode 100644
index 00000000..ad157909
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
@@ -0,0 +1,340 @@
1<?php
2
3use Symfony\Component\Routing\Exception\MethodNotAllowedException;
4use Symfony\Component\Routing\Exception\ResourceNotFoundException;
5use Symfony\Component\Routing\RequestContext;
6
7/**
8 * ProjectUrlMatcher
9 *
10 * This class has been auto-generated
11 * by the Symfony Routing Component.
12 */
13class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher
14{
15 /**
16 * Constructor.
17 */
18 public function __construct(RequestContext $context)
19 {
20 $this->context = $context;
21 }
22
23 public function match($pathinfo)
24 {
25 $allow = array();
26 $pathinfo = rawurldecode($pathinfo);
27
28 // foo
29 if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?P<bar>baz|symfony)$#s', $pathinfo, $matches)) {
30 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo')), array ( 'def' => 'test',));
31 }
32
33 if (0 === strpos($pathinfo, '/bar')) {
34 // bar
35 if (preg_match('#^/bar/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
36 if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
37 $allow = array_merge($allow, array('GET', 'HEAD'));
38 goto not_bar;
39 }
40
41 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar')), array ());
42 }
43 not_bar:
44
45 // barhead
46 if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
47 if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
48 $allow = array_merge($allow, array('GET', 'HEAD'));
49 goto not_barhead;
50 }
51
52 return $this->mergeDefaults(array_replace($matches, array('_route' => 'barhead')), array ());
53 }
54 not_barhead:
55
56 }
57
58 if (0 === strpos($pathinfo, '/test')) {
59 if (0 === strpos($pathinfo, '/test/baz')) {
60 // baz
61 if ($pathinfo === '/test/baz') {
62 return array('_route' => 'baz');
63 }
64
65 // baz2
66 if ($pathinfo === '/test/baz.html') {
67 return array('_route' => 'baz2');
68 }
69
70 // baz3
71 if (rtrim($pathinfo, '/') === '/test/baz3') {
72 if (substr($pathinfo, -1) !== '/') {
73 return $this->redirect($pathinfo.'/', 'baz3');
74 }
75
76 return array('_route' => 'baz3');
77 }
78
79 }
80
81 // baz4
82 if (preg_match('#^/test/(?P<foo>[^/]++)/?$#s', $pathinfo, $matches)) {
83 if (substr($pathinfo, -1) !== '/') {
84 return $this->redirect($pathinfo.'/', 'baz4');
85 }
86
87 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz4')), array ());
88 }
89
90 // baz5
91 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
92 if ($this->context->getMethod() != 'POST') {
93 $allow[] = 'POST';
94 goto not_baz5;
95 }
96
97 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz5')), array ());
98 }
99 not_baz5:
100
101 // baz.baz6
102 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
103 if ($this->context->getMethod() != 'PUT') {
104 $allow[] = 'PUT';
105 goto not_bazbaz6;
106 }
107
108 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz.baz6')), array ());
109 }
110 not_bazbaz6:
111
112 }
113
114 // foofoo
115 if ($pathinfo === '/foofoo') {
116 return array ( 'def' => 'test', '_route' => 'foofoo',);
117 }
118
119 // quoter
120 if (preg_match('#^/(?P<quoter>[\']+)$#s', $pathinfo, $matches)) {
121 return $this->mergeDefaults(array_replace($matches, array('_route' => 'quoter')), array ());
122 }
123
124 // space
125 if ($pathinfo === '/spa ce') {
126 return array('_route' => 'space');
127 }
128
129 if (0 === strpos($pathinfo, '/a')) {
130 if (0 === strpos($pathinfo, '/a/b\'b')) {
131 // foo1
132 if (preg_match('#^/a/b\'b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
133 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo1')), array ());
134 }
135
136 // bar1
137 if (preg_match('#^/a/b\'b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
138 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar1')), array ());
139 }
140
141 }
142
143 // overridden
144 if (preg_match('#^/a/(?P<var>.*)$#s', $pathinfo, $matches)) {
145 return $this->mergeDefaults(array_replace($matches, array('_route' => 'overridden')), array ());
146 }
147
148 if (0 === strpos($pathinfo, '/a/b\'b')) {
149 // foo2
150 if (preg_match('#^/a/b\'b/(?P<foo1>[^/]++)$#s', $pathinfo, $matches)) {
151 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo2')), array ());
152 }
153
154 // bar2
155 if (preg_match('#^/a/b\'b/(?P<bar1>[^/]++)$#s', $pathinfo, $matches)) {
156 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar2')), array ());
157 }
158
159 }
160
161 }
162
163 if (0 === strpos($pathinfo, '/multi')) {
164 // helloWorld
165 if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?P<who>[^/]++))?$#s', $pathinfo, $matches)) {
166 return $this->mergeDefaults(array_replace($matches, array('_route' => 'helloWorld')), array ( 'who' => 'World!',));
167 }
168
169 // overridden2
170 if ($pathinfo === '/multi/new') {
171 return array('_route' => 'overridden2');
172 }
173
174 // hey
175 if (rtrim($pathinfo, '/') === '/multi/hey') {
176 if (substr($pathinfo, -1) !== '/') {
177 return $this->redirect($pathinfo.'/', 'hey');
178 }
179
180 return array('_route' => 'hey');
181 }
182
183 }
184
185 // foo3
186 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
187 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo3')), array ());
188 }
189
190 // bar3
191 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
192 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar3')), array ());
193 }
194
195 if (0 === strpos($pathinfo, '/aba')) {
196 // ababa
197 if ($pathinfo === '/ababa') {
198 return array('_route' => 'ababa');
199 }
200
201 // foo4
202 if (preg_match('#^/aba/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
203 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo4')), array ());
204 }
205
206 }
207
208 $host = $this->context->getHost();
209
210 if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
211 // route1
212 if ($pathinfo === '/route1') {
213 return array('_route' => 'route1');
214 }
215
216 // route2
217 if ($pathinfo === '/c2/route2') {
218 return array('_route' => 'route2');
219 }
220
221 }
222
223 if (preg_match('#^b\\.example\\.com$#s', $host, $hostMatches)) {
224 // route3
225 if ($pathinfo === '/c2/route3') {
226 return array('_route' => 'route3');
227 }
228
229 }
230
231 if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
232 // route4
233 if ($pathinfo === '/route4') {
234 return array('_route' => 'route4');
235 }
236
237 }
238
239 if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
240 // route5
241 if ($pathinfo === '/route5') {
242 return array('_route' => 'route5');
243 }
244
245 }
246
247 // route6
248 if ($pathinfo === '/route6') {
249 return array('_route' => 'route6');
250 }
251
252 if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#s', $host, $hostMatches)) {
253 if (0 === strpos($pathinfo, '/route1')) {
254 // route11
255 if ($pathinfo === '/route11') {
256 return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route11')), array ());
257 }
258
259 // route12
260 if ($pathinfo === '/route12') {
261 return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route12')), array ( 'var1' => 'val',));
262 }
263
264 // route13
265 if (0 === strpos($pathinfo, '/route13') && preg_match('#^/route13/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
266 return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route13')), array ());
267 }
268
269 // route14
270 if (0 === strpos($pathinfo, '/route14') && preg_match('#^/route14/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
271 return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route14')), array ( 'var1' => 'val',));
272 }
273
274 }
275
276 }
277
278 if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
279 // route15
280 if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
281 return $this->mergeDefaults(array_replace($matches, array('_route' => 'route15')), array ());
282 }
283
284 }
285
286 if (0 === strpos($pathinfo, '/route1')) {
287 // route16
288 if (0 === strpos($pathinfo, '/route16') && preg_match('#^/route16/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
289 return $this->mergeDefaults(array_replace($matches, array('_route' => 'route16')), array ( 'var1' => 'val',));
290 }
291
292 // route17
293 if ($pathinfo === '/route17') {
294 return array('_route' => 'route17');
295 }
296
297 }
298
299 if (0 === strpos($pathinfo, '/a')) {
300 // a
301 if ($pathinfo === '/a/a...') {
302 return array('_route' => 'a');
303 }
304
305 if (0 === strpos($pathinfo, '/a/b')) {
306 // b
307 if (preg_match('#^/a/b/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
308 return $this->mergeDefaults(array_replace($matches, array('_route' => 'b')), array ());
309 }
310
311 // c
312 if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
313 return $this->mergeDefaults(array_replace($matches, array('_route' => 'c')), array ());
314 }
315
316 }
317
318 }
319
320 // secure
321 if ($pathinfo === '/secure') {
322 if ($this->context->getScheme() !== 'https') {
323 return $this->redirect($pathinfo, 'secure', 'https');
324 }
325
326 return array('_route' => 'secure');
327 }
328
329 // nonsecure
330 if ($pathinfo === '/nonsecure') {
331 if ($this->context->getScheme() !== 'http') {
332 return $this->redirect($pathinfo, 'nonsecure', 'http');
333 }
334
335 return array('_route' => 'nonsecure');
336 }
337
338 throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
339 }
340}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php
new file mode 100644
index 00000000..f2f642eb
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php
@@ -0,0 +1,43 @@
1<?php
2
3use Symfony\Component\Routing\Exception\MethodNotAllowedException;
4use Symfony\Component\Routing\Exception\ResourceNotFoundException;
5use Symfony\Component\Routing\RequestContext;
6
7/**
8 * ProjectUrlMatcher
9 *
10 * This class has been auto-generated
11 * by the Symfony Routing Component.
12 */
13class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
14{
15 /**
16 * Constructor.
17 */
18 public function __construct(RequestContext $context)
19 {
20 $this->context = $context;
21 }
22
23 public function match($pathinfo)
24 {
25 $allow = array();
26 $pathinfo = rawurldecode($pathinfo);
27
28 if (0 === strpos($pathinfo, '/rootprefix')) {
29 // static
30 if ($pathinfo === '/rootprefix/test') {
31 return array('_route' => 'static');
32 }
33
34 // dynamic
35 if (preg_match('#^/rootprefix/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
36 return $this->mergeDefaults(array_replace($matches, array('_route' => 'dynamic')), array ());
37 }
38
39 }
40
41 throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
42 }
43}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/empty.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/empty.yml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/empty.yml
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo.xml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo.xml
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo1.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo1.xml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo1.xml
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/incomplete.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/incomplete.yml
new file mode 100644
index 00000000..df64d324
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/incomplete.yml
@@ -0,0 +1,2 @@
1blog_show:
2 defaults: { _controller: MyBlogBundle:Blog:show }
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_id.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_id.xml
new file mode 100644
index 00000000..4ea4115f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_id.xml
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route path="/test"></route>
8</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_path.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_path.xml
new file mode 100644
index 00000000..ef5bc088
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_path.xml
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route id="myroute"></route>
8</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml
new file mode 100644
index 00000000..bdd6a473
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<r:routes xmlns:r="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <r:route id="blog_show" path="/blog/{slug}" host="{_locale}.example.com">
8 <r:default key="_controller">MyBundle:Blog:show</r:default>
9 <requirement xmlns="http://symfony.com/schema/routing" key="slug">\w+</requirement>
10 <r2:requirement xmlns:r2="http://symfony.com/schema/routing" key="_locale">en|fr|de</r2:requirement>
11 <r:option key="compiler_class">RouteCompiler</r:option>
12 </r:route>
13</r:routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_resource_plus_path.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_resource_plus_path.yml
new file mode 100644
index 00000000..a3e94737
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_resource_plus_path.yml
@@ -0,0 +1,3 @@
1blog_show:
2 resource: validpattern.yml
3 path: /test
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_type_without_resource.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_type_without_resource.yml
new file mode 100644
index 00000000..547cda3b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_type_without_resource.yml
@@ -0,0 +1,3 @@
1blog_show:
2 path: /blog/{slug}
3 type: custom
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.xml
new file mode 100644
index 00000000..755e4430
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.xml
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route id="blog_show" path="/blog/{slug}">
8 <default key="_controller">MyBundle:Blog:show</default>
9 <requirement key="_method">GET</requirement>
10 <!-- </route> -->
11</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.yml
new file mode 100644
index 00000000..257cc564
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.yml
@@ -0,0 +1 @@
foo
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid2.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid2.yml
new file mode 100644
index 00000000..cfa9992b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid2.yml
@@ -0,0 +1 @@
route: string
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidkeys.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidkeys.yml
new file mode 100644
index 00000000..015e270f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidkeys.yml
@@ -0,0 +1,3 @@
1someroute:
2 resource: path/to/some.yml
3 name_prefix: test_
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidnode.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidnode.xml
new file mode 100644
index 00000000..863ef03b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidnode.xml
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <foo>bar</foo>
8</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidroute.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidroute.xml
new file mode 100644
index 00000000..a46961ee
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidroute.xml
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route id="blog_show" path="/blog/{slug}">
8 <default key="_controller">MyBundle:Blog:show</default>
9 <requirement key="_method">GET</requirement>
10 <option key="compiler_class">RouteCompiler</option>
11 <foo key="bar">baz</foo>
12 </route>
13</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/special_route_name.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/special_route_name.yml
new file mode 100644
index 00000000..78be239a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/special_route_name.yml
@@ -0,0 +1,2 @@
1"#$péß^a|":
2 path: "true"
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.php
new file mode 100644
index 00000000..b8bbbb5f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.php
@@ -0,0 +1,23 @@
1<?php
2use Symfony\Component\Routing\RouteCollection;
3use Symfony\Component\Routing\Route;
4
5$collection = new RouteCollection();
6$collection->add('blog_show', new Route(
7 '/blog/{slug}',
8 array('_controller' => 'MyBlogBundle:Blog:show'),
9 array('locale' => '\w+'),
10 array('compiler_class' => 'RouteCompiler'),
11 '{locale}.example.com',
12 array('https'),
13 array('GET','POST','put','OpTiOnS')
14));
15$collection->add('blog_show_legacy', new Route(
16 '/blog/{slug}',
17 array('_controller' => 'MyBlogBundle:Blog:show'),
18 array('_method' => 'GET|POST|put|OpTiOnS', '_scheme' => 'https', 'locale' => '\w+',),
19 array('compiler_class' => 'RouteCompiler'),
20 '{locale}.example.com'
21));
22
23return $collection;
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml
new file mode 100644
index 00000000..b9f22347
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml
@@ -0,0 +1,21 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route id="blog_show" path="/blog/{slug}" host="{locale}.example.com" methods="GET|POST put,OpTiOnS" schemes="hTTps">
8 <default key="_controller">MyBundle:Blog:show</default>
9 <requirement key="locale">\w+</requirement>
10 <option key="compiler_class">RouteCompiler</option>
11 </route>
12
13 <route id="blog_show_legacy" pattern="/blog/{slug}" host="{locale}.example.com">
14 <default key="_controller">MyBundle:Blog:show</default>
15 <default key="slug" xsi:nil="true" />
16 <requirement key="_method">GET|POST|put|OpTiOnS</requirement>
17 <requirement key="_scheme">hTTps</requirement>
18 <requirement key="locale">\w+</requirement>
19 <option key="compiler_class">RouteCompiler</option>
20 </route>
21</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml
new file mode 100644
index 00000000..4ada8832
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml
@@ -0,0 +1,17 @@
1blog_show:
2 path: /blog/{slug}
3 defaults: { _controller: "MyBundle:Blog:show" }
4 host: "{locale}.example.com"
5 requirements: { 'locale': '\w+' }
6 methods: ['GET','POST','put','OpTiOnS']
7 schemes: ['https']
8 options:
9 compiler_class: RouteCompiler
10
11blog_show_legacy:
12 pattern: /blog/{slug}
13 defaults: { _controller: "MyBundle:Blog:show" }
14 host: "{locale}.example.com"
15 requirements: { '_method': 'GET|POST|put|OpTiOnS', _scheme: https, 'locale': '\w+' }
16 options:
17 compiler_class: RouteCompiler
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.xml
new file mode 100644
index 00000000..295c3cc4
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.xml
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <import resource="validpattern.xml" prefix="/{foo}" host="">
8 <default key="foo">123</default>
9 <requirement key="foo">\d+</requirement>
10 <option key="foo">bar</option>
11 </import>
12</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.yml
new file mode 100644
index 00000000..495ed854
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.yml
@@ -0,0 +1,7 @@
1_blog:
2 resource: validpattern.yml
3 prefix: /{foo}
4 defaults: { 'foo': '123' }
5 requirements: { 'foo': '\d+' }
6 options: { 'foo': 'bar' }
7 host: ""
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/withdoctype.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/withdoctype.xml
new file mode 100644
index 00000000..f217d5bc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/withdoctype.xml
@@ -0,0 +1,3 @@
1<?xml version="1.0"?>
2<!DOCTYPE foo>
3<foo></foo>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php
new file mode 100644
index 00000000..ab5f4cda
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php
@@ -0,0 +1,117 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Generator\Dumper;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper;
17use Symfony\Component\Routing\RequestContext;
18
19class PhpGeneratorDumperTest extends \PHPUnit_Framework_TestCase
20{
21 /**
22 * @var RouteCollection
23 */
24 private $routeCollection;
25
26 /**
27 * @var PhpGeneratorDumper
28 */
29 private $generatorDumper;
30
31 /**
32 * @var string
33 */
34 private $testTmpFilepath;
35
36 protected function setUp()
37 {
38 parent::setUp();
39
40 $this->routeCollection = new RouteCollection();
41 $this->generatorDumper = new PhpGeneratorDumper($this->routeCollection);
42 $this->testTmpFilepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_generator.php';
43 @unlink($this->testTmpFilepath);
44 }
45
46 protected function tearDown()
47 {
48 parent::tearDown();
49
50 @unlink($this->testTmpFilepath);
51
52 $this->routeCollection = null;
53 $this->generatorDumper = null;
54 $this->testTmpFilepath = null;
55 }
56
57 public function testDumpWithRoutes()
58 {
59 $this->routeCollection->add('Test', new Route('/testing/{foo}'));
60 $this->routeCollection->add('Test2', new Route('/testing2'));
61
62 file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump());
63 include ($this->testTmpFilepath);
64
65 $projectUrlGenerator = new \ProjectUrlGenerator(new RequestContext('/app.php'));
66
67 $absoluteUrlWithParameter = $projectUrlGenerator->generate('Test', array('foo' => 'bar'), true);
68 $absoluteUrlWithoutParameter = $projectUrlGenerator->generate('Test2', array(), true);
69 $relativeUrlWithParameter = $projectUrlGenerator->generate('Test', array('foo' => 'bar'), false);
70 $relativeUrlWithoutParameter = $projectUrlGenerator->generate('Test2', array(), false);
71
72 $this->assertEquals($absoluteUrlWithParameter, 'http://localhost/app.php/testing/bar');
73 $this->assertEquals($absoluteUrlWithoutParameter, 'http://localhost/app.php/testing2');
74 $this->assertEquals($relativeUrlWithParameter, '/app.php/testing/bar');
75 $this->assertEquals($relativeUrlWithoutParameter, '/app.php/testing2');
76 }
77
78 /**
79 * @expectedException \InvalidArgumentException
80 */
81 public function testDumpWithoutRoutes()
82 {
83 file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(array('class' => 'WithoutRoutesUrlGenerator')));
84 include ($this->testTmpFilepath);
85
86 $projectUrlGenerator = new \WithoutRoutesUrlGenerator(new RequestContext('/app.php'));
87
88 $projectUrlGenerator->generate('Test', array());
89 }
90
91 /**
92 * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
93 */
94 public function testGenerateNonExistingRoute()
95 {
96 $this->routeCollection->add('Test', new Route('/test'));
97
98 file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(array('class' => 'NonExistingRoutesUrlGenerator')));
99 include ($this->testTmpFilepath);
100
101 $projectUrlGenerator = new \NonExistingRoutesUrlGenerator(new RequestContext());
102 $url = $projectUrlGenerator->generate('NonExisting', array());
103 }
104
105 public function testDumpForRouteWithDefaults()
106 {
107 $this->routeCollection->add('Test', new Route('/testing/{foo}', array('foo' => 'bar')));
108
109 file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(array('class' => 'DefaultRoutesUrlGenerator')));
110 include ($this->testTmpFilepath);
111
112 $projectUrlGenerator = new \DefaultRoutesUrlGenerator(new RequestContext());
113 $url = $projectUrlGenerator->generate('Test', array());
114
115 $this->assertEquals($url, '/testing');
116 }
117}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php
new file mode 100644
index 00000000..5f8ef491
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php
@@ -0,0 +1,635 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Generator;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\Generator\UrlGenerator;
17use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
18use Symfony\Component\Routing\RequestContext;
19
20class UrlGeneratorTest extends \PHPUnit_Framework_TestCase
21{
22 public function testAbsoluteUrlWithPort80()
23 {
24 $routes = $this->getRoutes('test', new Route('/testing'));
25 $url = $this->getGenerator($routes)->generate('test', array(), true);
26
27 $this->assertEquals('http://localhost/app.php/testing', $url);
28 }
29
30 public function testAbsoluteSecureUrlWithPort443()
31 {
32 $routes = $this->getRoutes('test', new Route('/testing'));
33 $url = $this->getGenerator($routes, array('scheme' => 'https'))->generate('test', array(), true);
34
35 $this->assertEquals('https://localhost/app.php/testing', $url);
36 }
37
38 public function testAbsoluteUrlWithNonStandardPort()
39 {
40 $routes = $this->getRoutes('test', new Route('/testing'));
41 $url = $this->getGenerator($routes, array('httpPort' => 8080))->generate('test', array(), true);
42
43 $this->assertEquals('http://localhost:8080/app.php/testing', $url);
44 }
45
46 public function testAbsoluteSecureUrlWithNonStandardPort()
47 {
48 $routes = $this->getRoutes('test', new Route('/testing'));
49 $url = $this->getGenerator($routes, array('httpsPort' => 8080, 'scheme' => 'https'))->generate('test', array(), true);
50
51 $this->assertEquals('https://localhost:8080/app.php/testing', $url);
52 }
53
54 public function testRelativeUrlWithoutParameters()
55 {
56 $routes = $this->getRoutes('test', new Route('/testing'));
57 $url = $this->getGenerator($routes)->generate('test', array(), false);
58
59 $this->assertEquals('/app.php/testing', $url);
60 }
61
62 public function testRelativeUrlWithParameter()
63 {
64 $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
65 $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), false);
66
67 $this->assertEquals('/app.php/testing/bar', $url);
68 }
69
70 public function testRelativeUrlWithNullParameter()
71 {
72 $routes = $this->getRoutes('test', new Route('/testing.{format}', array('format' => null)));
73 $url = $this->getGenerator($routes)->generate('test', array(), false);
74
75 $this->assertEquals('/app.php/testing', $url);
76 }
77
78 /**
79 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
80 */
81 public function testRelativeUrlWithNullParameterButNotOptional()
82 {
83 $routes = $this->getRoutes('test', new Route('/testing/{foo}/bar', array('foo' => null)));
84 // This must raise an exception because the default requirement for "foo" is "[^/]+" which is not met with these params.
85 // Generating path "/testing//bar" would be wrong as matching this route would fail.
86 $this->getGenerator($routes)->generate('test', array(), false);
87 }
88
89 public function testRelativeUrlWithOptionalZeroParameter()
90 {
91 $routes = $this->getRoutes('test', new Route('/testing/{page}'));
92 $url = $this->getGenerator($routes)->generate('test', array('page' => 0), false);
93
94 $this->assertEquals('/app.php/testing/0', $url);
95 }
96
97 public function testNotPassedOptionalParameterInBetween()
98 {
99 $routes = $this->getRoutes('test', new Route('/{slug}/{page}', array('slug' => 'index', 'page' => 0)));
100 $this->assertSame('/app.php/index/1', $this->getGenerator($routes)->generate('test', array('page' => 1)));
101 $this->assertSame('/app.php/', $this->getGenerator($routes)->generate('test'));
102 }
103
104 public function testRelativeUrlWithExtraParameters()
105 {
106 $routes = $this->getRoutes('test', new Route('/testing'));
107 $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), false);
108
109 $this->assertEquals('/app.php/testing?foo=bar', $url);
110 }
111
112 public function testAbsoluteUrlWithExtraParameters()
113 {
114 $routes = $this->getRoutes('test', new Route('/testing'));
115 $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
116
117 $this->assertEquals('http://localhost/app.php/testing?foo=bar', $url);
118 }
119
120 public function testUrlWithNullExtraParameters()
121 {
122 $routes = $this->getRoutes('test', new Route('/testing'));
123 $url = $this->getGenerator($routes)->generate('test', array('foo' => null), true);
124
125 $this->assertEquals('http://localhost/app.php/testing', $url);
126 }
127
128 public function testUrlWithExtraParametersFromGlobals()
129 {
130 $routes = $this->getRoutes('test', new Route('/testing'));
131 $generator = $this->getGenerator($routes);
132 $context = new RequestContext('/app.php');
133 $context->setParameter('bar', 'bar');
134 $generator->setContext($context);
135 $url = $generator->generate('test', array('foo' => 'bar'));
136
137 $this->assertEquals('/app.php/testing?foo=bar', $url);
138 }
139
140 public function testUrlWithGlobalParameter()
141 {
142 $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
143 $generator = $this->getGenerator($routes);
144 $context = new RequestContext('/app.php');
145 $context->setParameter('foo', 'bar');
146 $generator->setContext($context);
147 $url = $generator->generate('test', array());
148
149 $this->assertEquals('/app.php/testing/bar', $url);
150 }
151
152 public function testGlobalParameterHasHigherPriorityThanDefault()
153 {
154 $routes = $this->getRoutes('test', new Route('/{_locale}', array('_locale' => 'en')));
155 $generator = $this->getGenerator($routes);
156 $context = new RequestContext('/app.php');
157 $context->setParameter('_locale', 'de');
158 $generator->setContext($context);
159 $url = $generator->generate('test', array());
160
161 $this->assertSame('/app.php/de', $url);
162 }
163
164 /**
165 * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
166 */
167 public function testGenerateWithoutRoutes()
168 {
169 $routes = $this->getRoutes('foo', new Route('/testing/{foo}'));
170 $this->getGenerator($routes)->generate('test', array(), true);
171 }
172
173 /**
174 * @expectedException \Symfony\Component\Routing\Exception\MissingMandatoryParametersException
175 */
176 public function testGenerateForRouteWithoutMandatoryParameter()
177 {
178 $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
179 $this->getGenerator($routes)->generate('test', array(), true);
180 }
181
182 /**
183 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
184 */
185 public function testGenerateForRouteWithInvalidOptionalParameter()
186 {
187 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
188 $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
189 }
190
191 /**
192 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
193 */
194 public function testGenerateForRouteWithInvalidParameter()
195 {
196 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => '1|2')));
197 $this->getGenerator($routes)->generate('test', array('foo' => '0'), true);
198 }
199
200 public function testGenerateForRouteWithInvalidOptionalParameterNonStrict()
201 {
202 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
203 $generator = $this->getGenerator($routes);
204 $generator->setStrictRequirements(false);
205 $this->assertNull($generator->generate('test', array('foo' => 'bar'), true));
206 }
207
208 public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger()
209 {
210 if (!interface_exists('Psr\Log\LoggerInterface')) {
211 $this->markTestSkipped('The "psr/log" package is not available');
212 }
213
214 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
215 $logger = $this->getMock('Psr\Log\LoggerInterface');
216 $logger->expects($this->once())
217 ->method('error');
218 $generator = $this->getGenerator($routes, array(), $logger);
219 $generator->setStrictRequirements(false);
220 $this->assertNull($generator->generate('test', array('foo' => 'bar'), true));
221 }
222
223 public function testGenerateForRouteWithInvalidParameterButDisabledRequirementsCheck()
224 {
225 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
226 $generator = $this->getGenerator($routes);
227 $generator->setStrictRequirements(null);
228 $this->assertSame('/app.php/testing/bar', $generator->generate('test', array('foo' => 'bar')));
229 }
230
231 /**
232 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
233 */
234 public function testGenerateForRouteWithInvalidMandatoryParameter()
235 {
236 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => 'd+')));
237 $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
238 }
239
240 /**
241 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
242 */
243 public function testRequiredParamAndEmptyPassed()
244 {
245 $routes = $this->getRoutes('test', new Route('/{slug}', array(), array('slug' => '.+')));
246 $this->getGenerator($routes)->generate('test', array('slug' => ''));
247 }
248
249 public function testSchemeRequirementDoesNothingIfSameCurrentScheme()
250 {
251 $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'http')));
252 $this->assertEquals('/app.php/', $this->getGenerator($routes)->generate('test'));
253
254 $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'https')));
255 $this->assertEquals('/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
256 }
257
258 public function testSchemeRequirementForcesAbsoluteUrl()
259 {
260 $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'https')));
261 $this->assertEquals('https://localhost/app.php/', $this->getGenerator($routes)->generate('test'));
262
263 $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'http')));
264 $this->assertEquals('http://localhost/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
265 }
266
267 public function testPathWithTwoStartingSlashes()
268 {
269 $routes = $this->getRoutes('test', new Route('//path-and-not-domain'));
270
271 // this must not generate '//path-and-not-domain' because that would be a network path
272 $this->assertSame('/path-and-not-domain', $this->getGenerator($routes, array('BaseUrl' => ''))->generate('test'));
273 }
274
275 public function testNoTrailingSlashForMultipleOptionalParameters()
276 {
277 $routes = $this->getRoutes('test', new Route('/category/{slug1}/{slug2}/{slug3}', array('slug2' => null, 'slug3' => null)));
278
279 $this->assertEquals('/app.php/category/foo', $this->getGenerator($routes)->generate('test', array('slug1' => 'foo')));
280 }
281
282 public function testWithAnIntegerAsADefaultValue()
283 {
284 $routes = $this->getRoutes('test', new Route('/{default}', array('default' => 0)));
285
286 $this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
287 }
288
289 public function testNullForOptionalParameterIsIgnored()
290 {
291 $routes = $this->getRoutes('test', new Route('/test/{default}', array('default' => 0)));
292
293 $this->assertEquals('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => null)));
294 }
295
296 public function testQueryParamSameAsDefault()
297 {
298 $routes = $this->getRoutes('test', new Route('/test', array('default' => 'value')));
299
300 $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
301 $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => 'value')));
302 $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test'));
303 }
304
305 public function testGenerateWithSpecialRouteName()
306 {
307 $routes = $this->getRoutes('$péß^a|', new Route('/bar'));
308
309 $this->assertSame('/app.php/bar', $this->getGenerator($routes)->generate('$péß^a|'));
310 }
311
312 public function testUrlEncoding()
313 {
314 // This tests the encoding of reserved characters that are used for delimiting of URI components (defined in RFC 3986)
315 // and other special ASCII chars. These chars are tested as static text path, variable path and query param.
316 $chars = '@:[]/()*\'" +,;-._~&$<>|{}%\\^`!?foo=bar#id';
317 $routes = $this->getRoutes('test', new Route("/$chars/{varpath}", array(), array('varpath' => '.+')));
318 $this->assertSame('/app.php/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
319 .'/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
320 .'?query=%40%3A%5B%5D%2F%28%29%2A%27%22+%2B%2C%3B-._%7E%26%24%3C%3E%7C%7B%7D%25%5C%5E%60%21%3Ffoo%3Dbar%23id',
321 $this->getGenerator($routes)->generate('test', array(
322 'varpath' => $chars,
323 'query' => $chars
324 ))
325 );
326 }
327
328 public function testEncodingOfRelativePathSegments()
329 {
330 $routes = $this->getRoutes('test', new Route('/dir/../dir/..'));
331 $this->assertSame('/app.php/dir/%2E%2E/dir/%2E%2E', $this->getGenerator($routes)->generate('test'));
332 $routes = $this->getRoutes('test', new Route('/dir/./dir/.'));
333 $this->assertSame('/app.php/dir/%2E/dir/%2E', $this->getGenerator($routes)->generate('test'));
334 $routes = $this->getRoutes('test', new Route('/a./.a/a../..a/...'));
335 $this->assertSame('/app.php/a./.a/a../..a/...', $this->getGenerator($routes)->generate('test'));
336 }
337
338 public function testAdjacentVariables()
339 {
340 $routes = $this->getRoutes('test', new Route('/{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '\d+')));
341 $generator = $this->getGenerator($routes);
342 $this->assertSame('/app.php/foo123', $generator->generate('test', array('x' => 'foo', 'y' => '123')));
343 $this->assertSame('/app.php/foo123bar.xml', $generator->generate('test', array('x' => 'foo', 'y' => '123', 'z' => 'bar', '_format' => 'xml')));
344
345 // The default requirement for 'x' should not allow the separator '.' in this case because it would otherwise match everything
346 // and following optional variables like _format could never match.
347 $this->setExpectedException('Symfony\Component\Routing\Exception\InvalidParameterException');
348 $generator->generate('test', array('x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml'));
349 }
350
351 public function testOptionalVariableWithNoRealSeparator()
352 {
353 $routes = $this->getRoutes('test', new Route('/get{what}', array('what' => 'All')));
354 $generator = $this->getGenerator($routes);
355
356 $this->assertSame('/app.php/get', $generator->generate('test'));
357 $this->assertSame('/app.php/getSites', $generator->generate('test', array('what' => 'Sites')));
358 }
359
360 public function testRequiredVariableWithNoRealSeparator()
361 {
362 $routes = $this->getRoutes('test', new Route('/get{what}Suffix'));
363 $generator = $this->getGenerator($routes);
364
365 $this->assertSame('/app.php/getSitesSuffix', $generator->generate('test', array('what' => 'Sites')));
366 }
367
368 public function testDefaultRequirementOfVariable()
369 {
370 $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
371 $generator = $this->getGenerator($routes);
372
373 $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html')));
374 }
375
376 /**
377 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
378 */
379 public function testDefaultRequirementOfVariableDisallowsSlash()
380 {
381 $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
382 $this->getGenerator($routes)->generate('test', array('page' => 'index', '_format' => 'sl/ash'));
383 }
384
385 /**
386 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
387 */
388 public function testDefaultRequirementOfVariableDisallowsNextSeparator()
389 {
390 $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
391 $this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html'));
392 }
393
394 public function testWithHostDifferentFromContext()
395 {
396 $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
397
398 $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' =>'Fabien', 'locale' => 'fr')));
399 }
400
401 public function testWithHostSameAsContext()
402 {
403 $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
404
405 $this->assertEquals('/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' =>'Fabien', 'locale' => 'fr')));
406 }
407
408 public function testWithHostSameAsContextAndAbsolute()
409 {
410 $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
411
412 $this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' =>'Fabien', 'locale' => 'fr'), true));
413 }
414
415 /**
416 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
417 */
418 public function testUrlWithInvalidParameterInHost()
419 {
420 $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
421 $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), false);
422 }
423
424 /**
425 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
426 */
427 public function testUrlWithInvalidParameterInHostWhenParamHasADefaultValue()
428 {
429 $routes = $this->getRoutes('test', new Route('/', array('foo' => 'bar'), array('foo' => 'bar'), array(), '{foo}.example.com'));
430 $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), false);
431 }
432
433 /**
434 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
435 */
436 public function testUrlWithInvalidParameterEqualsDefaultValueInHost()
437 {
438 $routes = $this->getRoutes('test', new Route('/', array('foo' => 'baz'), array('foo' => 'bar'), array(), '{foo}.example.com'));
439 $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), false);
440 }
441
442 public function testUrlWithInvalidParameterInHostInNonStrictMode()
443 {
444 $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
445 $generator = $this->getGenerator($routes);
446 $generator->setStrictRequirements(false);
447 $this->assertNull($generator->generate('test', array('foo' => 'baz'), false));
448 }
449
450 public function testGenerateNetworkPath()
451 {
452 $routes = $this->getRoutes('test', new Route('/{name}', array(), array('_scheme' => 'http'), array(), '{locale}.example.com'));
453
454 $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
455 array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'network path with different host'
456 );
457 $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test',
458 array('name' =>'Fabien', 'locale' => 'fr', 'query' => 'string'), UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context'
459 );
460 $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test',
461 array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context'
462 );
463 $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
464 array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested'
465 );
466 }
467
468 public function testGenerateRelativePath()
469 {
470 $routes = new RouteCollection();
471 $routes->add('article', new Route('/{author}/{article}/'));
472 $routes->add('comments', new Route('/{author}/{article}/comments'));
473 $routes->add('host', new Route('/{article}', array(), array(), array(), '{author}.example.com'));
474 $routes->add('scheme', new Route('/{author}', array(), array('_scheme' => 'https')));
475 $routes->add('unrelated', new Route('/about'));
476
477 $generator = $this->getGenerator($routes, array('host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/'));
478
479 $this->assertSame('comments', $generator->generate('comments',
480 array('author' =>'fabien', 'article' => 'symfony-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
481 );
482 $this->assertSame('comments?page=2', $generator->generate('comments',
483 array('author' =>'fabien', 'article' => 'symfony-is-great', 'page' => 2), UrlGeneratorInterface::RELATIVE_PATH)
484 );
485 $this->assertSame('../twig-is-great/', $generator->generate('article',
486 array('author' =>'fabien', 'article' => 'twig-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
487 );
488 $this->assertSame('../../bernhard/forms-are-great/', $generator->generate('article',
489 array('author' =>'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
490 );
491 $this->assertSame('//bernhard.example.com/app.php/forms-are-great', $generator->generate('host',
492 array('author' =>'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
493 );
494 $this->assertSame('https://example.com/app.php/bernhard', $generator->generate('scheme',
495 array('author' =>'bernhard'), UrlGeneratorInterface::RELATIVE_PATH)
496 );
497 $this->assertSame('../../about', $generator->generate('unrelated',
498 array(), UrlGeneratorInterface::RELATIVE_PATH)
499 );
500 }
501
502 /**
503 * @dataProvider provideRelativePaths
504 */
505 public function testGetRelativePath($sourcePath, $targetPath, $expectedPath)
506 {
507 $this->assertSame($expectedPath, UrlGenerator::getRelativePath($sourcePath, $targetPath));
508 }
509
510 public function provideRelativePaths()
511 {
512 return array(
513 array(
514 '/same/dir/',
515 '/same/dir/',
516 ''
517 ),
518 array(
519 '/same/file',
520 '/same/file',
521 ''
522 ),
523 array(
524 '/',
525 '/file',
526 'file'
527 ),
528 array(
529 '/',
530 '/dir/file',
531 'dir/file'
532 ),
533 array(
534 '/dir/file.html',
535 '/dir/different-file.html',
536 'different-file.html'
537 ),
538 array(
539 '/same/dir/extra-file',
540 '/same/dir/',
541 './'
542 ),
543 array(
544 '/parent/dir/',
545 '/parent/',
546 '../'
547 ),
548 array(
549 '/parent/dir/extra-file',
550 '/parent/',
551 '../'
552 ),
553 array(
554 '/a/b/',
555 '/x/y/z/',
556 '../../x/y/z/'
557 ),
558 array(
559 '/a/b/c/d/e',
560 '/a/c/d',
561 '../../../c/d'
562 ),
563 array(
564 '/a/b/c//',
565 '/a/b/c/',
566 '../'
567 ),
568 array(
569 '/a/b/c/',
570 '/a/b/c//',
571 './/'
572 ),
573 array(
574 '/root/a/b/c/',
575 '/root/x/b/c/',
576 '../../../x/b/c/'
577 ),
578 array(
579 '/a/b/c/d/',
580 '/a',
581 '../../../../a'
582 ),
583 array(
584 '/special-chars/sp%20ce/1€/mäh/e=mc²',
585 '/special-chars/sp%20ce/1€/<µ>/e=mc²',
586 '../<µ>/e=mc²'
587 ),
588 array(
589 'not-rooted',
590 'dir/file',
591 'dir/file'
592 ),
593 array(
594 '//dir/',
595 '',
596 '../../'
597 ),
598 array(
599 '/dir/',
600 '/dir/file:with-colon',
601 './file:with-colon'
602 ),
603 array(
604 '/dir/',
605 '/dir/subdir/file:with-colon',
606 'subdir/file:with-colon'
607 ),
608 array(
609 '/dir/',
610 '/dir/:subdir/',
611 './:subdir/'
612 ),
613 );
614 }
615
616 protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
617 {
618 $context = new RequestContext('/app.php');
619 foreach ($parameters as $key => $value) {
620 $method = 'set'.$key;
621 $context->$method($value);
622 }
623 $generator = new UrlGenerator($routes, $context, $logger);
624
625 return $generator;
626 }
627
628 protected function getRoutes($name, Route $route)
629 {
630 $routes = new RouteCollection();
631 $routes->add($name, $route);
632
633 return $routes;
634 }
635}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTest.php
new file mode 100644
index 00000000..c927ae4a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTest.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Loader;
13
14abstract class AbstractAnnotationLoaderTest extends \PHPUnit_Framework_TestCase
15{
16 protected function setUp()
17 {
18 if (!class_exists('Doctrine\\Common\\Version')) {
19 $this->markTestSkipped('Doctrine is not available.');
20 }
21 }
22
23 public function getReader()
24 {
25 return $this->getMockBuilder('Doctrine\Common\Annotations\Reader')
26 ->disableOriginalConstructor()
27 ->getMock()
28 ;
29 }
30
31 public function getClassLoader($reader)
32 {
33 return $this->getMockBuilder('Symfony\Component\Routing\Loader\AnnotationClassLoader')
34 ->setConstructorArgs(array($reader))
35 ->getMockForAbstractClass()
36 ;
37 }
38}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php
new file mode 100644
index 00000000..31c43f58
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php
@@ -0,0 +1,119 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Loader;
13
14class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
15{
16 protected $loader;
17
18 protected function setUp()
19 {
20 parent::setUp();
21
22 $this->reader = $this->getReader();
23 $this->loader = $this->getClassLoader($this->reader);
24 }
25
26 /**
27 * @expectedException \InvalidArgumentException
28 */
29 public function testLoadMissingClass()
30 {
31 $this->loader->load('MissingClass');
32 }
33
34 /**
35 * @expectedException \InvalidArgumentException
36 */
37 public function testLoadAbstractClass()
38 {
39 $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\AbstractClass');
40 }
41
42 /**
43 * @dataProvider provideTestSupportsChecksResource
44 */
45 public function testSupportsChecksResource($resource, $expectedSupports)
46 {
47 $this->assertSame($expectedSupports, $this->loader->supports($resource), '->supports() returns true if the resource is loadable');
48 }
49
50 public function provideTestSupportsChecksResource()
51 {
52 return array(
53 array('class', true),
54 array('\fully\qualified\class\name', true),
55 array('namespaced\class\without\leading\slash', true),
56 array('ÿClassWithLegalSpecialCharacters', true),
57 array('5', false),
58 array('foo.foo', false),
59 array(null, false),
60 );
61 }
62
63 public function testSupportsChecksTypeIfSpecified()
64 {
65 $this->assertTrue($this->loader->supports('class', 'annotation'), '->supports() checks the resource type if specified');
66 $this->assertFalse($this->loader->supports('class', 'foo'), '->supports() checks the resource type if specified');
67 }
68
69 public function getLoadTests()
70 {
71 return array(
72 array(
73 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
74 array('name'=>'route1'),
75 array('arg2' => 'defaultValue2', 'arg3' =>'defaultValue3')
76 ),
77 array(
78 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
79 array('name'=>'route1', 'defaults' => array('arg2' => 'foo')),
80 array('arg2' => 'defaultValue2', 'arg3' =>'defaultValue3')
81 ),
82 );
83 }
84
85 /**
86 * @dataProvider getLoadTests
87 */
88 public function testLoad($className, $routeDatas = array(), $methodArgs = array())
89 {
90 $routeDatas = array_replace(array(
91 'name' => 'route',
92 'path' => '/',
93 'requirements' => array(),
94 'options' => array(),
95 'defaults' => array(),
96 'schemes' => array(),
97 'methods' => array(),
98 ), $routeDatas);
99
100 $this->reader
101 ->expects($this->once())
102 ->method('getMethodAnnotations')
103 ->will($this->returnValue(array($this->getAnnotatedRoute($routeDatas))))
104 ;
105 $routeCollection = $this->loader->load($className);
106 $route = $routeCollection->get($routeDatas['name']);
107
108 $this->assertSame($routeDatas['path'], $route->getPath(), '->load preserves path annotation');
109 $this->assertSame($routeDatas['requirements'],$route->getRequirements(), '->load preserves requirements annotation');
110 $this->assertCount(0, array_intersect($route->getOptions(), $routeDatas['options']), '->load preserves options annotation');
111 $this->assertSame(array_replace($routeDatas['defaults'], $methodArgs), $route->getDefaults(), '->load preserves defaults annotation');
112 }
113
114 private function getAnnotatedRoute($datas)
115 {
116 return new \Symfony\Component\Routing\Annotation\Route($datas);
117 }
118
119}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php
new file mode 100644
index 00000000..29126ba4
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php
@@ -0,0 +1,53 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader;
15use Symfony\Component\Config\FileLocator;
16
17class AnnotationDirectoryLoaderTest extends AbstractAnnotationLoaderTest
18{
19 protected $loader;
20 protected $reader;
21
22 protected function setUp()
23 {
24 parent::setUp();
25
26 $this->reader = $this->getReader();
27 $this->loader = new AnnotationDirectoryLoader(new FileLocator(), $this->getClassLoader($this->reader));
28 }
29
30 public function testLoad()
31 {
32 $this->reader->expects($this->exactly(2))->method('getClassAnnotation');
33
34 $this->reader
35 ->expects($this->any())
36 ->method('getMethodAnnotations')
37 ->will($this->returnValue(array()))
38 ;
39
40 $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses');
41 }
42
43 public function testSupports()
44 {
45 $fixturesDir = __DIR__.'/../Fixtures';
46
47 $this->assertTrue($this->loader->supports($fixturesDir), '->supports() returns true if the resource is loadable');
48 $this->assertFalse($this->loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
49
50 $this->assertTrue($this->loader->supports($fixturesDir, 'annotation'), '->supports() checks the resource type if specified');
51 $this->assertFalse($this->loader->supports($fixturesDir, 'foo'), '->supports() checks the resource type if specified');
52 }
53}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php
new file mode 100644
index 00000000..f0a8a0e3
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Routing\Loader\AnnotationFileLoader;
15use Symfony\Component\Config\FileLocator;
16
17class AnnotationFileLoaderTest extends AbstractAnnotationLoaderTest
18{
19 protected $loader;
20 protected $reader;
21
22 protected function setUp()
23 {
24 parent::setUp();
25
26 $this->reader = $this->getReader();
27 $this->loader = new AnnotationFileLoader(new FileLocator(), $this->getClassLoader($this->reader));
28 }
29
30 public function testLoad()
31 {
32 $this->reader->expects($this->once())->method('getClassAnnotation');
33
34 $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php');
35 }
36
37 public function testSupports()
38 {
39 $fixture = __DIR__.'/../Fixtures/annotated.php';
40
41 $this->assertTrue($this->loader->supports($fixture), '->supports() returns true if the resource is loadable');
42 $this->assertFalse($this->loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
43
44 $this->assertTrue($this->loader->supports($fixture, 'annotation'), '->supports() checks the resource type if specified');
45 $this->assertFalse($this->loader->supports($fixture, 'foo'), '->supports() checks the resource type if specified');
46 }
47}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/ClosureLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/ClosureLoaderTest.php
new file mode 100644
index 00000000..64d1b086
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/ClosureLoaderTest.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Routing\Loader\ClosureLoader;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\RouteCollection;
17
18class ClosureLoaderTest extends \PHPUnit_Framework_TestCase
19{
20 protected function setUp()
21 {
22 if (!class_exists('Symfony\Component\Config\FileLocator')) {
23 $this->markTestSkipped('The "Config" component is not available');
24 }
25 }
26
27 public function testSupports()
28 {
29 $loader = new ClosureLoader();
30
31 $closure = function () {};
32
33 $this->assertTrue($loader->supports($closure), '->supports() returns true if the resource is loadable');
34 $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
35
36 $this->assertTrue($loader->supports($closure, 'closure'), '->supports() checks the resource type if specified');
37 $this->assertFalse($loader->supports($closure, 'foo'), '->supports() checks the resource type if specified');
38 }
39
40 public function testLoad()
41 {
42 $loader = new ClosureLoader();
43
44 $route = new Route('/');
45 $routes = $loader->load(function () use ($route) {
46 $routes = new RouteCollection();
47
48 $routes->add('foo', $route);
49
50 return $routes;
51 });
52
53 $this->assertEquals($route, $routes->get('foo'), '->load() loads a \Closure resource');
54 }
55}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php
new file mode 100644
index 00000000..18b166fc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Config\FileLocator;
15use Symfony\Component\Routing\Loader\PhpFileLoader;
16
17class PhpFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\FileLocator')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24 }
25
26 public function testSupports()
27 {
28 $loader = new PhpFileLoader($this->getMock('Symfony\Component\Config\FileLocator'));
29
30 $this->assertTrue($loader->supports('foo.php'), '->supports() returns true if the resource is loadable');
31 $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
32
33 $this->assertTrue($loader->supports('foo.php', 'php'), '->supports() checks the resource type if specified');
34 $this->assertFalse($loader->supports('foo.php', 'foo'), '->supports() checks the resource type if specified');
35 }
36
37 public function testLoadWithRoute()
38 {
39 $loader = new PhpFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
40 $routeCollection = $loader->load('validpattern.php');
41 $routes = $routeCollection->all();
42
43 $this->assertCount(2, $routes, 'Two routes are loaded');
44 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
45
46 foreach ($routes as $route) {
47 $this->assertSame('/blog/{slug}', $route->getPath());
48 $this->assertSame('MyBlogBundle:Blog:show', $route->getDefault('_controller'));
49 $this->assertSame('{locale}.example.com', $route->getHost());
50 $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
51 $this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
52 $this->assertEquals(array('https'), $route->getSchemes());
53 }
54 }
55}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
new file mode 100644
index 00000000..9f038c16
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
@@ -0,0 +1,127 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Config\FileLocator;
15use Symfony\Component\Routing\Loader\XmlFileLoader;
16use Symfony\Component\Routing\Tests\Fixtures\CustomXmlFileLoader;
17
18class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
19{
20 protected function setUp()
21 {
22 if (!class_exists('Symfony\Component\Config\FileLocator')) {
23 $this->markTestSkipped('The "Config" component is not available');
24 }
25 }
26
27 public function testSupports()
28 {
29 $loader = new XmlFileLoader($this->getMock('Symfony\Component\Config\FileLocator'));
30
31 $this->assertTrue($loader->supports('foo.xml'), '->supports() returns true if the resource is loadable');
32 $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
33
34 $this->assertTrue($loader->supports('foo.xml', 'xml'), '->supports() checks the resource type if specified');
35 $this->assertFalse($loader->supports('foo.xml', 'foo'), '->supports() checks the resource type if specified');
36 }
37
38 public function testLoadWithRoute()
39 {
40 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
41 $routeCollection = $loader->load('validpattern.xml');
42 $routes = $routeCollection->all();
43
44 $this->assertCount(2, $routes, 'Two routes are loaded');
45 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
46
47 foreach ($routes as $route) {
48 $this->assertSame('/blog/{slug}', $route->getPath());
49 $this->assertSame('{locale}.example.com', $route->getHost());
50 $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller'));
51 $this->assertSame('\w+', $route->getRequirement('locale'));
52 $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
53 $this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
54 $this->assertEquals(array('https'), $route->getSchemes());
55 }
56 }
57
58 public function testLoadWithNamespacePrefix()
59 {
60 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
61 $routeCollection = $loader->load('namespaceprefix.xml');
62
63 $this->assertCount(1, $routeCollection->all(), 'One route is loaded');
64
65 $route = $routeCollection->get('blog_show');
66 $this->assertSame('/blog/{slug}', $route->getPath());
67 $this->assertSame('{_locale}.example.com', $route->getHost());
68 $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller'));
69 $this->assertSame('\w+', $route->getRequirement('slug'));
70 $this->assertSame('en|fr|de', $route->getRequirement('_locale'));
71 $this->assertSame(null, $route->getDefault('slug'));
72 $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
73 }
74
75 public function testLoadWithImport()
76 {
77 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
78 $routeCollection = $loader->load('validresource.xml');
79 $routes = $routeCollection->all();
80
81 $this->assertCount(2, $routes, 'Two routes are loaded');
82 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
83
84 foreach ($routes as $route) {
85 $this->assertSame('/{foo}/blog/{slug}', $route->getPath());
86 $this->assertSame('123', $route->getDefault('foo'));
87 $this->assertSame('\d+', $route->getRequirement('foo'));
88 $this->assertSame('bar', $route->getOption('foo'));
89 $this->assertSame('', $route->getHost());
90 }
91 }
92
93 /**
94 * @expectedException \InvalidArgumentException
95 * @dataProvider getPathsToInvalidFiles
96 */
97 public function testLoadThrowsExceptionWithInvalidFile($filePath)
98 {
99 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
100 $loader->load($filePath);
101 }
102
103 /**
104 * @expectedException \InvalidArgumentException
105 * @dataProvider getPathsToInvalidFiles
106 */
107 public function testLoadThrowsExceptionWithInvalidFileEvenWithoutSchemaValidation($filePath)
108 {
109 $loader = new CustomXmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
110 $loader->load($filePath);
111 }
112
113 public function getPathsToInvalidFiles()
114 {
115 return array(array('nonvalidnode.xml'), array('nonvalidroute.xml'), array('nonvalid.xml'), array('missing_id.xml'), array('missing_path.xml'));
116 }
117
118 /**
119 * @expectedException \InvalidArgumentException
120 * @expectedExceptionMessage Document types are not allowed.
121 */
122 public function testDocTypeIsNotAllowed()
123 {
124 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
125 $loader->load('withdoctype.xml');
126 }
127}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
new file mode 100644
index 00000000..a3e934ce
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
@@ -0,0 +1,113 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Config\FileLocator;
15use Symfony\Component\Routing\Loader\YamlFileLoader;
16use Symfony\Component\Config\Resource\FileResource;
17
18class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
19{
20 protected function setUp()
21 {
22 if (!class_exists('Symfony\Component\Config\FileLocator')) {
23 $this->markTestSkipped('The "Config" component is not available');
24 }
25
26 if (!class_exists('Symfony\Component\Yaml\Yaml')) {
27 $this->markTestSkipped('The "Yaml" component is not available');
28 }
29 }
30
31 public function testSupports()
32 {
33 $loader = new YamlFileLoader($this->getMock('Symfony\Component\Config\FileLocator'));
34
35 $this->assertTrue($loader->supports('foo.yml'), '->supports() returns true if the resource is loadable');
36 $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
37
38 $this->assertTrue($loader->supports('foo.yml', 'yaml'), '->supports() checks the resource type if specified');
39 $this->assertFalse($loader->supports('foo.yml', 'foo'), '->supports() checks the resource type if specified');
40 }
41
42 public function testLoadDoesNothingIfEmpty()
43 {
44 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
45 $collection = $loader->load('empty.yml');
46
47 $this->assertEquals(array(), $collection->all());
48 $this->assertEquals(array(new FileResource(realpath(__DIR__.'/../Fixtures/empty.yml'))), $collection->getResources());
49 }
50
51 /**
52 * @expectedException \InvalidArgumentException
53 * @dataProvider getPathsToInvalidFiles
54 */
55 public function testLoadThrowsExceptionWithInvalidFile($filePath)
56 {
57 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
58 $loader->load($filePath);
59 }
60
61 public function getPathsToInvalidFiles()
62 {
63 return array(array('nonvalid.yml'), array('nonvalid2.yml'), array('incomplete.yml'), array('nonvalidkeys.yml'), array('nonesense_resource_plus_path.yml'), array('nonesense_type_without_resource.yml'));
64 }
65
66 public function testLoadSpecialRouteName()
67 {
68 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
69 $routeCollection = $loader->load('special_route_name.yml');
70 $route = $routeCollection->get('#$péß^a|');
71
72 $this->assertInstanceOf('Symfony\Component\Routing\Route', $route);
73 $this->assertSame('/true', $route->getPath());
74 }
75
76 public function testLoadWithRoute()
77 {
78 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
79 $routeCollection = $loader->load('validpattern.yml');
80 $routes = $routeCollection->all();
81
82 $this->assertCount(2, $routes, 'Two routes are loaded');
83 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
84
85 foreach ($routes as $route) {
86 $this->assertSame('/blog/{slug}', $route->getPath());
87 $this->assertSame('{locale}.example.com', $route->getHost());
88 $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller'));
89 $this->assertSame('\w+', $route->getRequirement('locale'));
90 $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
91 $this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
92 $this->assertEquals(array('https'), $route->getSchemes());
93 }
94 }
95
96 public function testLoadWithResource()
97 {
98 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
99 $routeCollection = $loader->load('validresource.yml');
100 $routes = $routeCollection->all();
101
102 $this->assertCount(2, $routes, 'Two routes are loaded');
103 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
104
105 foreach ($routes as $route) {
106 $this->assertSame('/{foo}/blog/{slug}', $route->getPath());
107 $this->assertSame('123', $route->getDefault('foo'));
108 $this->assertSame('\d+', $route->getRequirement('foo'));
109 $this->assertSame('bar', $route->getOption('foo'));
110 $this->assertSame('', $route->getHost());
111 }
112 }
113}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/ApacheUrlMatcherTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/ApacheUrlMatcherTest.php
new file mode 100644
index 00000000..6550911e
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/ApacheUrlMatcherTest.php
@@ -0,0 +1,137 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Matcher;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\RequestContext;
16use Symfony\Component\Routing\Matcher\ApacheUrlMatcher;
17
18class ApacheUrlMatcherTest extends \PHPUnit_Framework_TestCase
19{
20 protected $server;
21
22 protected function setUp()
23 {
24 $this->server = $_SERVER;
25 }
26
27 protected function tearDown()
28 {
29 $_SERVER = $this->server;
30 }
31
32 /**
33 * @dataProvider getMatchData
34 */
35 public function testMatch($name, $pathinfo, $server, $expect)
36 {
37 $collection = new RouteCollection();
38 $context = new RequestContext();
39 $matcher = new ApacheUrlMatcher($collection, $context);
40
41 $_SERVER = $server;
42
43 $result = $matcher->match($pathinfo, $server);
44 $this->assertSame(var_export($expect, true), var_export($result, true));
45 }
46
47 public function getMatchData()
48 {
49 return array(
50 array(
51 'Simple route',
52 '/hello/world',
53 array(
54 '_ROUTING_route' => 'hello',
55 '_ROUTING_param__controller' => 'AcmeBundle:Default:index',
56 '_ROUTING_param_name' => 'world',
57 ),
58 array(
59 '_controller' => 'AcmeBundle:Default:index',
60 'name' => 'world',
61 '_route' => 'hello',
62 ),
63 ),
64 array(
65 'Route with params and defaults',
66 '/hello/hugo',
67 array(
68 '_ROUTING_route' => 'hello',
69 '_ROUTING_param__controller' => 'AcmeBundle:Default:index',
70 '_ROUTING_param_name' => 'hugo',
71 '_ROUTING_default_name' => 'world',
72 ),
73 array(
74 'name' => 'hugo',
75 '_controller' => 'AcmeBundle:Default:index',
76 '_route' => 'hello',
77 ),
78 ),
79 array(
80 'Route with defaults only',
81 '/hello',
82 array(
83 '_ROUTING_route' => 'hello',
84 '_ROUTING_param__controller' => 'AcmeBundle:Default:index',
85 '_ROUTING_default_name' => 'world',
86 ),
87 array(
88 'name' => 'world',
89 '_controller' => 'AcmeBundle:Default:index',
90 '_route' => 'hello',
91 ),
92 ),
93 array(
94 'REDIRECT_ envs',
95 '/hello/world',
96 array(
97 'REDIRECT__ROUTING_route' => 'hello',
98 'REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
99 'REDIRECT__ROUTING_param_name' => 'world',
100 ),
101 array(
102 '_controller' => 'AcmeBundle:Default:index',
103 'name' => 'world',
104 '_route' => 'hello',
105 ),
106 ),
107 array(
108 'REDIRECT_REDIRECT_ envs',
109 '/hello/world',
110 array(
111 'REDIRECT_REDIRECT__ROUTING_route' => 'hello',
112 'REDIRECT_REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
113 'REDIRECT_REDIRECT__ROUTING_param_name' => 'world',
114 ),
115 array(
116 '_controller' => 'AcmeBundle:Default:index',
117 'name' => 'world',
118 '_route' => 'hello',
119 ),
120 ),
121 array(
122 'REDIRECT_REDIRECT_ envs',
123 '/hello/world',
124 array(
125 'REDIRECT_REDIRECT__ROUTING_route' => 'hello',
126 'REDIRECT_REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
127 'REDIRECT_REDIRECT__ROUTING_param_name' => 'world',
128 ),
129 array(
130 '_controller' => 'AcmeBundle:Default:index',
131 'name' => 'world',
132 '_route' => 'hello',
133 ),
134 ),
135 );
136 }
137}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/ApacheMatcherDumperTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/ApacheMatcherDumperTest.php
new file mode 100644
index 00000000..72bee710
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/ApacheMatcherDumperTest.php
@@ -0,0 +1,196 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\RouteCollection;
16use Symfony\Component\Routing\Matcher\Dumper\ApacheMatcherDumper;
17
18class ApacheMatcherDumperTest extends \PHPUnit_Framework_TestCase
19{
20 protected static $fixturesPath;
21
22 public static function setUpBeforeClass()
23 {
24 self::$fixturesPath = realpath(__DIR__.'/../../Fixtures/');
25 }
26
27 public function testDump()
28 {
29 $dumper = new ApacheMatcherDumper($this->getRouteCollection());
30
31 $this->assertStringEqualsFile(self::$fixturesPath.'/dumper/url_matcher1.apache', $dumper->dump(), '->dump() dumps basic routes to the correct apache format.');
32 }
33
34 /**
35 * @dataProvider provideEscapeFixtures
36 */
37 public function testEscapePattern($src, $dest, $char, $with, $message)
38 {
39 $r = new \ReflectionMethod(new ApacheMatcherDumper($this->getRouteCollection()), 'escape');
40 $r->setAccessible(true);
41 $this->assertEquals($dest, $r->invoke(null, $src, $char, $with), $message);
42 }
43
44 public function provideEscapeFixtures()
45 {
46 return array(
47 array('foo', 'foo', ' ', '-', 'Preserve string that should not be escaped'),
48 array('fo-o', 'fo-o', ' ', '-', 'Preserve string that should not be escaped'),
49 array('fo o', 'fo- o', ' ', '-', 'Escape special characters'),
50 array('fo-- o', 'fo--- o', ' ', '-', 'Escape special characters'),
51 array('fo- o', 'fo- o', ' ', '-', 'Do not escape already escaped string'),
52 );
53 }
54
55 public function testEscapeScriptName()
56 {
57 $collection = new RouteCollection();
58 $collection->add('foo', new Route('/foo'));
59 $dumper = new ApacheMatcherDumper($collection);
60 $this->assertStringEqualsFile(self::$fixturesPath.'/dumper/url_matcher2.apache', $dumper->dump(array('script_name' => 'ap p_d\ ev.php')));
61 }
62
63 private function getRouteCollection()
64 {
65 $collection = new RouteCollection();
66
67 // defaults and requirements
68 $collection->add('foo', new Route(
69 '/foo/{bar}',
70 array('def' => 'test'),
71 array('bar' => 'baz|symfony')
72 ));
73 // defaults parameters in pattern
74 $collection->add('foobar', new Route(
75 '/foo/{bar}',
76 array('bar' => 'toto')
77 ));
78 // method requirement
79 $collection->add('bar', new Route(
80 '/bar/{foo}',
81 array(),
82 array('_method' => 'GET|head')
83 ));
84 // method requirement (again)
85 $collection->add('baragain', new Route(
86 '/baragain/{foo}',
87 array(),
88 array('_method' => 'get|post')
89 ));
90 // simple
91 $collection->add('baz', new Route(
92 '/test/baz'
93 ));
94 // simple with extension
95 $collection->add('baz2', new Route(
96 '/test/baz.html'
97 ));
98 // trailing slash
99 $collection->add('baz3', new Route(
100 '/test/baz3/'
101 ));
102 // trailing slash with variable
103 $collection->add('baz4', new Route(
104 '/test/{foo}/'
105 ));
106 // trailing slash and safe method
107 $collection->add('baz5', new Route(
108 '/test/{foo}/',
109 array(),
110 array('_method' => 'get')
111 ));
112 // trailing slash and unsafe method
113 $collection->add('baz5unsafe', new Route(
114 '/testunsafe/{foo}/',
115 array(),
116 array('_method' => 'post')
117 ));
118 // complex
119 $collection->add('baz6', new Route(
120 '/test/baz',
121 array('foo' => 'bar baz')
122 ));
123 // space in path
124 $collection->add('baz7', new Route(
125 '/te st/baz'
126 ));
127 // space preceded with \ in path
128 $collection->add('baz8', new Route(
129 '/te\\ st/baz'
130 ));
131 // space preceded with \ in requirement
132 $collection->add('baz9', new Route(
133 '/test/{baz}',
134 array(),
135 array(
136 'baz' => 'te\\\\ st',
137 )
138 ));
139
140 $collection1 = new RouteCollection();
141
142 $route1 = new Route('/route1', array(), array(), array(), 'a.example.com');
143 $collection1->add('route1', $route1);
144
145 $collection2 = new RouteCollection();
146
147 $route2 = new Route('/route2', array(), array(), array(), 'a.example.com');
148 $collection2->add('route2', $route2);
149
150 $route3 = new Route('/route3', array(), array(), array(), 'b.example.com');
151 $collection2->add('route3', $route3);
152
153 $collection2->addPrefix('/c2');
154 $collection1->addCollection($collection2);
155
156 $route4 = new Route('/route4', array(), array(), array(), 'a.example.com');
157 $collection1->add('route4', $route4);
158
159 $route5 = new Route('/route5', array(), array(), array(), 'c.example.com');
160 $collection1->add('route5', $route5);
161
162 $route6 = new Route('/route6', array(), array(), array(), null);
163 $collection1->add('route6', $route6);
164
165 $collection->addCollection($collection1);
166
167 // host and variables
168
169 $collection1 = new RouteCollection();
170
171 $route11 = new Route('/route11', array(), array(), array(), '{var1}.example.com');
172 $collection1->add('route11', $route11);
173
174 $route12 = new Route('/route12', array('var1' => 'val'), array(), array(), '{var1}.example.com');
175 $collection1->add('route12', $route12);
176
177 $route13 = new Route('/route13/{name}', array(), array(), array(), '{var1}.example.com');
178 $collection1->add('route13', $route13);
179
180 $route14 = new Route('/route14/{name}', array('var1' => 'val'), array(), array(), '{var1}.example.com');
181 $collection1->add('route14', $route14);
182
183 $route15 = new Route('/route15/{name}', array(), array(), array(), 'c.example.com');
184 $collection1->add('route15', $route15);
185
186 $route16 = new Route('/route16/{name}', array('var1' => 'val'), array(), array(), null);
187 $collection1->add('route16', $route16);
188
189 $route17 = new Route('/route17', array(), array(), array(), null);
190 $collection1->add('route17', $route17);
191
192 $collection->addCollection($collection1);
193
194 return $collection;
195 }
196}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperCollectionTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperCollectionTest.php
new file mode 100644
index 00000000..54b37727
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperCollectionTest.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Test\Matcher\Dumper;
13
14use Symfony\Component\Routing\Matcher\Dumper\DumperCollection;
15
16class DumperCollectionTest extends \PHPUnit_Framework_TestCase
17{
18 public function testGetRoot()
19 {
20 $a = new DumperCollection();
21
22 $b = new DumperCollection();
23 $a->add($b);
24
25 $c = new DumperCollection();
26 $b->add($c);
27
28 $d = new DumperCollection();
29 $c->add($d);
30
31 $this->assertSame($a, $c->getRoot());
32 }
33}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php
new file mode 100644
index 00000000..7b4565c4
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php
@@ -0,0 +1,123 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\Matcher\Dumper\DumperPrefixCollection;
16use Symfony\Component\Routing\Matcher\Dumper\DumperRoute;
17use Symfony\Component\Routing\Matcher\Dumper\DumperCollection;
18
19class DumperPrefixCollectionTest extends \PHPUnit_Framework_TestCase
20{
21 public function testAddPrefixRoute()
22 {
23 $coll = new DumperPrefixCollection;
24 $coll->setPrefix('');
25
26 $route = new DumperRoute('bar', new Route('/foo/bar'));
27 $coll = $coll->addPrefixRoute($route);
28
29 $route = new DumperRoute('bar2', new Route('/foo/bar'));
30 $coll = $coll->addPrefixRoute($route);
31
32 $route = new DumperRoute('qux', new Route('/foo/qux'));
33 $coll = $coll->addPrefixRoute($route);
34
35 $route = new DumperRoute('bar3', new Route('/foo/bar'));
36 $coll = $coll->addPrefixRoute($route);
37
38 $route = new DumperRoute('bar4', new Route(''));
39 $result = $coll->addPrefixRoute($route);
40
41 $expect = <<<'EOF'
42 |-coll /
43 | |-coll /f
44 | | |-coll /fo
45 | | | |-coll /foo
46 | | | | |-coll /foo/
47 | | | | | |-coll /foo/b
48 | | | | | | |-coll /foo/ba
49 | | | | | | | |-coll /foo/bar
50 | | | | | | | | |-route bar /foo/bar
51 | | | | | | | | |-route bar2 /foo/bar
52 | | | | | |-coll /foo/q
53 | | | | | | |-coll /foo/qu
54 | | | | | | | |-coll /foo/qux
55 | | | | | | | | |-route qux /foo/qux
56 | | | | | |-coll /foo/b
57 | | | | | | |-coll /foo/ba
58 | | | | | | | |-coll /foo/bar
59 | | | | | | | | |-route bar3 /foo/bar
60 | |-route bar4 /
61
62EOF;
63
64 $this->assertSame($expect, $this->collectionToString($result->getRoot(), ' '));
65 }
66
67 public function testMergeSlashNodes()
68 {
69 $coll = new DumperPrefixCollection;
70 $coll->setPrefix('');
71
72 $route = new DumperRoute('bar', new Route('/foo/bar'));
73 $coll = $coll->addPrefixRoute($route);
74
75 $route = new DumperRoute('bar2', new Route('/foo/bar'));
76 $coll = $coll->addPrefixRoute($route);
77
78 $route = new DumperRoute('qux', new Route('/foo/qux'));
79 $coll = $coll->addPrefixRoute($route);
80
81 $route = new DumperRoute('bar3', new Route('/foo/bar'));
82 $result = $coll->addPrefixRoute($route);
83
84 $result->getRoot()->mergeSlashNodes();
85
86 $expect = <<<'EOF'
87 |-coll /f
88 | |-coll /fo
89 | | |-coll /foo
90 | | | |-coll /foo/b
91 | | | | |-coll /foo/ba
92 | | | | | |-coll /foo/bar
93 | | | | | | |-route bar /foo/bar
94 | | | | | | |-route bar2 /foo/bar
95 | | | |-coll /foo/q
96 | | | | |-coll /foo/qu
97 | | | | | |-coll /foo/qux
98 | | | | | | |-route qux /foo/qux
99 | | | |-coll /foo/b
100 | | | | |-coll /foo/ba
101 | | | | | |-coll /foo/bar
102 | | | | | | |-route bar3 /foo/bar
103
104EOF;
105
106 $this->assertSame($expect, $this->collectionToString($result->getRoot(), ' '));
107 }
108
109 private function collectionToString(DumperCollection $collection, $prefix)
110 {
111 $string = '';
112 foreach ($collection as $route) {
113 if ($route instanceof DumperCollection) {
114 $string .= sprintf("%s|-coll %s\n", $prefix, $route->getPrefix());
115 $string .= $this->collectionToString($route, $prefix.'| ');
116 } else {
117 $string .= sprintf("%s|-route %s %s\n", $prefix, $route->getName(), $route->getRoute()->getPath());
118 }
119 }
120
121 return $string;
122 }
123}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
new file mode 100644
index 00000000..542ede85
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
@@ -0,0 +1,261 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
13
14use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\RouteCollection;
17
18class PhpMatcherDumperTest extends \PHPUnit_Framework_TestCase
19{
20 /**
21 * @expectedException \LogicException
22 */
23 public function testDumpWhenSchemeIsUsedWithoutAProperDumper()
24 {
25 $collection = new RouteCollection();
26 $collection->add('secure', new Route(
27 '/secure',
28 array(),
29 array('_scheme' => 'https')
30 ));
31 $dumper = new PhpMatcherDumper($collection);
32 $dumper->dump();
33 }
34
35 /**
36 * @dataProvider getRouteCollections
37 */
38 public function testDump(RouteCollection $collection, $fixture, $options = array())
39 {
40 $basePath = __DIR__.'/../../Fixtures/dumper/';
41
42 $dumper = new PhpMatcherDumper($collection);
43 $this->assertStringEqualsFile($basePath.$fixture, $dumper->dump($options), '->dump() correctly dumps routes as optimized PHP code.');
44 }
45
46 public function getRouteCollections()
47 {
48 /* test case 1 */
49
50 $collection = new RouteCollection();
51
52 $collection->add('overridden', new Route('/overridden'));
53
54 // defaults and requirements
55 $collection->add('foo', new Route(
56 '/foo/{bar}',
57 array('def' => 'test'),
58 array('bar' => 'baz|symfony')
59 ));
60 // method requirement
61 $collection->add('bar', new Route(
62 '/bar/{foo}',
63 array(),
64 array('_method' => 'GET|head')
65 ));
66 // GET method requirement automatically adds HEAD as valid
67 $collection->add('barhead', new Route(
68 '/barhead/{foo}',
69 array(),
70 array('_method' => 'GET')
71 ));
72 // simple
73 $collection->add('baz', new Route(
74 '/test/baz'
75 ));
76 // simple with extension
77 $collection->add('baz2', new Route(
78 '/test/baz.html'
79 ));
80 // trailing slash
81 $collection->add('baz3', new Route(
82 '/test/baz3/'
83 ));
84 // trailing slash with variable
85 $collection->add('baz4', new Route(
86 '/test/{foo}/'
87 ));
88 // trailing slash and method
89 $collection->add('baz5', new Route(
90 '/test/{foo}/',
91 array(),
92 array('_method' => 'post')
93 ));
94 // complex name
95 $collection->add('baz.baz6', new Route(
96 '/test/{foo}/',
97 array(),
98 array('_method' => 'put')
99 ));
100 // defaults without variable
101 $collection->add('foofoo', new Route(
102 '/foofoo',
103 array('def' => 'test')
104 ));
105 // pattern with quotes
106 $collection->add('quoter', new Route(
107 '/{quoter}',
108 array(),
109 array('quoter' => '[\']+')
110 ));
111 // space in pattern
112 $collection->add('space', new Route(
113 '/spa ce'
114 ));
115
116 // prefixes
117 $collection1 = new RouteCollection();
118 $collection1->add('overridden', new Route('/overridden1'));
119 $collection1->add('foo1', new Route('/{foo}'));
120 $collection1->add('bar1', new Route('/{bar}'));
121 $collection1->addPrefix('/b\'b');
122 $collection2 = new RouteCollection();
123 $collection2->addCollection($collection1);
124 $collection2->add('overridden', new Route('/{var}', array(), array('var' => '.*')));
125 $collection1 = new RouteCollection();
126 $collection1->add('foo2', new Route('/{foo1}'));
127 $collection1->add('bar2', new Route('/{bar1}'));
128 $collection1->addPrefix('/b\'b');
129 $collection2->addCollection($collection1);
130 $collection2->addPrefix('/a');
131 $collection->addCollection($collection2);
132
133 // overridden through addCollection() and multiple sub-collections with no own prefix
134 $collection1 = new RouteCollection();
135 $collection1->add('overridden2', new Route('/old'));
136 $collection1->add('helloWorld', new Route('/hello/{who}', array('who' => 'World!')));
137 $collection2 = new RouteCollection();
138 $collection3 = new RouteCollection();
139 $collection3->add('overridden2', new Route('/new'));
140 $collection3->add('hey', new Route('/hey/'));
141 $collection2->addCollection($collection3);
142 $collection1->addCollection($collection2);
143 $collection1->addPrefix('/multi');
144 $collection->addCollection($collection1);
145
146 // "dynamic" prefix
147 $collection1 = new RouteCollection();
148 $collection1->add('foo3', new Route('/{foo}'));
149 $collection1->add('bar3', new Route('/{bar}'));
150 $collection1->addPrefix('/b');
151 $collection1->addPrefix('{_locale}');
152 $collection->addCollection($collection1);
153
154 // route between collections
155 $collection->add('ababa', new Route('/ababa'));
156
157 // collection with static prefix but only one route
158 $collection1 = new RouteCollection();
159 $collection1->add('foo4', new Route('/{foo}'));
160 $collection1->addPrefix('/aba');
161 $collection->addCollection($collection1);
162
163 // prefix and host
164
165 $collection1 = new RouteCollection();
166
167 $route1 = new Route('/route1', array(), array(), array(), 'a.example.com');
168 $collection1->add('route1', $route1);
169
170 $collection2 = new RouteCollection();
171
172 $route2 = new Route('/c2/route2', array(), array(), array(), 'a.example.com');
173 $collection1->add('route2', $route2);
174
175 $route3 = new Route('/c2/route3', array(), array(), array(), 'b.example.com');
176 $collection1->add('route3', $route3);
177
178 $route4 = new Route('/route4', array(), array(), array(), 'a.example.com');
179 $collection1->add('route4', $route4);
180
181 $route5 = new Route('/route5', array(), array(), array(), 'c.example.com');
182 $collection1->add('route5', $route5);
183
184 $route6 = new Route('/route6', array(), array(), array(), null);
185 $collection1->add('route6', $route6);
186
187 $collection->addCollection($collection1);
188
189 // host and variables
190
191 $collection1 = new RouteCollection();
192
193 $route11 = new Route('/route11', array(), array(), array(), '{var1}.example.com');
194 $collection1->add('route11', $route11);
195
196 $route12 = new Route('/route12', array('var1' => 'val'), array(), array(), '{var1}.example.com');
197 $collection1->add('route12', $route12);
198
199 $route13 = new Route('/route13/{name}', array(), array(), array(), '{var1}.example.com');
200 $collection1->add('route13', $route13);
201
202 $route14 = new Route('/route14/{name}', array('var1' => 'val'), array(), array(), '{var1}.example.com');
203 $collection1->add('route14', $route14);
204
205 $route15 = new Route('/route15/{name}', array(), array(), array(), 'c.example.com');
206 $collection1->add('route15', $route15);
207
208 $route16 = new Route('/route16/{name}', array('var1' => 'val'), array(), array(), null);
209 $collection1->add('route16', $route16);
210
211 $route17 = new Route('/route17', array(), array(), array(), null);
212 $collection1->add('route17', $route17);
213
214 $collection->addCollection($collection1);
215
216 // multiple sub-collections with a single route and a prefix each
217 $collection1 = new RouteCollection();
218 $collection1->add('a', new Route('/a...'));
219 $collection2 = new RouteCollection();
220 $collection2->add('b', new Route('/{var}'));
221 $collection3 = new RouteCollection();
222 $collection3->add('c', new Route('/{var}'));
223 $collection3->addPrefix('/c');
224 $collection2->addCollection($collection3);
225 $collection2->addPrefix('/b');
226 $collection1->addCollection($collection2);
227 $collection1->addPrefix('/a');
228 $collection->addCollection($collection1);
229
230 /* test case 2 */
231
232 $redirectCollection = clone $collection;
233
234 // force HTTPS redirection
235 $redirectCollection->add('secure', new Route(
236 '/secure',
237 array(),
238 array('_scheme' => 'https')
239 ));
240
241 // force HTTP redirection
242 $redirectCollection->add('nonsecure', new Route(
243 '/nonsecure',
244 array(),
245 array('_scheme' => 'http')
246 ));
247
248 /* test case 3 */
249
250 $rootprefixCollection = new RouteCollection();
251 $rootprefixCollection->add('static', new Route('/test'));
252 $rootprefixCollection->add('dynamic', new Route('/{var}'));
253 $rootprefixCollection->addPrefix('rootprefix');
254
255 return array(
256 array($collection, 'url_matcher1.php', array()),
257 array($redirectCollection, 'url_matcher2.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')),
258 array($rootprefixCollection, 'url_matcher3.php', array())
259 );
260 }
261}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php
new file mode 100644
index 00000000..2ad4fc87
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php
@@ -0,0 +1,58 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Matcher;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\RouteCollection;
16use Symfony\Component\Routing\RequestContext;
17
18class RedirectableUrlMatcherTest extends \PHPUnit_Framework_TestCase
19{
20 public function testRedirectWhenNoSlash()
21 {
22 $coll = new RouteCollection();
23 $coll->add('foo', new Route('/foo/'));
24
25 $matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
26 $matcher->expects($this->once())->method('redirect');
27 $matcher->match('/foo');
28 }
29
30 /**
31 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
32 */
33 public function testRedirectWhenNoSlashForNonSafeMethod()
34 {
35 $coll = new RouteCollection();
36 $coll->add('foo', new Route('/foo/'));
37
38 $context = new RequestContext();
39 $context->setMethod('POST');
40 $matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, $context));
41 $matcher->match('/foo');
42 }
43
44 public function testSchemeRedirect()
45 {
46 $coll = new RouteCollection();
47 $coll->add('foo', new Route('/foo', array(), array('_scheme' => 'https')));
48
49 $matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
50 $matcher
51 ->expects($this->once())
52 ->method('redirect')
53 ->with('/foo', 'foo', 'https')
54 ->will($this->returnValue(array('_route' => 'foo')))
55 ;
56 $matcher->match('/foo');
57 }
58}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php
new file mode 100644
index 00000000..86d8d954
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Matcher;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\RouteCollection;
16use Symfony\Component\Routing\RequestContext;
17use Symfony\Component\Routing\Matcher\TraceableUrlMatcher;
18
19class TraceableUrlMatcherTest extends \PHPUnit_Framework_TestCase
20{
21 public function test()
22 {
23 $coll = new RouteCollection();
24 $coll->add('foo', new Route('/foo', array(), array('_method' => 'POST')));
25 $coll->add('bar', new Route('/bar/{id}', array(), array('id' => '\d+')));
26 $coll->add('bar1', new Route('/bar/{name}', array(), array('id' => '\w+', '_method' => 'POST')));
27 $coll->add('bar2', new Route('/foo', array(), array(), array(), 'baz'));
28 $coll->add('bar3', new Route('/foo1', array(), array(), array(), 'baz'));
29
30 $context = new RequestContext();
31 $context->setHost('baz');
32
33 $matcher = new TraceableUrlMatcher($coll, $context);
34 $traces = $matcher->getTraces('/babar');
35 $this->assertEquals(array(0, 0, 0, 0, 0), $this->getLevels($traces));
36
37 $traces = $matcher->getTraces('/foo');
38 $this->assertEquals(array(1, 0, 0, 2), $this->getLevels($traces));
39
40 $traces = $matcher->getTraces('/bar/12');
41 $this->assertEquals(array(0, 2), $this->getLevels($traces));
42
43 $traces = $matcher->getTraces('/bar/dd');
44 $this->assertEquals(array(0, 1, 1, 0, 0), $this->getLevels($traces));
45
46 $traces = $matcher->getTraces('/foo1');
47 $this->assertEquals(array(0, 0, 0, 0, 2), $this->getLevels($traces));
48
49 $context->setMethod('POST');
50 $traces = $matcher->getTraces('/foo');
51 $this->assertEquals(array(2), $this->getLevels($traces));
52
53 $traces = $matcher->getTraces('/bar/dd');
54 $this->assertEquals(array(0, 1, 2), $this->getLevels($traces));
55 }
56
57 public function getLevels($traces)
58 {
59 $levels = array();
60 foreach ($traces as $trace) {
61 $levels[] = $trace['level'];
62 }
63
64 return $levels;
65 }
66}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
new file mode 100644
index 00000000..8a1428f1
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
@@ -0,0 +1,383 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests\Matcher;
13
14use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15use Symfony\Component\Routing\Exception\ResourceNotFoundException;
16use Symfony\Component\Routing\Matcher\UrlMatcher;
17use Symfony\Component\Routing\Route;
18use Symfony\Component\Routing\RouteCollection;
19use Symfony\Component\Routing\RequestContext;
20
21class UrlMatcherTest extends \PHPUnit_Framework_TestCase
22{
23 public function testNoMethodSoAllowed()
24 {
25 $coll = new RouteCollection();
26 $coll->add('foo', new Route('/foo'));
27
28 $matcher = new UrlMatcher($coll, new RequestContext());
29 $matcher->match('/foo');
30 }
31
32 public function testMethodNotAllowed()
33 {
34 $coll = new RouteCollection();
35 $coll->add('foo', new Route('/foo', array(), array('_method' => 'post')));
36
37 $matcher = new UrlMatcher($coll, new RequestContext());
38
39 try {
40 $matcher->match('/foo');
41 $this->fail();
42 } catch (MethodNotAllowedException $e) {
43 $this->assertEquals(array('POST'), $e->getAllowedMethods());
44 }
45 }
46
47 public function testHeadAllowedWhenRequirementContainsGet()
48 {
49 $coll = new RouteCollection();
50 $coll->add('foo', new Route('/foo', array(), array('_method' => 'get')));
51
52 $matcher = new UrlMatcher($coll, new RequestContext('', 'head'));
53 $matcher->match('/foo');
54 }
55
56 public function testMethodNotAllowedAggregatesAllowedMethods()
57 {
58 $coll = new RouteCollection();
59 $coll->add('foo1', new Route('/foo', array(), array('_method' => 'post')));
60 $coll->add('foo2', new Route('/foo', array(), array('_method' => 'put|delete')));
61
62 $matcher = new UrlMatcher($coll, new RequestContext());
63
64 try {
65 $matcher->match('/foo');
66 $this->fail();
67 } catch (MethodNotAllowedException $e) {
68 $this->assertEquals(array('POST', 'PUT', 'DELETE'), $e->getAllowedMethods());
69 }
70 }
71
72 public function testMatch()
73 {
74 // test the patterns are matched and parameters are returned
75 $collection = new RouteCollection();
76 $collection->add('foo', new Route('/foo/{bar}'));
77 $matcher = new UrlMatcher($collection, new RequestContext());
78 try {
79 $matcher->match('/no-match');
80 $this->fail();
81 } catch (ResourceNotFoundException $e) {}
82 $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz'), $matcher->match('/foo/baz'));
83
84 // test that defaults are merged
85 $collection = new RouteCollection();
86 $collection->add('foo', new Route('/foo/{bar}', array('def' => 'test')));
87 $matcher = new UrlMatcher($collection, new RequestContext());
88 $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz', 'def' => 'test'), $matcher->match('/foo/baz'));
89
90 // test that route "method" is ignored if no method is given in the context
91 $collection = new RouteCollection();
92 $collection->add('foo', new Route('/foo', array(), array('_method' => 'GET|head')));
93 $matcher = new UrlMatcher($collection, new RequestContext());
94 $this->assertInternalType('array', $matcher->match('/foo'));
95
96 // route does not match with POST method context
97 $matcher = new UrlMatcher($collection, new RequestContext('', 'post'));
98 try {
99 $matcher->match('/foo');
100 $this->fail();
101 } catch (MethodNotAllowedException $e) {}
102
103 // route does match with GET or HEAD method context
104 $matcher = new UrlMatcher($collection, new RequestContext());
105 $this->assertInternalType('array', $matcher->match('/foo'));
106 $matcher = new UrlMatcher($collection, new RequestContext('', 'head'));
107 $this->assertInternalType('array', $matcher->match('/foo'));
108
109 // route with an optional variable as the first segment
110 $collection = new RouteCollection();
111 $collection->add('bar', new Route('/{bar}/foo', array('bar' => 'bar'), array('bar' => 'foo|bar')));
112 $matcher = new UrlMatcher($collection, new RequestContext());
113 $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/bar/foo'));
114 $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo/foo'));
115
116 $collection = new RouteCollection();
117 $collection->add('bar', new Route('/{bar}', array('bar' => 'bar'), array('bar' => 'foo|bar')));
118 $matcher = new UrlMatcher($collection, new RequestContext());
119 $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo'));
120 $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/'));
121
122 // route with only optional variables
123 $collection = new RouteCollection();
124 $collection->add('bar', new Route('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar'), array()));
125 $matcher = new UrlMatcher($collection, new RequestContext());
126 $this->assertEquals(array('_route' => 'bar', 'foo' => 'foo', 'bar' => 'bar'), $matcher->match('/'));
127 $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'bar'), $matcher->match('/a'));
128 $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'b'), $matcher->match('/a/b'));
129 }
130
131 public function testMatchWithPrefixes()
132 {
133 $collection = new RouteCollection();
134 $collection->add('foo', new Route('/{foo}'));
135 $collection->addPrefix('/b');
136 $collection->addPrefix('/a');
137
138 $matcher = new UrlMatcher($collection, new RequestContext());
139 $this->assertEquals(array('_route' => 'foo', 'foo' => 'foo'), $matcher->match('/a/b/foo'));
140 }
141
142 public function testMatchWithDynamicPrefix()
143 {
144 $collection = new RouteCollection();
145 $collection->add('foo', new Route('/{foo}'));
146 $collection->addPrefix('/b');
147 $collection->addPrefix('/{_locale}');
148
149 $matcher = new UrlMatcher($collection, new RequestContext());
150 $this->assertEquals(array('_locale' => 'fr', '_route' => 'foo', 'foo' => 'foo'), $matcher->match('/fr/b/foo'));
151 }
152
153 public function testMatchSpecialRouteName()
154 {
155 $collection = new RouteCollection();
156 $collection->add('$péß^a|', new Route('/bar'));
157
158 $matcher = new UrlMatcher($collection, new RequestContext());
159 $this->assertEquals(array('_route' => '$péß^a|'), $matcher->match('/bar'));
160 }
161
162 public function testMatchNonAlpha()
163 {
164 $collection = new RouteCollection();
165 $chars = '!"$%éà &\'()*+,./:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\[]^_`abcdefghijklmnopqrstuvwxyz{|}~-';
166 $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '['.preg_quote($chars).']+')));
167
168 $matcher = new UrlMatcher($collection, new RequestContext());
169 $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.rawurlencode($chars).'/bar'));
170 $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.strtr($chars, array('%' => '%25')).'/bar'));
171 }
172
173 public function testMatchWithDotMetacharacterInRequirements()
174 {
175 $collection = new RouteCollection();
176 $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '.+')));
177
178 $matcher = new UrlMatcher($collection, new RequestContext());
179 $this->assertEquals(array('_route' => 'foo', 'foo' => "\n"), $matcher->match('/'.urlencode("\n").'/bar'), 'linefeed character is matched');
180 }
181
182 public function testMatchOverriddenRoute()
183 {
184 $collection = new RouteCollection();
185 $collection->add('foo', new Route('/foo'));
186
187 $collection1 = new RouteCollection();
188 $collection1->add('foo', new Route('/foo1'));
189
190 $collection->addCollection($collection1);
191
192 $matcher = new UrlMatcher($collection, new RequestContext());
193
194 $this->assertEquals(array('_route' => 'foo'), $matcher->match('/foo1'));
195 $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException');
196 $this->assertEquals(array(), $matcher->match('/foo'));
197 }
198
199 public function testMatchRegression()
200 {
201 $coll = new RouteCollection();
202 $coll->add('foo', new Route('/foo/{foo}'));
203 $coll->add('bar', new Route('/foo/bar/{foo}'));
204
205 $matcher = new UrlMatcher($coll, new RequestContext());
206 $this->assertEquals(array('foo' => 'bar', '_route' => 'bar'), $matcher->match('/foo/bar/bar'));
207
208 $collection = new RouteCollection();
209 $collection->add('foo', new Route('/{bar}'));
210 $matcher = new UrlMatcher($collection, new RequestContext());
211 try {
212 $matcher->match('/');
213 $this->fail();
214 } catch (ResourceNotFoundException $e) {
215 }
216 }
217
218 public function testDefaultRequirementForOptionalVariables()
219 {
220 $coll = new RouteCollection();
221 $coll->add('test', new Route('/{page}.{_format}', array('page' => 'index', '_format' => 'html')));
222
223 $matcher = new UrlMatcher($coll, new RequestContext());
224 $this->assertEquals(array('page' => 'my-page', '_format' => 'xml', '_route' => 'test'), $matcher->match('/my-page.xml'));
225 }
226
227 public function testMatchingIsEager()
228 {
229 $coll = new RouteCollection();
230 $coll->add('test', new Route('/{foo}-{bar}-', array(), array('foo' => '.+', 'bar' => '.+')));
231
232 $matcher = new UrlMatcher($coll, new RequestContext());
233 $this->assertEquals(array('foo' => 'text1-text2-text3', 'bar' => 'text4', '_route' => 'test'), $matcher->match('/text1-text2-text3-text4-'));
234 }
235
236 public function testAdjacentVariables()
237 {
238 $coll = new RouteCollection();
239 $coll->add('test', new Route('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => 'y|Y')));
240
241 $matcher = new UrlMatcher($coll, new RequestContext());
242 // 'w' eagerly matches as much as possible and the other variables match the remaining chars.
243 // This also shows that the variables w-z must all exclude the separating char (the dot '.' in this case) by default requirement.
244 // Otherwise they would also consume '.xml' and _format would never match as it's an optional variable.
245 $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'Y', 'z' => 'Z','_format' => 'xml', '_route' => 'test'), $matcher->match('/wwwwwxYZ.xml'));
246 // As 'y' has custom requirement and can only be of value 'y|Y', it will leave 'ZZZ' to variable z.
247 // So with carefully chosen requirements adjacent variables, can be useful.
248 $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'ZZZ','_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxyZZZ'));
249 // z and _format are optional.
250 $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'default-z','_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxy'));
251
252 $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException');
253 $matcher->match('/wxy.html');
254 }
255
256 public function testOptionalVariableWithNoRealSeparator()
257 {
258 $coll = new RouteCollection();
259 $coll->add('test', new Route('/get{what}', array('what' => 'All')));
260 $matcher = new UrlMatcher($coll, new RequestContext());
261
262 $this->assertEquals(array('what' => 'All', '_route' => 'test'), $matcher->match('/get'));
263 $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSites'));
264
265 // Usually the character in front of an optional parameter can be left out, e.g. with pattern '/get/{what}' just '/get' would match.
266 // But here the 't' in 'get' is not a separating character, so it makes no sense to match without it.
267 $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException');
268 $matcher->match('/ge');
269 }
270
271 public function testRequiredVariableWithNoRealSeparator()
272 {
273 $coll = new RouteCollection();
274 $coll->add('test', new Route('/get{what}Suffix'));
275 $matcher = new UrlMatcher($coll, new RequestContext());
276
277 $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSitesSuffix'));
278 }
279
280 public function testDefaultRequirementOfVariable()
281 {
282 $coll = new RouteCollection();
283 $coll->add('test', new Route('/{page}.{_format}'));
284 $matcher = new UrlMatcher($coll, new RequestContext());
285
286 $this->assertEquals(array('page' => 'index', '_format' => 'mobile.html', '_route' => 'test'), $matcher->match('/index.mobile.html'));
287 }
288
289 /**
290 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
291 */
292 public function testDefaultRequirementOfVariableDisallowsSlash()
293 {
294 $coll = new RouteCollection();
295 $coll->add('test', new Route('/{page}.{_format}'));
296 $matcher = new UrlMatcher($coll, new RequestContext());
297
298 $matcher->match('/index.sl/ash');
299 }
300
301 /**
302 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
303 */
304 public function testDefaultRequirementOfVariableDisallowsNextSeparator()
305 {
306 $coll = new RouteCollection();
307 $coll->add('test', new Route('/{page}.{_format}', array(), array('_format' => 'html|xml')));
308 $matcher = new UrlMatcher($coll, new RequestContext());
309
310 $matcher->match('/do.t.html');
311 }
312
313 /**
314 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
315 */
316 public function testSchemeRequirement()
317 {
318 $coll = new RouteCollection();
319 $coll->add('foo', new Route('/foo', array(), array('_scheme' => 'https')));
320 $matcher = new UrlMatcher($coll, new RequestContext());
321 $matcher->match('/foo');
322 }
323
324 public function testDecodeOnce()
325 {
326 $coll = new RouteCollection();
327 $coll->add('foo', new Route('/foo/{foo}'));
328
329 $matcher = new UrlMatcher($coll, new RequestContext());
330 $this->assertEquals(array('foo' => 'bar%23', '_route' => 'foo'), $matcher->match('/foo/bar%2523'));
331 }
332
333 public function testCannotRelyOnPrefix()
334 {
335 $coll = new RouteCollection();
336
337 $subColl = new RouteCollection();
338 $subColl->add('bar', new Route('/bar'));
339 $subColl->addPrefix('/prefix');
340 // overwrite the pattern, so the prefix is not valid anymore for this route in the collection
341 $subColl->get('bar')->setPattern('/new');
342
343 $coll->addCollection($subColl);
344
345 $matcher = new UrlMatcher($coll, new RequestContext());
346 $this->assertEquals(array('_route' => 'bar'), $matcher->match('/new'));
347 }
348
349 public function testWithHost()
350 {
351 $coll = new RouteCollection();
352 $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com'));
353
354 $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
355 $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar'));
356 }
357
358 public function testWithHostOnRouteCollection()
359 {
360 $coll = new RouteCollection();
361 $coll->add('foo', new Route('/foo/{foo}'));
362 $coll->add('bar', new Route('/bar/{foo}', array(), array(), array(), '{locale}.example.net'));
363 $coll->setHost('{locale}.example.com');
364
365 $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
366 $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar'));
367
368 $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
369 $this->assertEquals(array('foo' => 'bar', '_route' => 'bar', 'locale' => 'en'), $matcher->match('/bar/bar'));
370 }
371
372 /**
373 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
374 */
375 public function testWithOutHostHostDoesNotMatch()
376 {
377 $coll = new RouteCollection();
378 $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com'));
379
380 $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'example.com'));
381 $matcher->match('/foo/bar');
382 }
383}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCollectionTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCollectionTest.php
new file mode 100644
index 00000000..3d78adf9
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCollectionTest.php
@@ -0,0 +1,255 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Config\Resource\FileResource;
17
18class RouteCollectionTest extends \PHPUnit_Framework_TestCase
19{
20 public function testRoute()
21 {
22 $collection = new RouteCollection();
23 $route = new Route('/foo');
24 $collection->add('foo', $route);
25 $this->assertEquals(array('foo' => $route), $collection->all(), '->add() adds a route');
26 $this->assertEquals($route, $collection->get('foo'), '->get() returns a route by name');
27 $this->assertNull($collection->get('bar'), '->get() returns null if a route does not exist');
28 }
29
30 public function testOverriddenRoute()
31 {
32 $collection = new RouteCollection();
33 $collection->add('foo', new Route('/foo'));
34 $collection->add('foo', new Route('/foo1'));
35
36 $this->assertEquals('/foo1', $collection->get('foo')->getPath());
37 }
38
39 public function testDeepOverriddenRoute()
40 {
41 $collection = new RouteCollection();
42 $collection->add('foo', new Route('/foo'));
43
44 $collection1 = new RouteCollection();
45 $collection1->add('foo', new Route('/foo1'));
46
47 $collection2 = new RouteCollection();
48 $collection2->add('foo', new Route('/foo2'));
49
50 $collection1->addCollection($collection2);
51 $collection->addCollection($collection1);
52
53 $this->assertEquals('/foo2', $collection1->get('foo')->getPath());
54 $this->assertEquals('/foo2', $collection->get('foo')->getPath());
55 }
56
57 public function testIterator()
58 {
59 $collection = new RouteCollection();
60 $collection->add('foo', new Route('/foo'));
61
62 $collection1 = new RouteCollection();
63 $collection1->add('bar', $bar = new Route('/bar'));
64 $collection1->add('foo', $foo = new Route('/foo-new'));
65 $collection->addCollection($collection1);
66 $collection->add('last', $last = new Route('/last'));
67
68 $this->assertInstanceOf('\ArrayIterator', $collection->getIterator());
69 $this->assertSame(array('bar' => $bar, 'foo' => $foo, 'last' => $last), $collection->getIterator()->getArrayCopy());
70 }
71
72 public function testCount()
73 {
74 $collection = new RouteCollection();
75 $collection->add('foo', new Route('/foo'));
76
77 $collection1 = new RouteCollection();
78 $collection1->add('bar', new Route('/bar'));
79 $collection->addCollection($collection1);
80
81 $this->assertCount(2, $collection);
82 }
83
84 public function testAddCollection()
85 {
86 $collection = new RouteCollection();
87 $collection->add('foo', new Route('/foo'));
88
89 $collection1 = new RouteCollection();
90 $collection1->add('bar', $bar = new Route('/bar'));
91 $collection1->add('foo', $foo = new Route('/foo-new'));
92
93 $collection2 = new RouteCollection();
94 $collection2->add('grandchild', $grandchild = new Route('/grandchild'));
95
96 $collection1->addCollection($collection2);
97 $collection->addCollection($collection1);
98 $collection->add('last', $last = new Route('/last'));
99
100 $this->assertSame(array('bar' => $bar, 'foo' => $foo, 'grandchild' => $grandchild, 'last' => $last), $collection->all(),
101 '->addCollection() imports routes of another collection, overrides if necessary and adds them at the end');
102 }
103
104 public function testAddCollectionWithResources()
105 {
106 if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
107 $this->markTestSkipped('The "Config" component is not available');
108 }
109
110 $collection = new RouteCollection();
111 $collection->addResource($foo = new FileResource(__DIR__.'/Fixtures/foo.xml'));
112 $collection1 = new RouteCollection();
113 $collection1->addResource($foo1 = new FileResource(__DIR__.'/Fixtures/foo1.xml'));
114 $collection->addCollection($collection1);
115 $this->assertEquals(array($foo, $foo1), $collection->getResources(), '->addCollection() merges resources');
116 }
117
118 public function testAddDefaultsAndRequirementsAndOptions()
119 {
120 $collection = new RouteCollection();
121 $collection->add('foo', new Route('/{placeholder}'));
122 $collection1 = new RouteCollection();
123 $collection1->add('bar', new Route('/{placeholder}',
124 array('_controller' => 'fixed', 'placeholder' => 'default'), array('placeholder' => '.+'), array('option' => 'value'))
125 );
126 $collection->addCollection($collection1);
127
128 $collection->addDefaults(array('placeholder' => 'new-default'));
129 $this->assertEquals(array('placeholder' => 'new-default'), $collection->get('foo')->getDefaults(), '->addDefaults() adds defaults to all routes');
130 $this->assertEquals(array('_controller' => 'fixed', 'placeholder' => 'new-default'), $collection->get('bar')->getDefaults(),
131 '->addDefaults() adds defaults to all routes and overwrites existing ones');
132
133 $collection->addRequirements(array('placeholder' => '\d+'));
134 $this->assertEquals(array('placeholder' => '\d+'), $collection->get('foo')->getRequirements(), '->addRequirements() adds requirements to all routes');
135 $this->assertEquals(array('placeholder' => '\d+'), $collection->get('bar')->getRequirements(),
136 '->addRequirements() adds requirements to all routes and overwrites existing ones');
137
138 $collection->addOptions(array('option' => 'new-value'));
139 $this->assertEquals(
140 array('option' => 'new-value', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'),
141 $collection->get('bar')->getOptions(), '->addOptions() adds options to all routes and overwrites existing ones'
142 );
143 }
144
145 public function testAddPrefix()
146 {
147 $collection = new RouteCollection();
148 $collection->add('foo', $foo = new Route('/foo'));
149 $collection2 = new RouteCollection();
150 $collection2->add('bar', $bar = new Route('/bar'));
151 $collection->addCollection($collection2);
152 $collection->addPrefix(' / ');
153 $this->assertSame('/foo', $collection->get('foo')->getPattern(), '->addPrefix() trims the prefix and a single slash has no effect');
154 $collection->addPrefix('/{admin}', array('admin' => 'admin'), array('admin' => '\d+'));
155 $this->assertEquals('/{admin}/foo', $collection->get('foo')->getPath(), '->addPrefix() adds a prefix to all routes');
156 $this->assertEquals('/{admin}/bar', $collection->get('bar')->getPath(), '->addPrefix() adds a prefix to all routes');
157 $this->assertEquals(array('admin' => 'admin'), $collection->get('foo')->getDefaults(), '->addPrefix() adds defaults to all routes');
158 $this->assertEquals(array('admin' => 'admin'), $collection->get('bar')->getDefaults(), '->addPrefix() adds defaults to all routes');
159 $this->assertEquals(array('admin' => '\d+'), $collection->get('foo')->getRequirements(), '->addPrefix() adds requirements to all routes');
160 $this->assertEquals(array('admin' => '\d+'), $collection->get('bar')->getRequirements(), '->addPrefix() adds requirements to all routes');
161 $collection->addPrefix('0');
162 $this->assertEquals('/0/{admin}/foo', $collection->get('foo')->getPattern(), '->addPrefix() ensures a prefix must start with a slash and must not end with a slash');
163 $collection->addPrefix('/ /');
164 $this->assertSame('/ /0/{admin}/foo', $collection->get('foo')->getPath(), '->addPrefix() can handle spaces if desired');
165 $this->assertSame('/ /0/{admin}/bar', $collection->get('bar')->getPath(), 'the route pattern of an added collection is in synch with the added prefix');
166 }
167
168 public function testAddPrefixOverridesDefaultsAndRequirements()
169 {
170 $collection = new RouteCollection();
171 $collection->add('foo', $foo = new Route('/foo'));
172 $collection->add('bar', $bar = new Route('/bar', array(), array('_scheme' => 'http')));
173 $collection->addPrefix('/admin', array(), array('_scheme' => 'https'));
174
175 $this->assertEquals('https', $collection->get('foo')->getRequirement('_scheme'), '->addPrefix() overrides existing requirements');
176 $this->assertEquals('https', $collection->get('bar')->getRequirement('_scheme'), '->addPrefix() overrides existing requirements');
177 }
178
179 public function testResource()
180 {
181 if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
182 $this->markTestSkipped('The "Config" component is not available');
183 }
184
185 $collection = new RouteCollection();
186 $collection->addResource($foo = new FileResource(__DIR__.'/Fixtures/foo.xml'));
187 $collection->addResource($bar = new FileResource(__DIR__.'/Fixtures/bar.xml'));
188 $collection->addResource(new FileResource(__DIR__.'/Fixtures/foo.xml'));
189
190 $this->assertEquals(array($foo, $bar), $collection->getResources(),
191 '->addResource() adds a resource and getResources() only returns unique ones by comparing the string representation');
192 }
193
194 public function testUniqueRouteWithGivenName()
195 {
196 $collection1 = new RouteCollection();
197 $collection1->add('foo', new Route('/old'));
198 $collection2 = new RouteCollection();
199 $collection3 = new RouteCollection();
200 $collection3->add('foo', $new = new Route('/new'));
201
202 $collection2->addCollection($collection3);
203 $collection1->addCollection($collection2);
204
205 $this->assertSame($new, $collection1->get('foo'), '->get() returns new route that overrode previous one');
206 // size of 1 because collection1 contains /new but not /old anymore
207 $this->assertCount(1, $collection1->getIterator(), '->addCollection() removes previous routes when adding new routes with the same name');
208 }
209
210 public function testGet()
211 {
212 $collection1 = new RouteCollection();
213 $collection1->add('a', $a = new Route('/a'));
214 $collection2 = new RouteCollection();
215 $collection2->add('b', $b = new Route('/b'));
216 $collection1->addCollection($collection2);
217 $collection1->add('$péß^a|', $c = new Route('/special'));
218
219 $this->assertSame($b, $collection1->get('b'), '->get() returns correct route in child collection');
220 $this->assertSame($c, $collection1->get('$péß^a|'), '->get() can handle special characters');
221 $this->assertNull($collection2->get('a'), '->get() does not return the route defined in parent collection');
222 $this->assertNull($collection1->get('non-existent'), '->get() returns null when route does not exist');
223 $this->assertNull($collection1->get(0), '->get() does not disclose internal child RouteCollection');
224 }
225
226 public function testRemove()
227 {
228 $collection = new RouteCollection();
229 $collection->add('foo', $foo = new Route('/foo'));
230
231 $collection1 = new RouteCollection();
232 $collection1->add('bar', $bar = new Route('/bar'));
233 $collection->addCollection($collection1);
234 $collection->add('last', $last = new Route('/last'));
235
236 $collection->remove('foo');
237 $this->assertSame(array('bar' => $bar, 'last' => $last), $collection->all(), '->remove() can remove a single route');
238 $collection->remove(array('bar', 'last'));
239 $this->assertSame(array(), $collection->all(), '->remove() accepts an array and can remove multiple routes at once');
240 }
241
242 public function testSetHost()
243 {
244 $collection = new RouteCollection();
245 $routea = new Route('/a');
246 $routeb = new Route('/b', array(), array(), array(), '{locale}.example.net');
247 $collection->add('a', $routea);
248 $collection->add('b', $routeb);
249
250 $collection->setHost('{locale}.example.com');
251
252 $this->assertEquals('{locale}.example.com', $routea->getHost());
253 $this->assertEquals('{locale}.example.com', $routeb->getHost());
254 }
255}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCompilerTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCompilerTest.php
new file mode 100644
index 00000000..d663ae96
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCompilerTest.php
@@ -0,0 +1,253 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\Route;
15
16class RouteCompilerTest extends \PHPUnit_Framework_TestCase
17{
18 /**
19 * @dataProvider provideCompileData
20 */
21 public function testCompile($name, $arguments, $prefix, $regex, $variables, $tokens)
22 {
23 $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route');
24 $route = $r->newInstanceArgs($arguments);
25
26 $compiled = $route->compile();
27 $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)');
28 $this->assertEquals($regex, $compiled->getRegex(), $name.' (regex)');
29 $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)');
30 $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)');
31 }
32
33 public function provideCompileData()
34 {
35 return array(
36 array(
37 'Static route',
38 array('/foo'),
39 '/foo', '#^/foo$#s', array(), array(
40 array('text', '/foo'),
41 )),
42
43 array(
44 'Route with a variable',
45 array('/foo/{bar}'),
46 '/foo', '#^/foo/(?P<bar>[^/]++)$#s', array('bar'), array(
47 array('variable', '/', '[^/]++', 'bar'),
48 array('text', '/foo'),
49 )),
50
51 array(
52 'Route with a variable that has a default value',
53 array('/foo/{bar}', array('bar' => 'bar')),
54 '/foo', '#^/foo(?:/(?P<bar>[^/]++))?$#s', array('bar'), array(
55 array('variable', '/', '[^/]++', 'bar'),
56 array('text', '/foo'),
57 )),
58
59 array(
60 'Route with several variables',
61 array('/foo/{bar}/{foobar}'),
62 '/foo', '#^/foo/(?P<bar>[^/]++)/(?P<foobar>[^/]++)$#s', array('bar', 'foobar'), array(
63 array('variable', '/', '[^/]++', 'foobar'),
64 array('variable', '/', '[^/]++', 'bar'),
65 array('text', '/foo'),
66 )),
67
68 array(
69 'Route with several variables that have default values',
70 array('/foo/{bar}/{foobar}', array('bar' => 'bar', 'foobar' => '')),
71 '/foo', '#^/foo(?:/(?P<bar>[^/]++)(?:/(?P<foobar>[^/]++))?)?$#s', array('bar', 'foobar'), array(
72 array('variable', '/', '[^/]++', 'foobar'),
73 array('variable', '/', '[^/]++', 'bar'),
74 array('text', '/foo'),
75 )),
76
77 array(
78 'Route with several variables but some of them have no default values',
79 array('/foo/{bar}/{foobar}', array('bar' => 'bar')),
80 '/foo', '#^/foo/(?P<bar>[^/]++)/(?P<foobar>[^/]++)$#s', array('bar', 'foobar'), array(
81 array('variable', '/', '[^/]++', 'foobar'),
82 array('variable', '/', '[^/]++', 'bar'),
83 array('text', '/foo'),
84 )),
85
86 array(
87 'Route with an optional variable as the first segment',
88 array('/{bar}', array('bar' => 'bar')),
89 '', '#^/(?P<bar>[^/]++)?$#s', array('bar'), array(
90 array('variable', '/', '[^/]++', 'bar'),
91 )),
92
93 array(
94 'Route with a requirement of 0',
95 array('/{bar}', array('bar' => null), array('bar' => '0')),
96 '', '#^/(?P<bar>0)?$#s', array('bar'), array(
97 array('variable', '/', '0', 'bar'),
98 )),
99
100 array(
101 'Route with an optional variable as the first segment with requirements',
102 array('/{bar}', array('bar' => 'bar'), array('bar' => '(foo|bar)')),
103 '', '#^/(?P<bar>(foo|bar))?$#s', array('bar'), array(
104 array('variable', '/', '(foo|bar)', 'bar'),
105 )),
106
107 array(
108 'Route with only optional variables',
109 array('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar')),
110 '', '#^/(?P<foo>[^/]++)?(?:/(?P<bar>[^/]++))?$#s', array('foo', 'bar'), array(
111 array('variable', '/', '[^/]++', 'bar'),
112 array('variable', '/', '[^/]++', 'foo'),
113 )),
114
115 array(
116 'Route with a variable in last position',
117 array('/foo-{bar}'),
118 '/foo', '#^/foo\-(?P<bar>[^/]++)$#s', array('bar'), array(
119 array('variable', '-', '[^/]++', 'bar'),
120 array('text', '/foo'),
121 )),
122
123 array(
124 'Route with nested placeholders',
125 array('/{static{var}static}'),
126 '/{static', '#^/\{static(?P<var>[^/]+)static\}$#s', array('var'), array(
127 array('text', 'static}'),
128 array('variable', '', '[^/]+', 'var'),
129 array('text', '/{static'),
130 )),
131
132 array(
133 'Route without separator between variables',
134 array('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '(y|Y)')),
135 '', '#^/(?P<w>[^/\.]+)(?P<x>[^/\.]+)(?P<y>(y|Y))(?:(?P<z>[^/\.]++)(?:\.(?P<_format>[^/]++))?)?$#s', array('w', 'x', 'y', 'z', '_format'), array(
136 array('variable', '.', '[^/]++', '_format'),
137 array('variable', '', '[^/\.]++', 'z'),
138 array('variable', '', '(y|Y)', 'y'),
139 array('variable', '', '[^/\.]+', 'x'),
140 array('variable', '/', '[^/\.]+', 'w'),
141 )),
142
143 array(
144 'Route with a format',
145 array('/foo/{bar}.{_format}'),
146 '/foo', '#^/foo/(?P<bar>[^/\.]++)\.(?P<_format>[^/]++)$#s', array('bar', '_format'), array(
147 array('variable', '.', '[^/]++', '_format'),
148 array('variable', '/', '[^/\.]++', 'bar'),
149 array('text', '/foo'),
150 )),
151 );
152 }
153
154 /**
155 * @expectedException \LogicException
156 */
157 public function testRouteWithSameVariableTwice()
158 {
159 $route = new Route('/{name}/{name}');
160
161 $compiled = $route->compile();
162 }
163
164 /**
165 * @dataProvider getNumericVariableNames
166 * @expectedException \DomainException
167 */
168 public function testRouteWithNumericVariableName($name)
169 {
170 $route = new Route('/{'. $name.'}');
171 $route->compile();
172 }
173
174 public function getNumericVariableNames()
175 {
176 return array(
177 array('09'),
178 array('123'),
179 array('1e2')
180 );
181 }
182
183 /**
184 * @dataProvider provideCompileWithHostData
185 */
186 public function testCompileWithHost($name, $arguments, $prefix, $regex, $variables, $pathVariables, $tokens, $hostRegex, $hostVariables, $hostTokens)
187 {
188 $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route');
189 $route = $r->newInstanceArgs($arguments);
190
191 $compiled = $route->compile();
192 $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)');
193 $this->assertEquals($regex, str_replace(array("\n", ' '), '', $compiled->getRegex()), $name.' (regex)');
194 $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)');
195 $this->assertEquals($pathVariables, $compiled->getPathVariables(), $name.' (path variables)');
196 $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)');
197 $this->assertEquals($hostRegex, str_replace(array("\n", ' '), '', $compiled->getHostRegex()), $name.' (host regex)');
198 $this->assertEquals($hostVariables, $compiled->getHostVariables(), $name.' (host variables)');
199 $this->assertEquals($hostTokens, $compiled->getHostTokens(), $name.' (host tokens)');
200 }
201
202 public function provideCompileWithHostData()
203 {
204 return array(
205 array(
206 'Route with host pattern',
207 array('/hello', array(), array(), array(), 'www.example.com'),
208 '/hello', '#^/hello$#s', array(), array(), array(
209 array('text', '/hello'),
210 ),
211 '#^www\.example\.com$#s', array(), array(
212 array('text', 'www.example.com'),
213 ),
214 ),
215 array(
216 'Route with host pattern and some variables',
217 array('/hello/{name}', array(), array(), array(), 'www.example.{tld}'),
218 '/hello', '#^/hello/(?P<name>[^/]++)$#s', array('tld', 'name'), array('name'), array(
219 array('variable', '/', '[^/]++', 'name'),
220 array('text', '/hello'),
221 ),
222 '#^www\.example\.(?P<tld>[^\.]++)$#s', array('tld'), array(
223 array('variable', '.', '[^\.]++', 'tld'),
224 array('text', 'www.example'),
225 ),
226 ),
227 array(
228 'Route with variable at beginning of host',
229 array('/hello', array(), array(), array(), '{locale}.example.{tld}'),
230 '/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
231 array('text', '/hello'),
232 ),
233 '#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#s', array('locale', 'tld'), array(
234 array('variable', '.', '[^\.]++', 'tld'),
235 array('text', '.example'),
236 array('variable', '', '[^\.]++', 'locale'),
237 ),
238 ),
239 array(
240 'Route with host variables that has a default value',
241 array('/hello', array('locale' => 'a', 'tld' => 'b'), array(), array(), '{locale}.example.{tld}'),
242 '/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
243 array('text', '/hello'),
244 ),
245 '#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#s', array('locale', 'tld'), array(
246 array('variable', '.', '[^\.]++', 'tld'),
247 array('text', '.example'),
248 array('variable', '', '[^\.]++', 'locale'),
249 ),
250 ),
251 );
252 }
253}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteTest.php
new file mode 100644
index 00000000..31f1066f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteTest.php
@@ -0,0 +1,192 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\Route;
15
16class RouteTest extends \PHPUnit_Framework_TestCase
17{
18 public function testConstructor()
19 {
20 $route = new Route('/{foo}', array('foo' => 'bar'), array('foo' => '\d+'), array('foo' => 'bar'), '{locale}.example.com');
21 $this->assertEquals('/{foo}', $route->getPath(), '__construct() takes a path as its first argument');
22 $this->assertEquals(array('foo' => 'bar'), $route->getDefaults(), '__construct() takes defaults as its second argument');
23 $this->assertEquals(array('foo' => '\d+'), $route->getRequirements(), '__construct() takes requirements as its third argument');
24 $this->assertEquals('bar', $route->getOption('foo'), '__construct() takes options as its fourth argument');
25 $this->assertEquals('{locale}.example.com', $route->getHost(), '__construct() takes a host pattern as its fifth argument');
26
27 $route = new Route('/', array(), array(), array(), '', array('Https'), array('POST', 'put'));
28 $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes schemes as its sixth argument and lowercases it');
29 $this->assertEquals(array('POST', 'PUT'), $route->getMethods(), '__construct() takes methods as its seventh argument and uppercases it');
30
31 $route = new Route('/', array(), array(), array(), '', 'Https', 'Post');
32 $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes a single scheme as its sixth argument');
33 $this->assertEquals(array('POST'), $route->getMethods(), '__construct() takes a single method as its seventh argument');
34 }
35
36 public function testPath()
37 {
38 $route = new Route('/{foo}');
39 $route->setPath('/{bar}');
40 $this->assertEquals('/{bar}', $route->getPath(), '->setPath() sets the path');
41 $route->setPath('');
42 $this->assertEquals('/', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed');
43 $route->setPath('bar');
44 $this->assertEquals('/bar', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed');
45 $this->assertEquals($route, $route->setPath(''), '->setPath() implements a fluent interface');
46 $route->setPath('//path');
47 $this->assertEquals('/path', $route->getPath(), '->setPath() does not allow two slahes "//" at the beginning of the path as it would be confused with a network path when generating the path from the route');
48 }
49
50 public function testOptions()
51 {
52 $route = new Route('/{foo}');
53 $route->setOptions(array('foo' => 'bar'));
54 $this->assertEquals(array_merge(array(
55 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
56 ), array('foo' => 'bar')), $route->getOptions(), '->setOptions() sets the options');
57 $this->assertEquals($route, $route->setOptions(array()), '->setOptions() implements a fluent interface');
58
59 $route->setOptions(array('foo' => 'foo'));
60 $route->addOptions(array('bar' => 'bar'));
61 $this->assertEquals($route, $route->addOptions(array()), '->addOptions() implements a fluent interface');
62 $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'), $route->getOptions(), '->addDefaults() keep previous defaults');
63 }
64
65 public function testDefaults()
66 {
67 $route = new Route('/{foo}');
68 $route->setDefaults(array('foo' => 'bar'));
69 $this->assertEquals(array('foo' => 'bar'), $route->getDefaults(), '->setDefaults() sets the defaults');
70 $this->assertEquals($route, $route->setDefaults(array()), '->setDefaults() implements a fluent interface');
71
72 $route->setDefault('foo', 'bar');
73 $this->assertEquals('bar', $route->getDefault('foo'), '->setDefault() sets a default value');
74
75 $route->setDefault('foo2', 'bar2');
76 $this->assertEquals('bar2', $route->getDefault('foo2'), '->getDefault() return the default value');
77 $this->assertNull($route->getDefault('not_defined'), '->getDefault() return null if default value is not setted');
78
79 $route->setDefault('_controller', $closure = function () { return 'Hello'; });
80 $this->assertEquals($closure, $route->getDefault('_controller'), '->setDefault() sets a default value');
81
82 $route->setDefaults(array('foo' => 'foo'));
83 $route->addDefaults(array('bar' => 'bar'));
84 $this->assertEquals($route, $route->addDefaults(array()), '->addDefaults() implements a fluent interface');
85 $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar'), $route->getDefaults(), '->addDefaults() keep previous defaults');
86 }
87
88 public function testRequirements()
89 {
90 $route = new Route('/{foo}');
91 $route->setRequirements(array('foo' => '\d+'));
92 $this->assertEquals(array('foo' => '\d+'), $route->getRequirements(), '->setRequirements() sets the requirements');
93 $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() returns a requirement');
94 $this->assertNull($route->getRequirement('bar'), '->getRequirement() returns null if a requirement is not defined');
95 $route->setRequirements(array('foo' => '^\d+$'));
96 $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() removes ^ and $ from the path');
97 $this->assertEquals($route, $route->setRequirements(array()), '->setRequirements() implements a fluent interface');
98
99 $route->setRequirements(array('foo' => '\d+'));
100 $route->addRequirements(array('bar' => '\d+'));
101 $this->assertEquals($route, $route->addRequirements(array()), '->addRequirements() implements a fluent interface');
102 $this->assertEquals(array('foo' => '\d+', 'bar' => '\d+'), $route->getRequirements(), '->addRequirement() keep previous requirements');
103 }
104
105 public function testRequirement()
106 {
107 $route = new Route('/{foo}');
108 $route->setRequirement('foo', '^\d+$');
109 $this->assertEquals('\d+', $route->getRequirement('foo'), '->setRequirement() removes ^ and $ from the path');
110 }
111
112 /**
113 * @dataProvider getInvalidRequirements
114 * @expectedException \InvalidArgumentException
115 */
116 public function testSetInvalidRequirement($req)
117 {
118 $route = new Route('/{foo}');
119 $route->setRequirement('foo', $req);
120 }
121
122 public function getInvalidRequirements()
123 {
124 return array(
125 array(''),
126 array(array()),
127 array('^$'),
128 array('^'),
129 array('$')
130 );
131 }
132
133 public function testHost()
134 {
135 $route = new Route('/');
136 $route->setHost('{locale}.example.net');
137 $this->assertEquals('{locale}.example.net', $route->getHost(), '->setHost() sets the host pattern');
138 }
139
140 public function testScheme()
141 {
142 $route = new Route('/');
143 $this->assertEquals(array(), $route->getSchemes(), 'schemes is initialized with array()');
144 $route->setSchemes('hTTp');
145 $this->assertEquals(array('http'), $route->getSchemes(), '->setSchemes() accepts a single scheme string and lowercases it');
146 $route->setSchemes(array('HttpS', 'hTTp'));
147 $this->assertEquals(array('https', 'http'), $route->getSchemes(), '->setSchemes() accepts an array of schemes and lowercases them');
148 }
149
150 public function testSchemeIsBC()
151 {
152 $route = new Route('/');
153 $route->setRequirement('_scheme', 'http|https');
154 $this->assertEquals('http|https', $route->getRequirement('_scheme'));
155 $this->assertEquals(array('http', 'https'), $route->getSchemes());
156 $route->setSchemes(array('hTTp'));
157 $this->assertEquals('http', $route->getRequirement('_scheme'));
158 $route->setSchemes(array());
159 $this->assertNull($route->getRequirement('_scheme'));
160 }
161
162 public function testMethod()
163 {
164 $route = new Route('/');
165 $this->assertEquals(array(), $route->getMethods(), 'methods is initialized with array()');
166 $route->setMethods('gEt');
167 $this->assertEquals(array('GET'), $route->getMethods(), '->setMethods() accepts a single method string and uppercases it');
168 $route->setMethods(array('gEt', 'PosT'));
169 $this->assertEquals(array('GET', 'POST'), $route->getMethods(), '->setMethods() accepts an array of methods and uppercases them');
170 }
171
172 public function testMethodIsBC()
173 {
174 $route = new Route('/');
175 $route->setRequirement('_method', 'GET|POST');
176 $this->assertEquals('GET|POST', $route->getRequirement('_method'));
177 $this->assertEquals(array('GET', 'POST'), $route->getMethods());
178 $route->setMethods(array('gEt'));
179 $this->assertEquals('GET', $route->getRequirement('_method'));
180 $route->setMethods(array());
181 $this->assertNull($route->getRequirement('_method'));
182 }
183
184 public function testCompile()
185 {
186 $route = new Route('/{foo}');
187 $this->assertInstanceOf('Symfony\Component\Routing\CompiledRoute', $compiled = $route->compile(), '->compile() returns a compiled route');
188 $this->assertSame($compiled, $route->compile(), '->compile() only compiled the route once if unchanged');
189 $route->setRequirement('foo', '.*');
190 $this->assertNotSame($compiled, $route->compile(), '->compile() recompiles if the route was modified');
191 }
192}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouterTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouterTest.php
new file mode 100644
index 00000000..a3c336e5
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouterTest.php
@@ -0,0 +1,138 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\Router;
15
16class RouterTest extends \PHPUnit_Framework_TestCase
17{
18 private $router = null;
19
20 private $loader = null;
21
22 protected function setUp()
23 {
24 $this->loader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
25 $this->router = new Router($this->loader, 'routing.yml');
26 }
27
28 public function testSetOptionsWithSupportedOptions()
29 {
30 $this->router->setOptions(array(
31 'cache_dir' => './cache',
32 'debug' => true,
33 'resource_type' => 'ResourceType'
34 ));
35
36 $this->assertSame('./cache', $this->router->getOption('cache_dir'));
37 $this->assertTrue($this->router->getOption('debug'));
38 $this->assertSame('ResourceType', $this->router->getOption('resource_type'));
39 }
40
41 /**
42 * @expectedException \InvalidArgumentException
43 * @expectedExceptionMessage The Router does not support the following options: "option_foo", "option_bar"
44 */
45 public function testSetOptionsWithUnsupportedOptions()
46 {
47 $this->router->setOptions(array(
48 'cache_dir' => './cache',
49 'option_foo' => true,
50 'option_bar' => 'baz',
51 'resource_type' => 'ResourceType'
52 ));
53 }
54
55 public function testSetOptionWithSupportedOption()
56 {
57 $this->router->setOption('cache_dir', './cache');
58
59 $this->assertSame('./cache', $this->router->getOption('cache_dir'));
60 }
61
62 /**
63 * @expectedException \InvalidArgumentException
64 * @expectedExceptionMessage The Router does not support the "option_foo" option
65 */
66 public function testSetOptionWithUnsupportedOption()
67 {
68 $this->router->setOption('option_foo', true);
69 }
70
71 /**
72 * @expectedException \InvalidArgumentException
73 * @expectedExceptionMessage The Router does not support the "option_foo" option
74 */
75 public function testGetOptionWithUnsupportedOption()
76 {
77 $this->router->getOption('option_foo', true);
78 }
79
80 public function testThatRouteCollectionIsLoaded()
81 {
82 $this->router->setOption('resource_type', 'ResourceType');
83
84 $routeCollection = $this->getMock('Symfony\Component\Routing\RouteCollection');
85
86 $this->loader->expects($this->once())
87 ->method('load')->with('routing.yml', 'ResourceType')
88 ->will($this->returnValue($routeCollection));
89
90 $this->assertSame($routeCollection, $this->router->getRouteCollection());
91 }
92
93 /**
94 * @dataProvider provideMatcherOptionsPreventingCaching
95 */
96 public function testMatcherIsCreatedIfCacheIsNotConfigured($option)
97 {
98 $this->router->setOption($option, null);
99
100 $this->loader->expects($this->once())
101 ->method('load')->with('routing.yml', null)
102 ->will($this->returnValue($this->getMock('Symfony\Component\Routing\RouteCollection')));
103
104 $this->assertInstanceOf('Symfony\\Component\\Routing\\Matcher\\UrlMatcher', $this->router->getMatcher());
105
106 }
107
108 public function provideMatcherOptionsPreventingCaching()
109 {
110 return array(
111 array('cache_dir'),
112 array('matcher_cache_class')
113 );
114 }
115
116 /**
117 * @dataProvider provideGeneratorOptionsPreventingCaching
118 */
119 public function testGeneratorIsCreatedIfCacheIsNotConfigured($option)
120 {
121 $this->router->setOption($option, null);
122
123 $this->loader->expects($this->once())
124 ->method('load')->with('routing.yml', null)
125 ->will($this->returnValue($this->getMock('Symfony\Component\Routing\RouteCollection')));
126
127 $this->assertInstanceOf('Symfony\\Component\\Routing\\Generator\\UrlGenerator', $this->router->getGenerator());
128
129 }
130
131 public function provideGeneratorOptionsPreventingCaching()
132 {
133 return array(
134 array('cache_dir'),
135 array('generator_cache_class')
136 );
137 }
138}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/composer.json b/vendor/symfony/routing/Symfony/Component/Routing/composer.json
new file mode 100644
index 00000000..9a737c6b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/composer.json
@@ -0,0 +1,42 @@
1{
2 "name": "symfony/routing",
3 "type": "library",
4 "description": "Symfony Routing Component",
5 "keywords": [],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3"
20 },
21 "require-dev": {
22 "symfony/config": "~2.2",
23 "symfony/yaml": "~2.0",
24 "doctrine/common": "~2.2",
25 "psr/log": "~1.0"
26 },
27 "suggest": {
28 "symfony/config": "",
29 "symfony/yaml": "",
30 "doctrine/common": ""
31 },
32 "autoload": {
33 "psr-0": { "Symfony\\Component\\Routing\\": "" }
34 },
35 "target-dir": "Symfony/Component/Routing",
36 "minimum-stability": "dev",
37 "extra": {
38 "branch-alias": {
39 "dev-master": "2.3-dev"
40 }
41 }
42}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/phpunit.xml.dist b/vendor/symfony/routing/Symfony/Component/Routing/phpunit.xml.dist
new file mode 100644
index 00000000..830066aa
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/phpunit.xml.dist
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony Routing Component Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./vendor</directory>
25 <directory>./Tests</directory>
26 </exclude>
27 </whitelist>
28 </filter>
29</phpunit>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/.gitignore b/vendor/symfony/translation/Symfony/Component/Translation/.gitignore
new file mode 100644
index 00000000..44de97a3
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/.gitignore
@@ -0,0 +1,4 @@
1vendor/
2composer.lock
3phpunit.xml
4
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/CHANGELOG.md b/vendor/symfony/translation/Symfony/Component/Translation/CHANGELOG.md
new file mode 100644
index 00000000..b8027ab1
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/CHANGELOG.md
@@ -0,0 +1,27 @@
1CHANGELOG
2=========
3
42.3.0
5-----
6
7 * added classes to make operations on catalogues (like making a diff or a merge on 2 catalogues)
8 * added Translator::getFallbackLocales()
9 * deprecated Translator::setFallbackLocale() in favor of the new Translator::setFallbackLocales() method
10
112.2.0
12-----
13
14 * QtTranslationsLoader class renamed to QtFileLoader. QtTranslationsLoader is deprecated and will be removed in 2.3.
15 * [BC BREAK] uniformized the exception thrown by the load() method when an error occurs. The load() method now
16 throws Symfony\Component\Translation\Exception\NotFoundResourceException when a resource cannot be found
17 and Symfony\Component\Translation\Exception\InvalidResourceException when a resource is invalid.
18 * changed the exception class thrown by some load() methods from \RuntimeException to \InvalidArgumentException
19 (IcuDatFileLoader, IcuResFileLoader and QtFileLoader)
20
212.1.0
22-----
23
24 * added support for more than one fallback locale
25 * added support for extracting translation messages from templates (Twig and PHP)
26 * added dumpers for translation catalogs
27 * added support for QT, gettext, and ResourceBundles
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/AbstractOperation.php b/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/AbstractOperation.php
new file mode 100644
index 00000000..062056b7
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/AbstractOperation.php
@@ -0,0 +1,146 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Catalogue;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\MessageCatalogueInterface;
16
17/**
18 * Base catalogues binary operation class.
19 *
20 * @author Jean-François Simon <contact@jfsimon.fr>
21 */
22abstract class AbstractOperation implements OperationInterface
23{
24 /**
25 * @var MessageCatalogueInterface
26 */
27 protected $source;
28
29 /**
30 * @var MessageCatalogueInterface
31 */
32 protected $target;
33
34 /**
35 * @var MessageCatalogue
36 */
37 protected $result;
38
39 /**
40 * @var null|array
41 */
42 private $domains;
43
44 /**
45 * @var array
46 */
47 protected $messages;
48
49 /**
50 * @param MessageCatalogueInterface $source
51 * @param MessageCatalogueInterface $target
52 *
53 * @throws \LogicException
54 */
55 public function __construct(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
56 {
57 if ($source->getLocale() !== $target->getLocale()) {
58 throw new \LogicException('Operated catalogues must belong to the same locale.');
59 }
60
61 $this->source = $source;
62 $this->target = $target;
63 $this->result = new MessageCatalogue($source->getLocale());
64 $this->domains = null;
65 $this->messages = array();
66 }
67
68 /**
69 * {@inheritdoc}
70 */
71 public function getDomains()
72 {
73 if (null === $this->domains) {
74 $this->domains = array_values(array_unique(array_merge($this->source->getDomains(), $this->target->getDomains())));
75 }
76
77 return $this->domains;
78 }
79
80 /**
81 * {@inheritdoc}
82 */
83 public function getMessages($domain)
84 {
85 if (!in_array($domain, $this->getDomains())) {
86 throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
87 }
88
89 if (!isset($this->messages[$domain]['all'])) {
90 $this->processDomain($domain);
91 }
92
93 return $this->messages[$domain]['all'];
94 }
95
96 /**
97 * {@inheritdoc}
98 */
99 public function getNewMessages($domain)
100 {
101 if (!in_array($domain, $this->getDomains())) {
102 throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
103 }
104
105 if (!isset($this->messages[$domain]['new'])) {
106 $this->processDomain($domain);
107 }
108
109 return $this->messages[$domain]['new'];
110 }
111
112 /**
113 * {@inheritdoc}
114 */
115 public function getObsoleteMessages($domain)
116 {
117 if (!in_array($domain, $this->getDomains())) {
118 throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
119 }
120
121 if (!isset($this->messages[$domain]['obsolete'])) {
122 $this->processDomain($domain);
123 }
124
125 return $this->messages[$domain]['obsolete'];
126 }
127
128 /**
129 * {@inheritdoc}
130 */
131 public function getResult()
132 {
133 foreach ($this->getDomains() as $domain) {
134 if (!isset($this->messages[$domain])) {
135 $this->processDomain($domain);
136 }
137 }
138
139 return $this->result;
140 }
141
142 /**
143 * @param string $domain
144 */
145 abstract protected function processDomain($domain);
146}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/DiffOperation.php b/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/DiffOperation.php
new file mode 100644
index 00000000..1672d121
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/DiffOperation.php
@@ -0,0 +1,49 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Catalogue;
13
14/**
15 * Diff operation between two catalogues.
16 *
17 * @author Jean-François Simon <contact@jfsimon.fr>
18 */
19class DiffOperation extends AbstractOperation
20{
21 /**
22 * {@inheritdoc}
23 */
24 protected function processDomain($domain)
25 {
26 $this->messages[$domain] = array(
27 'all' => array(),
28 'new' => array(),
29 'obsolete' => array(),
30 );
31
32 foreach ($this->source->all($domain) as $id => $message) {
33 if ($this->target->has($id, $domain)) {
34 $this->messages[$domain]['all'][$id] = $message;
35 $this->result->add(array($id => $message), $domain);
36 } else {
37 $this->messages[$domain]['obsolete'][$id] = $message;
38 }
39 }
40
41 foreach ($this->target->all($domain) as $id => $message) {
42 if (!$this->source->has($id, $domain)) {
43 $this->messages[$domain]['all'][$id] = $message;
44 $this->messages[$domain]['new'][$id] = $message;
45 $this->result->add(array($id => $message), $domain);
46 }
47 }
48 }
49}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/MergeOperation.php b/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/MergeOperation.php
new file mode 100644
index 00000000..0052363e
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/MergeOperation.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Catalogue;
13
14/**
15 * Merge operation between two catalogues.
16 *
17 * @author Jean-François Simon <contact@jfsimon.fr>
18 */
19class MergeOperation extends AbstractOperation
20{
21 /**
22 * {@inheritdoc}
23 */
24 protected function processDomain($domain)
25 {
26 $this->messages[$domain] = array(
27 'all' => array(),
28 'new' => array(),
29 'obsolete' => array(),
30 );
31
32 foreach ($this->source->all($domain) as $id => $message) {
33 $this->messages[$domain]['all'][$id] = $message;
34 $this->result->add(array($id => $message), $domain);
35 }
36
37 foreach ($this->target->all($domain) as $id => $message) {
38 if (!$this->source->has($id, $domain)) {
39 $this->messages[$domain]['all'][$id] = $message;
40 $this->messages[$domain]['new'][$id] = $message;
41 $this->result->add(array($id => $message), $domain);
42 }
43 }
44 }
45}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/OperationInterface.php b/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/OperationInterface.php
new file mode 100644
index 00000000..d72378a3
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Catalogue/OperationInterface.php
@@ -0,0 +1,63 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Catalogue;
13
14use Symfony\Component\Translation\MessageCatalogueInterface;
15
16/**
17 * Represents an operation on catalogue(s).
18 *
19 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
20 */
21interface OperationInterface
22{
23 /**
24 * Returns domains affected by operation.
25 *
26 * @return array
27 */
28 public function getDomains();
29
30 /**
31 * Returns all valid messages after operation.
32 *
33 * @param string $domain
34 *
35 * @return array
36 */
37 public function getMessages($domain);
38
39 /**
40 * Returns new messages after operation.
41 *
42 * @param string $domain
43 *
44 * @return array
45 */
46 public function getNewMessages($domain);
47
48 /**
49 * Returns obsolete messages after operation.
50 *
51 * @param string $domain
52 *
53 * @return array
54 */
55 public function getObsoleteMessages($domain);
56
57 /**
58 * Returns resulting catalogue.
59 *
60 * @return MessageCatalogueInterface
61 */
62 public function getResult();
63}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/CsvFileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/CsvFileDumper.php
new file mode 100644
index 00000000..0b411905
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/CsvFileDumper.php
@@ -0,0 +1,63 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * CsvFileDumper generates a csv formatted string representation of a message catalogue.
18 *
19 * @author Stealth35
20 */
21class CsvFileDumper extends FileDumper
22{
23 private $delimiter = ';';
24 private $enclosure = '"';
25
26 /**
27 * {@inheritDoc}
28 */
29 public function format(MessageCatalogue $messages, $domain = 'messages')
30 {
31 $handle = fopen('php://memory', 'rb+');
32
33 foreach ($messages->all($domain) as $source => $target) {
34 fputcsv($handle, array($source, $target), $this->delimiter, $this->enclosure);
35 }
36
37 rewind($handle);
38 $output = stream_get_contents($handle);
39 fclose($handle);
40
41 return $output;
42 }
43
44 /**
45 * Sets the delimiter and escape character for CSV.
46 *
47 * @param string $delimiter delimiter character
48 * @param string $enclosure enclosure character
49 */
50 public function setCsvControl($delimiter = ';', $enclosure = '"')
51 {
52 $this->delimiter = $delimiter;
53 $this->enclosure = $enclosure;
54 }
55
56 /**
57 * {@inheritDoc}
58 */
59 protected function getExtension()
60 {
61 return 'csv';
62 }
63}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/DumperInterface.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/DumperInterface.php
new file mode 100644
index 00000000..cebc65ed
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/DumperInterface.php
@@ -0,0 +1,31 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * DumperInterface is the interface implemented by all translation dumpers.
18 * There is no common option.
19 *
20 * @author Michel Salib <michelsalib@hotmail.com>
21 */
22interface DumperInterface
23{
24 /**
25 * Dumps the message catalogue.
26 *
27 * @param MessageCatalogue $messages The message catalogue
28 * @param array $options Options that are used by the dumper
29 */
30 public function dump(MessageCatalogue $messages, $options = array());
31}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/FileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/FileDumper.php
new file mode 100644
index 00000000..63c1e6c3
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/FileDumper.php
@@ -0,0 +1,65 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * FileDumper is an implementation of DumperInterface that dump a message catalogue to file(s).
18 * Performs backup of already existing files.
19 *
20 * Options:
21 * - path (mandatory): the directory where the files should be saved
22 *
23 * @author Michel Salib <michelsalib@hotmail.com>
24 */
25abstract class FileDumper implements DumperInterface
26{
27 /**
28 * {@inheritDoc}
29 */
30 public function dump(MessageCatalogue $messages, $options = array())
31 {
32 if (!array_key_exists('path', $options)) {
33 throw new \InvalidArgumentException('The file dumper need a path options.');
34 }
35
36 // save a file for each domain
37 foreach ($messages->getDomains() as $domain) {
38 $file = $domain.'.'.$messages->getLocale().'.'.$this->getExtension();
39 // backup
40 $fullpath = $options['path'].'/'.$file;
41 if (file_exists($fullpath)) {
42 copy($fullpath, $fullpath.'~');
43 }
44 // save file
45 file_put_contents($fullpath, $this->format($messages, $domain));
46 }
47 }
48
49 /**
50 * Transforms a domain of a message catalogue to its string representation.
51 *
52 * @param MessageCatalogue $messages
53 * @param string $domain
54 *
55 * @return string representation
56 */
57 abstract protected function format(MessageCatalogue $messages, $domain);
58
59 /**
60 * Gets the file extension of the dumper.
61 *
62 * @return string file extension
63 */
64 abstract protected function getExtension();
65}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/IcuResFileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/IcuResFileDumper.php
new file mode 100644
index 00000000..979153ac
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/IcuResFileDumper.php
@@ -0,0 +1,135 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * IcuResDumper generates an ICU ResourceBundle formatted string representation of a message catalogue.
18 *
19 * @author Stealth35
20 */
21class IcuResFileDumper implements DumperInterface
22{
23 /**
24 * {@inheritDoc}
25 */
26 public function dump(MessageCatalogue $messages, $options = array())
27 {
28 if (!array_key_exists('path', $options)) {
29 throw new \InvalidArgumentException('The file dumper need a path options.');
30 }
31
32 // save a file for each domain
33 foreach ($messages->getDomains() as $domain) {
34 $file = $messages->getLocale().'.'.$this->getExtension();
35 $path = $options['path'].'/'.$domain.'/';
36
37 if (!file_exists($path)) {
38 mkdir($path);
39 }
40
41 // backup
42 if (file_exists($path.$file)) {
43 copy($path.$file, $path.$file.'~');
44 }
45
46 // save file
47 file_put_contents($path.$file, $this->format($messages, $domain));
48 }
49 }
50
51 /**
52 * {@inheritDoc}
53 */
54 public function format(MessageCatalogue $messages, $domain = 'messages')
55 {
56 $data = $indexes = $resources = '';
57
58 foreach ($messages->all($domain) as $source => $target) {
59 $indexes .= pack('v', strlen($data) + 28);
60 $data .= $source."\0";
61 }
62
63 $data .= $this->writePadding($data);
64
65 $keyTop = $this->getPosition($data);
66
67 foreach ($messages->all($domain) as $source => $target) {
68 $resources .= pack('V', $this->getPosition($data));
69
70 $data .= pack('V', strlen($target))
71 .mb_convert_encoding($target."\0", 'UTF-16LE', 'UTF-8')
72 .$this->writePadding($data)
73 ;
74 }
75
76 $resOffset = $this->getPosition($data);
77
78 $data .= pack('v', count($messages))
79 .$indexes
80 .$this->writePadding($data)
81 .$resources
82 ;
83
84 $bundleTop = $this->getPosition($data);
85
86 $root = pack('V7',
87 $resOffset + (2 << 28), // Resource Offset + Resource Type
88 6, // Index length
89 $keyTop, // Index keys top
90 $bundleTop, // Index resources top
91 $bundleTop, // Index bundle top
92 count($messages), // Index max table length
93 0 // Index attributes
94 );
95
96 $header = pack('vC2v4C12@32',
97 32, // Header size
98 0xDA, 0x27, // Magic number 1 and 2
99 20, 0, 0, 2, // Rest of the header, ..., Size of a char
100 0x52, 0x65, 0x73, 0x42, // Data format identifier
101 1, 2, 0, 0, // Data version
102 1, 4, 0, 0 // Unicode version
103 );
104
105 $output = $header
106 .$root
107 .$data;
108
109 return $output;
110 }
111
112 private function writePadding($data)
113 {
114 $padding = strlen($data) % 4;
115
116 if ($padding) {
117 return str_repeat("\xAA", 4 - $padding);
118 }
119 }
120
121 private function getPosition($data)
122 {
123 $position = (strlen($data) + 28) / 4;
124
125 return $position;
126 }
127
128 /**
129 * {@inheritDoc}
130 */
131 protected function getExtension()
132 {
133 return 'res';
134 }
135}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/IniFileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/IniFileDumper.php
new file mode 100644
index 00000000..173cf8c1
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/IniFileDumper.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * IniFileDumper generates an ini formatted string representation of a message catalogue.
18 *
19 * @author Stealth35
20 */
21class IniFileDumper extends FileDumper
22{
23 /**
24 * {@inheritDoc}
25 */
26 public function format(MessageCatalogue $messages, $domain = 'messages')
27 {
28 $output = '';
29
30 foreach ($messages->all($domain) as $source => $target) {
31 $escapeTarget = str_replace('"', '\"', $target);
32 $output .= $source.'="'.$escapeTarget."\"\n";
33 }
34
35 return $output;
36 }
37
38 /**
39 * {@inheritDoc}
40 */
41 protected function getExtension()
42 {
43 return 'ini';
44 }
45}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/MoFileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/MoFileDumper.php
new file mode 100644
index 00000000..a3a2a649
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/MoFileDumper.php
@@ -0,0 +1,82 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Loader\MoFileLoader;
16
17/**
18 * MoFileDumper generates a gettext formatted string representation of a message catalogue.
19 *
20 * @author Stealth35
21 */
22class MoFileDumper extends FileDumper
23{
24 /**
25 * {@inheritDoc}
26 */
27 public function format(MessageCatalogue $messages, $domain = 'messages')
28 {
29 $output = $sources = $targets = $sourceOffsets = $targetOffsets = '';
30 $offsets = array();
31 $size = 0;
32
33 foreach ($messages->all($domain) as $source => $target) {
34 $offsets[] = array_map('strlen', array($sources, $source, $targets, $target));
35 $sources .= "\0".$source;
36 $targets .= "\0".$target;
37 ++$size;
38 }
39
40 $header = array(
41 'magicNumber' => MoFileLoader::MO_LITTLE_ENDIAN_MAGIC,
42 'formatRevision' => 0,
43 'count' => $size,
44 'offsetId' => MoFileLoader::MO_HEADER_SIZE,
45 'offsetTranslated' => MoFileLoader::MO_HEADER_SIZE + (8 * $size),
46 'sizeHashes' => 0,
47 'offsetHashes' => MoFileLoader::MO_HEADER_SIZE + (16 * $size),
48 );
49
50 $sourcesSize = strlen($sources);
51 $sourcesStart = $header['offsetHashes'] + 1;
52
53 foreach ($offsets as $offset) {
54 $sourceOffsets .= $this->writeLong($offset[1])
55 .$this->writeLong($offset[0] + $sourcesStart);
56 $targetOffsets .= $this->writeLong($offset[3])
57 .$this->writeLong($offset[2] + $sourcesStart + $sourcesSize);
58 }
59
60 $output = implode(array_map(array($this, 'writeLong'), $header))
61 .$sourceOffsets
62 .$targetOffsets
63 .$sources
64 .$targets
65 ;
66
67 return $output;
68 }
69
70 /**
71 * {@inheritDoc}
72 */
73 protected function getExtension()
74 {
75 return 'mo';
76 }
77
78 private function writeLong($str)
79 {
80 return pack('V*', $str);
81 }
82}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/PhpFileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/PhpFileDumper.php
new file mode 100644
index 00000000..8de4a5b4
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/PhpFileDumper.php
@@ -0,0 +1,40 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * PhpFileDumper generates php files from a message catalogue.
18 *
19 * @author Michel Salib <michelsalib@hotmail.com>
20 */
21class PhpFileDumper extends FileDumper
22{
23 /**
24 * {@inheritDoc}
25 */
26 protected function format(MessageCatalogue $messages, $domain)
27 {
28 $output = "<?php\n\nreturn ".var_export($messages->all($domain), true).";\n";
29
30 return $output;
31 }
32
33 /**
34 * {@inheritDoc}
35 */
36 protected function getExtension()
37 {
38 return 'php';
39 }
40}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/PoFileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/PoFileDumper.php
new file mode 100644
index 00000000..d957ab91
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/PoFileDumper.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * PoFileDumper generates a gettext formatted string representation of a message catalogue.
18 *
19 * @author Stealth35
20 */
21class PoFileDumper extends FileDumper
22{
23 /**
24 * {@inheritDoc}
25 */
26 public function format(MessageCatalogue $messages, $domain = 'messages')
27 {
28 $output = '';
29 $newLine = false;
30 foreach ($messages->all($domain) as $source => $target) {
31 if ($newLine) {
32 $output .= "\n";
33 } else {
34 $newLine = true;
35 }
36 $output .= sprintf('msgid "%s"'."\n", $this->escape($source));
37 $output .= sprintf('msgstr "%s"', $this->escape($target));
38 }
39
40 return $output;
41 }
42
43 /**
44 * {@inheritDoc}
45 */
46 protected function getExtension()
47 {
48 return 'po';
49 }
50
51 private function escape($str)
52 {
53 return addcslashes($str, "\0..\37\42\134");
54 }
55}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/QtFileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/QtFileDumper.php
new file mode 100644
index 00000000..a1a84805
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/QtFileDumper.php
@@ -0,0 +1,50 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * QtFileDumper generates ts files from a message catalogue.
18 *
19 * @author Benjamin Eberlei <kontakt@beberlei.de>
20 */
21class QtFileDumper extends FileDumper
22{
23 /**
24 * {@inheritDoc}
25 */
26 public function format(MessageCatalogue $messages, $domain)
27 {
28 $dom = new \DOMDocument('1.0', 'utf-8');
29 $dom->formatOutput = true;
30 $ts = $dom->appendChild($dom->createElement('TS'));
31 $context = $ts->appendChild($dom->createElement('context'));
32 $context->appendChild($dom->createElement('name', $domain));
33
34 foreach ($messages->all($domain) as $source => $target) {
35 $message = $context->appendChild($dom->createElement('message'));
36 $message->appendChild($dom->createElement('source', $source));
37 $message->appendChild($dom->createElement('translation', $target));
38 }
39
40 return $dom->saveXML();
41 }
42
43 /**
44 * {@inheritDoc}
45 */
46 protected function getExtension()
47 {
48 return 'ts';
49 }
50}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/XliffFileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/XliffFileDumper.php
new file mode 100644
index 00000000..0d258aad
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/XliffFileDumper.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * XliffFileDumper generates xliff files from a message catalogue.
18 *
19 * @author Michel Salib <michelsalib@hotmail.com>
20 */
21class XliffFileDumper extends FileDumper
22{
23 /**
24 * {@inheritDoc}
25 */
26 protected function format(MessageCatalogue $messages, $domain)
27 {
28 $dom = new \DOMDocument('1.0', 'utf-8');
29 $dom->formatOutput = true;
30
31 $xliff = $dom->appendChild($dom->createElement('xliff'));
32 $xliff->setAttribute('version', '1.2');
33 $xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2');
34
35 $xliffFile = $xliff->appendChild($dom->createElement('file'));
36 $xliffFile->setAttribute('source-language', $messages->getLocale());
37 $xliffFile->setAttribute('datatype', 'plaintext');
38 $xliffFile->setAttribute('original', 'file.ext');
39
40 $xliffBody = $xliffFile->appendChild($dom->createElement('body'));
41 foreach ($messages->all($domain) as $source => $target) {
42 $translation = $dom->createElement('trans-unit');
43
44 $translation->setAttribute('id', md5($source));
45 $translation->setAttribute('resname', $source);
46
47 $s = $translation->appendChild($dom->createElement('source'));
48 $s->appendChild($dom->createTextNode($source));
49
50 $t = $translation->appendChild($dom->createElement('target'));
51 $t->appendChild($dom->createTextNode($target));
52
53 $xliffBody->appendChild($translation);
54 }
55
56 return $dom->saveXML();
57 }
58
59 /**
60 * {@inheritDoc}
61 */
62 protected function getExtension()
63 {
64 return 'xlf';
65 }
66}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Dumper/YamlFileDumper.php b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/YamlFileDumper.php
new file mode 100644
index 00000000..d8072fb7
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Dumper/YamlFileDumper.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Yaml\Yaml;
16
17/**
18 * YamlFileDumper generates yaml files from a message catalogue.
19 *
20 * @author Michel Salib <michelsalib@hotmail.com>
21 */
22class YamlFileDumper extends FileDumper
23{
24 /**
25 * {@inheritDoc}
26 */
27 protected function format(MessageCatalogue $messages, $domain)
28 {
29 return Yaml::dump($messages->all($domain));
30 }
31
32 /**
33 * {@inheritDoc}
34 */
35 protected function getExtension()
36 {
37 return 'yml';
38 }
39}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Exception/ExceptionInterface.php b/vendor/symfony/translation/Symfony/Component/Translation/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..7757e669
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Exception/ExceptionInterface.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Exception;
13
14/**
15 * Exception interface for all exceptions thrown by the component.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 *
19 * @api
20 */
21interface ExceptionInterface
22{
23}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Exception/InvalidResourceException.php b/vendor/symfony/translation/Symfony/Component/Translation/Exception/InvalidResourceException.php
new file mode 100644
index 00000000..6413f1ae
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Exception/InvalidResourceException.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Exception;
13
14/**
15 * Thrown when a resource cannot be loaded.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 *
19 * @api
20 */
21class InvalidResourceException extends \InvalidArgumentException implements ExceptionInterface
22{
23}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Exception/NotFoundResourceException.php b/vendor/symfony/translation/Symfony/Component/Translation/Exception/NotFoundResourceException.php
new file mode 100644
index 00000000..7826e5ce
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Exception/NotFoundResourceException.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Exception;
13
14/**
15 * Thrown when a resource does not exist.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 *
19 * @api
20 */
21class NotFoundResourceException extends \InvalidArgumentException implements ExceptionInterface
22{
23}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Extractor/ChainExtractor.php b/vendor/symfony/translation/Symfony/Component/Translation/Extractor/ChainExtractor.php
new file mode 100644
index 00000000..0d07a93f
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Extractor/ChainExtractor.php
@@ -0,0 +1,60 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Extractor;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * ChainExtractor extracts translation messages from template files.
18 *
19 * @author Michel Salib <michelsalib@hotmail.com>
20 */
21class ChainExtractor implements ExtractorInterface
22{
23 /**
24 * The extractors.
25 *
26 * @var ExtractorInterface[]
27 */
28 private $extractors = array();
29
30 /**
31 * Adds a loader to the translation extractor.
32 *
33 * @param string $format The format of the loader
34 * @param ExtractorInterface $extractor The loader
35 */
36 public function addExtractor($format, ExtractorInterface $extractor)
37 {
38 $this->extractors[$format] = $extractor;
39 }
40
41 /**
42 * {@inheritDoc}
43 */
44 public function setPrefix($prefix)
45 {
46 foreach ($this->extractors as $extractor) {
47 $extractor->setPrefix($prefix);
48 }
49 }
50
51 /**
52 * {@inheritDoc}
53 */
54 public function extract($directory, MessageCatalogue $catalogue)
55 {
56 foreach ($this->extractors as $extractor) {
57 $extractor->extract($directory, $catalogue);
58 }
59 }
60}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Extractor/ExtractorInterface.php b/vendor/symfony/translation/Symfony/Component/Translation/Extractor/ExtractorInterface.php
new file mode 100644
index 00000000..6f877c31
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Extractor/ExtractorInterface.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Extractor;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * Extracts translation messages from a template directory to the catalogue.
18 * New found messages are injected to the catalogue using the prefix.
19 *
20 * @author Michel Salib <michelsalib@hotmail.com>
21 */
22interface ExtractorInterface
23{
24 /**
25 * Extracts translation messages from a template directory to the catalogue.
26 *
27 * @param string $directory The path to look into
28 * @param MessageCatalogue $catalogue The catalogue
29 */
30 public function extract($directory, MessageCatalogue $catalogue);
31
32 /**
33 * Sets the prefix that should be used for new found messages.
34 *
35 * @param string $prefix The prefix
36 */
37 public function setPrefix($prefix);
38}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/IdentityTranslator.php b/vendor/symfony/translation/Symfony/Component/Translation/IdentityTranslator.php
new file mode 100644
index 00000000..f30556b5
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/IdentityTranslator.php
@@ -0,0 +1,74 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation;
13
14/**
15 * IdentityTranslator does not translate anything.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 *
19 * @api
20 */
21class IdentityTranslator implements TranslatorInterface
22{
23 private $selector;
24
25 /**
26 * Constructor.
27 *
28 * @param MessageSelector $selector The message selector for pluralization
29 *
30 * @api
31 */
32 public function __construct(MessageSelector $selector)
33 {
34 $this->selector = $selector;
35 }
36
37 /**
38 * {@inheritdoc}
39 *
40 * @api
41 */
42 public function setLocale($locale)
43 {
44 }
45
46 /**
47 * {@inheritdoc}
48 *
49 * @api
50 */
51 public function getLocale()
52 {
53 }
54
55 /**
56 * {@inheritdoc}
57 *
58 * @api
59 */
60 public function trans($id, array $parameters = array(), $domain = 'messages', $locale = null)
61 {
62 return strtr((string) $id, $parameters);
63 }
64
65 /**
66 * {@inheritdoc}
67 *
68 * @api
69 */
70 public function transChoice($id, $number, array $parameters = array(), $domain = 'messages', $locale = null)
71 {
72 return strtr($this->selector->choose((string) $id, (int) $number, $locale), $parameters);
73 }
74}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Interval.php b/vendor/symfony/translation/Symfony/Component/Translation/Interval.php
new file mode 100644
index 00000000..033b0188
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Interval.php
@@ -0,0 +1,107 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation;
13
14/**
15 * Tests if a given number belongs to a given math interval.
16 *
17 * An interval can represent a finite set of numbers:
18 *
19 * {1,2,3,4}
20 *
21 * An interval can represent numbers between two numbers:
22 *
23 * [1, +Inf]
24 * ]-1,2[
25 *
26 * The left delimiter can be [ (inclusive) or ] (exclusive).
27 * The right delimiter can be [ (exclusive) or ] (inclusive).
28 * Beside numbers, you can use -Inf and +Inf for the infinite.
29 *
30 * @author Fabien Potencier <fabien@symfony.com>
31 *
32 * @see http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
33 */
34class Interval
35{
36 /**
37 * Tests if the given number is in the math interval.
38 *
39 * @param integer $number A number
40 * @param string $interval An interval
41 *
42 * @return Boolean
43 *
44 * @throws \InvalidArgumentException
45 */
46 public static function test($number, $interval)
47 {
48 $interval = trim($interval);
49
50 if (!preg_match('/^'.self::getIntervalRegexp().'$/x', $interval, $matches)) {
51 throw new \InvalidArgumentException(sprintf('"%s" is not a valid interval.', $interval));
52 }
53
54 if ($matches[1]) {
55 foreach (explode(',', $matches[2]) as $n) {
56 if ($number == $n) {
57 return true;
58 }
59 }
60 } else {
61 $leftNumber = self::convertNumber($matches['left']);
62 $rightNumber = self::convertNumber($matches['right']);
63
64 return
65 ('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
66 && (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
67 ;
68 }
69
70 return false;
71 }
72
73 /**
74 * Returns a Regexp that matches valid intervals.
75 *
76 * @return string A Regexp (without the delimiters)
77 */
78 public static function getIntervalRegexp()
79 {
80 return <<<EOF
81 ({\s*
82 (\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
83 \s*})
84
85 |
86
87 (?P<left_delimiter>[\[\]])
88 \s*
89 (?P<left>-Inf|\-?\d+(\.\d+)?)
90 \s*,\s*
91 (?P<right>\+?Inf|\-?\d+(\.\d+)?)
92 \s*
93 (?P<right_delimiter>[\[\]])
94EOF;
95 }
96
97 private static function convertNumber($number)
98 {
99 if ('-Inf' === $number) {
100 return log(0);
101 } elseif ('+Inf' === $number || 'Inf' === $number) {
102 return -log(0);
103 }
104
105 return (float) $number;
106 }
107}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/LICENSE b/vendor/symfony/translation/Symfony/Component/Translation/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/ArrayLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/ArrayLoader.php
new file mode 100644
index 00000000..99058fbf
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/ArrayLoader.php
@@ -0,0 +1,70 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * ArrayLoader loads translations from a PHP array.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 *
21 * @api
22 */
23class ArrayLoader implements LoaderInterface
24{
25 /**
26 * {@inheritdoc}
27 *
28 * @api
29 */
30 public function load($resource, $locale, $domain = 'messages')
31 {
32 $this->flatten($resource);
33 $catalogue = new MessageCatalogue($locale);
34 $catalogue->add($resource, $domain);
35
36 return $catalogue;
37 }
38
39 /**
40 * Flattens an nested array of translations
41 *
42 * The scheme used is:
43 * 'key' => array('key2' => array('key3' => 'value'))
44 * Becomes:
45 * 'key.key2.key3' => 'value'
46 *
47 * This function takes an array by reference and will modify it
48 *
49 * @param array &$messages The array that will be flattened
50 * @param array $subnode Current subnode being parsed, used internally for recursive calls
51 * @param string $path Current path being parsed, used internally for recursive calls
52 */
53 private function flatten(array &$messages, array $subnode = null, $path = null)
54 {
55 if (null === $subnode) {
56 $subnode =& $messages;
57 }
58 foreach ($subnode as $key => $value) {
59 if (is_array($value)) {
60 $nodePath = $path ? $path.'.'.$key : $key;
61 $this->flatten($messages, $value, $nodePath);
62 if (null === $path) {
63 unset($messages[$key]);
64 }
65 } elseif (null !== $path) {
66 $messages[$path.'.'.$key] = $value;
67 }
68 }
69 }
70}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/CsvFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/CsvFileLoader.php
new file mode 100644
index 00000000..bc10188c
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/CsvFileLoader.php
@@ -0,0 +1,92 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\Exception\InvalidResourceException;
15use Symfony\Component\Translation\Exception\NotFoundResourceException;
16use Symfony\Component\Config\Resource\FileResource;
17
18/**
19 * CsvFileLoader loads translations from CSV files.
20 *
21 * @author Saša Stamenković <umpirsky@gmail.com>
22 *
23 * @api
24 */
25class CsvFileLoader extends ArrayLoader implements LoaderInterface
26{
27 private $delimiter = ';';
28 private $enclosure = '"';
29 private $escape = '\\';
30
31 /**
32 * {@inheritdoc}
33 *
34 * @api
35 */
36 public function load($resource, $locale, $domain = 'messages')
37 {
38 if (!stream_is_local($resource)) {
39 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
40 }
41
42 if (!file_exists($resource)) {
43 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
44 }
45
46 $messages = array();
47
48 try {
49 $file = new \SplFileObject($resource, 'rb');
50 } catch (\RuntimeException $e) {
51 throw new NotFoundResourceException(sprintf('Error opening file "%s".', $resource), 0, $e);
52 }
53
54 $file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY);
55 $file->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
56
57 foreach ($file as $data) {
58 if (substr($data[0], 0, 1) === '#') {
59 continue;
60 }
61
62 if (!isset($data[1])) {
63 continue;
64 }
65
66 if (count($data) == 2) {
67 $messages[$data[0]] = $data[1];
68 } else {
69 continue;
70 }
71 }
72
73 $catalogue = parent::load($messages, $locale, $domain);
74 $catalogue->addResource(new FileResource($resource));
75
76 return $catalogue;
77 }
78
79 /**
80 * Sets the delimiter, enclosure, and escape character for CSV.
81 *
82 * @param string $delimiter delimiter character
83 * @param string $enclosure enclosure character
84 * @param string $escape escape character
85 */
86 public function setCsvControl($delimiter = ';', $enclosure = '"', $escape = '\\')
87 {
88 $this->delimiter = $delimiter;
89 $this->enclosure = $enclosure;
90 $this->escape = $escape;
91 }
92}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/IcuDatFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/IcuDatFileLoader.php
new file mode 100644
index 00000000..104883b0
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/IcuDatFileLoader.php
@@ -0,0 +1,54 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Exception\InvalidResourceException;
16use Symfony\Component\Translation\Exception\NotFoundResourceException;
17use Symfony\Component\Config\Resource\FileResource;
18
19/**
20 * IcuResFileLoader loads translations from a resource bundle.
21 *
22 * @author stealth35
23 */
24class IcuDatFileLoader extends IcuResFileLoader
25{
26 /**
27 * {@inheritdoc}
28 */
29 public function load($resource, $locale, $domain = 'messages')
30 {
31 if (!stream_is_local($resource.'.dat')) {
32 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
33 }
34
35 if (!file_exists($resource.'.dat')) {
36 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
37 }
38
39 $rb = new \ResourceBundle($locale, $resource);
40
41 if (!$rb) {
42 throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
43 } elseif (intl_is_failure($rb->getErrorCode())) {
44 throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
45 }
46
47 $messages = $this->flatten($rb);
48 $catalogue = new MessageCatalogue($locale);
49 $catalogue->add($messages, $domain);
50 $catalogue->addResource(new FileResource($resource.'.dat'));
51
52 return $catalogue;
53 }
54}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/IcuResFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/IcuResFileLoader.php
new file mode 100644
index 00000000..81b8e0fc
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/IcuResFileLoader.php
@@ -0,0 +1,84 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Exception\InvalidResourceException;
16use Symfony\Component\Translation\Exception\NotFoundResourceException;
17use Symfony\Component\Config\Resource\DirectoryResource;
18
19/**
20 * IcuResFileLoader loads translations from a resource bundle.
21 *
22 * @author stealth35
23 */
24class IcuResFileLoader implements LoaderInterface
25{
26 /**
27 * {@inheritdoc}
28 */
29 public function load($resource, $locale, $domain = 'messages')
30 {
31 if (!stream_is_local($resource)) {
32 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
33 }
34
35 if (!is_dir($resource)) {
36 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
37 }
38
39 $rb = new \ResourceBundle($locale, $resource);
40
41 if (!$rb) {
42 throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
43 } elseif (intl_is_failure($rb->getErrorCode())) {
44 throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
45 }
46
47 $messages = $this->flatten($rb);
48 $catalogue = new MessageCatalogue($locale);
49 $catalogue->add($messages, $domain);
50 $catalogue->addResource(new DirectoryResource($resource));
51
52 return $catalogue;
53 }
54
55 /**
56 * Flattens an ResourceBundle
57 *
58 * The scheme used is:
59 * key { key2 { key3 { "value" } } }
60 * Becomes:
61 * 'key.key2.key3' => 'value'
62 *
63 * This function takes an array by reference and will modify it
64 *
65 * @param \ResourceBundle $rb the ResourceBundle that will be flattened
66 * @param array $messages used internally for recursive calls
67 * @param string $path current path being parsed, used internally for recursive calls
68 *
69 * @return array the flattened ResourceBundle
70 */
71 protected function flatten(\ResourceBundle $rb, array &$messages = array(), $path = null)
72 {
73 foreach ($rb as $key => $value) {
74 $nodePath = $path ? $path.'.'.$key : $key;
75 if ($value instanceof \ResourceBundle) {
76 $this->flatten($value, $messages, $nodePath);
77 } else {
78 $messages[$nodePath] = $value;
79 }
80 }
81
82 return $messages;
83 }
84}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/IniFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/IniFileLoader.php
new file mode 100644
index 00000000..616fa7e0
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/IniFileLoader.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\Exception\InvalidResourceException;
15use Symfony\Component\Translation\Exception\NotFoundResourceException;
16use Symfony\Component\Config\Resource\FileResource;
17
18/**
19 * IniFileLoader loads translations from an ini file.
20 *
21 * @author stealth35
22 */
23class IniFileLoader extends ArrayLoader implements LoaderInterface
24{
25 /**
26 * {@inheritdoc}
27 */
28 public function load($resource, $locale, $domain = 'messages')
29 {
30 if (!stream_is_local($resource)) {
31 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
32 }
33
34 if (!file_exists($resource)) {
35 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
36 }
37
38 $messages = parse_ini_file($resource, true);
39
40 $catalogue = parent::load($messages, $locale, $domain);
41 $catalogue->addResource(new FileResource($resource));
42
43 return $catalogue;
44 }
45}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/LoaderInterface.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/LoaderInterface.php
new file mode 100644
index 00000000..4d9965ce
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/LoaderInterface.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Exception\InvalidResourceException;
16
17/**
18 * LoaderInterface is the interface implemented by all translation loaders.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 *
22 * @api
23 */
24interface LoaderInterface
25{
26 /**
27 * Loads a locale.
28 *
29 * @param mixed $resource A resource
30 * @param string $locale A locale
31 * @param string $domain The domain
32 *
33 * @return MessageCatalogue A MessageCatalogue instance
34 *
35 * @api
36 *
37 * @throws NotFoundResourceException when the resource cannot be found
38 * @throws InvalidResourceException when the resource cannot be loaded
39 */
40 public function load($resource, $locale, $domain = 'messages');
41}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/MoFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/MoFileLoader.php
new file mode 100644
index 00000000..9d1cacb3
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/MoFileLoader.php
@@ -0,0 +1,179 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\Exception\InvalidResourceException;
15use Symfony\Component\Translation\Exception\NotFoundResourceException;
16use Symfony\Component\Config\Resource\FileResource;
17
18/**
19 * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
20 */
21class MoFileLoader extends ArrayLoader implements LoaderInterface
22{
23 /**
24 * Magic used for validating the format of a MO file as well as
25 * detecting if the machine used to create that file was little endian.
26 *
27 * @var float
28 */
29 const MO_LITTLE_ENDIAN_MAGIC = 0x950412de;
30
31 /**
32 * Magic used for validating the format of a MO file as well as
33 * detecting if the machine used to create that file was big endian.
34 *
35 * @var float
36 */
37 const MO_BIG_ENDIAN_MAGIC = 0xde120495;
38
39 /**
40 * The size of the header of a MO file in bytes.
41 *
42 * @var integer Number of bytes.
43 */
44 const MO_HEADER_SIZE = 28;
45
46 public function load($resource, $locale, $domain = 'messages')
47 {
48 if (!stream_is_local($resource)) {
49 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
50 }
51
52 if (!file_exists($resource)) {
53 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
54 }
55
56 $messages = $this->parse($resource);
57
58 // empty file
59 if (null === $messages) {
60 $messages = array();
61 }
62
63 // not an array
64 if (!is_array($messages)) {
65 throw new InvalidResourceException(sprintf('The file "%s" must contain a valid mo file.', $resource));
66 }
67
68 $catalogue = parent::load($messages, $locale, $domain);
69 $catalogue->addResource(new FileResource($resource));
70
71 return $catalogue;
72 }
73
74 /**
75 * Parses machine object (MO) format, independent of the machine's endian it
76 * was created on. Both 32bit and 64bit systems are supported.
77 *
78 * @param resource $resource
79 *
80 * @return array
81 * @throws InvalidResourceException If stream content has an invalid format.
82 */
83 private function parse($resource)
84 {
85 $stream = fopen($resource, 'r');
86
87 $stat = fstat($stream);
88
89 if ($stat['size'] < self::MO_HEADER_SIZE) {
90 throw new InvalidResourceException("MO stream content has an invalid format.");
91 }
92 $magic = unpack('V1', fread($stream, 4));
93 $magic = hexdec(substr(dechex(current($magic)), -8));
94
95 if ($magic == self::MO_LITTLE_ENDIAN_MAGIC) {
96 $isBigEndian = false;
97 } elseif ($magic == self::MO_BIG_ENDIAN_MAGIC) {
98 $isBigEndian = true;
99 } else {
100 throw new InvalidResourceException("MO stream content has an invalid format.");
101 }
102
103 $formatRevision = $this->readLong($stream, $isBigEndian);
104 $count = $this->readLong($stream, $isBigEndian);
105 $offsetId = $this->readLong($stream, $isBigEndian);
106 $offsetTranslated = $this->readLong($stream, $isBigEndian);
107 $sizeHashes = $this->readLong($stream, $isBigEndian);
108 $offsetHashes = $this->readLong($stream, $isBigEndian);
109
110 $messages = array();
111
112 for ($i = 0; $i < $count; $i++) {
113 $singularId = $pluralId = null;
114 $translated = null;
115
116 fseek($stream, $offsetId + $i * 8);
117
118 $length = $this->readLong($stream, $isBigEndian);
119 $offset = $this->readLong($stream, $isBigEndian);
120
121 if ($length < 1) {
122 continue;
123 }
124
125 fseek($stream, $offset);
126 $singularId = fread($stream, $length);
127
128 if (strpos($singularId, "\000") !== false) {
129 list($singularId, $pluralId) = explode("\000", $singularId);
130 }
131
132 fseek($stream, $offsetTranslated + $i * 8);
133 $length = $this->readLong($stream, $isBigEndian);
134 $offset = $this->readLong($stream, $isBigEndian);
135
136 fseek($stream, $offset);
137 $translated = fread($stream, $length);
138
139 if (strpos($translated, "\000") !== false) {
140 $translated = explode("\000", $translated);
141 }
142
143 $ids = array('singular' => $singularId, 'plural' => $pluralId);
144 $item = compact('ids', 'translated');
145
146 if (is_array($item['translated'])) {
147 $messages[$item['ids']['singular']] = stripcslashes($item['translated'][0]);
148 if (isset($item['ids']['plural'])) {
149 $plurals = array();
150 foreach ($item['translated'] as $plural => $translated) {
151 $plurals[] = sprintf('{%d} %s', $plural, $translated);
152 }
153 $messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
154 }
155 } elseif (!empty($item['ids']['singular'])) {
156 $messages[$item['ids']['singular']] = stripcslashes($item['translated']);
157 }
158 }
159
160 fclose($stream);
161
162 return array_filter($messages);
163 }
164
165 /**
166 * Reads an unsigned long from stream respecting endianess.
167 *
168 * @param resource $stream
169 * @param boolean $isBigEndian
170 * @return integer
171 */
172 private function readLong($stream, $isBigEndian)
173 {
174 $result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));
175 $result = current($result);
176
177 return (integer) substr($result, -8);
178 }
179}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/PhpFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/PhpFileLoader.php
new file mode 100644
index 00000000..4737d1bf
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/PhpFileLoader.php
@@ -0,0 +1,49 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\Exception\InvalidResourceException;
15use Symfony\Component\Translation\Exception\NotFoundResourceException;
16use Symfony\Component\Config\Resource\FileResource;
17
18/**
19 * PhpFileLoader loads translations from PHP files returning an array of translations.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 *
23 * @api
24 */
25class PhpFileLoader extends ArrayLoader implements LoaderInterface
26{
27 /**
28 * {@inheritdoc}
29 *
30 * @api
31 */
32 public function load($resource, $locale, $domain = 'messages')
33 {
34 if (!stream_is_local($resource)) {
35 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
36 }
37
38 if (!file_exists($resource)) {
39 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
40 }
41
42 $messages = require($resource);
43
44 $catalogue = parent::load($messages, $locale, $domain);
45 $catalogue->addResource(new FileResource($resource));
46
47 return $catalogue;
48 }
49}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/PoFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/PoFileLoader.php
new file mode 100644
index 00000000..58ec6c7a
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/PoFileLoader.php
@@ -0,0 +1,178 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\Exception\InvalidResourceException;
15use Symfony\Component\Translation\Exception\NotFoundResourceException;
16use Symfony\Component\Config\Resource\FileResource;
17
18/**
19 * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
20 * @copyright Copyright (c) 2012, Clemens Tolboom
21 */
22class PoFileLoader extends ArrayLoader implements LoaderInterface
23{
24 public function load($resource, $locale, $domain = 'messages')
25 {
26 if (!stream_is_local($resource)) {
27 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
28 }
29
30 if (!file_exists($resource)) {
31 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
32 }
33
34 $messages = $this->parse($resource);
35
36 // empty file
37 if (null === $messages) {
38 $messages = array();
39 }
40
41 // not an array
42 if (!is_array($messages)) {
43 throw new InvalidResourceException(sprintf('The file "%s" must contain a valid po file.', $resource));
44 }
45
46 $catalogue = parent::load($messages, $locale, $domain);
47 $catalogue->addResource(new FileResource($resource));
48
49 return $catalogue;
50 }
51
52 /**
53 * Parses portable object (PO) format.
54 *
55 * From http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files
56 * we should be able to parse files having:
57 *
58 * white-space
59 * # translator-comments
60 * #. extracted-comments
61 * #: reference...
62 * #, flag...
63 * #| msgid previous-untranslated-string
64 * msgid untranslated-string
65 * msgstr translated-string
66 *
67 * extra or different lines are:
68 *
69 * #| msgctxt previous-context
70 * #| msgid previous-untranslated-string
71 * msgctxt context
72 *
73 * #| msgid previous-untranslated-string-singular
74 * #| msgid_plural previous-untranslated-string-plural
75 * msgid untranslated-string-singular
76 * msgid_plural untranslated-string-plural
77 * msgstr[0] translated-string-case-0
78 * ...
79 * msgstr[N] translated-string-case-n
80 *
81 * The definition states:
82 * - white-space and comments are optional.
83 * - msgid "" that an empty singleline defines a header.
84 *
85 * This parser sacrifices some features of the reference implementation the
86 * differences to that implementation are as follows.
87 * - No support for comments spanning multiple lines.
88 * - Translator and extracted comments are treated as being the same type.
89 * - Message IDs are allowed to have other encodings as just US-ASCII.
90 *
91 * Items with an empty id are ignored.
92 *
93 * @param resource $resource
94 *
95 * @return array
96 */
97 private function parse($resource)
98 {
99 $stream = fopen($resource, 'r');
100
101 $defaults = array(
102 'ids' => array(),
103 'translated' => null,
104 );
105
106 $messages = array();
107 $item = $defaults;
108
109 while ($line = fgets($stream)) {
110 $line = trim($line);
111
112 if ($line === '') {
113 // Whitespace indicated current item is done
114 $this->addMessage($messages, $item);
115 $item = $defaults;
116 } elseif (substr($line, 0, 7) === 'msgid "') {
117 // We start a new msg so save previous
118 // TODO: this fails when comments or contexts are added
119 $this->addMessage($messages, $item);
120 $item = $defaults;
121 $item['ids']['singular'] = substr($line, 7, -1);
122 } elseif (substr($line, 0, 8) === 'msgstr "') {
123 $item['translated'] = substr($line, 8, -1);
124 } elseif ($line[0] === '"') {
125 $continues = isset($item['translated']) ? 'translated' : 'ids';
126
127 if (is_array($item[$continues])) {
128 end($item[$continues]);
129 $item[$continues][key($item[$continues])] .= substr($line, 1, -1);
130 } else {
131 $item[$continues] .= substr($line, 1, -1);
132 }
133 } elseif (substr($line, 0, 14) === 'msgid_plural "') {
134 $item['ids']['plural'] = substr($line, 14, -1);
135 } elseif (substr($line, 0, 7) === 'msgstr[') {
136 $size = strpos($line, ']');
137 $item['translated'][(integer) substr($line, 7, 1)] = substr($line, $size + 3, -1);
138 }
139
140 }
141 // save last item
142 $this->addMessage($messages, $item);
143 fclose($stream);
144
145 return $messages;
146 }
147
148 /**
149 * Save a translation item to the messeages.
150 *
151 * A .po file could contain by error missing plural indexes. We need to
152 * fix these before saving them.
153 *
154 * @param array $messages
155 * @param array $item
156 */
157 private function addMessage(array &$messages, array $item)
158 {
159 if (is_array($item['translated'])) {
160 $messages[$item['ids']['singular']] = stripslashes($item['translated'][0]);
161 if (isset($item['ids']['plural'])) {
162 $plurals = $item['translated'];
163 // PO are by definition indexed so sort by index.
164 ksort($plurals);
165 // Make sure every index is filled.
166 end($plurals);
167 $count = key($plurals);
168 // Fill missing spots with '-'.
169 $empties = array_fill(0, $count+1, '-');
170 $plurals += $empties;
171 ksort($plurals);
172 $messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
173 }
174 } elseif (!empty($item['ids']['singular'])) {
175 $messages[$item['ids']['singular']] = stripslashes($item['translated']);
176 }
177 }
178}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/QtFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/QtFileLoader.php
new file mode 100644
index 00000000..d64494b8
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/QtFileLoader.php
@@ -0,0 +1,95 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Exception\InvalidResourceException;
16use Symfony\Component\Translation\Exception\NotFoundResourceException;
17use Symfony\Component\Config\Resource\FileResource;
18
19/**
20 * QtFileLoader loads translations from QT Translations XML files.
21 *
22 * @author Benjamin Eberlei <kontakt@beberlei.de>
23 *
24 * @api
25 */
26class QtFileLoader implements LoaderInterface
27{
28 /**
29 * {@inheritdoc}
30 *
31 * @api
32 */
33 public function load($resource, $locale, $domain = 'messages')
34 {
35 if (!stream_is_local($resource)) {
36 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
37 }
38
39 if (!file_exists($resource)) {
40 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
41 }
42
43 $dom = new \DOMDocument();
44 $current = libxml_use_internal_errors(true);
45 if (!@$dom->load($resource, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) {
46 throw new InvalidResourceException(implode("\n", $this->getXmlErrors()));
47 }
48
49 $xpath = new \DOMXPath($dom);
50 $nodes = $xpath->evaluate('//TS/context/name[text()="'.$domain.'"]');
51
52 $catalogue = new MessageCatalogue($locale);
53 if ($nodes->length == 1) {
54 $translations = $nodes->item(0)->nextSibling->parentNode->parentNode->getElementsByTagName('message');
55 foreach ($translations as $translation) {
56 $catalogue->set(
57 (string) $translation->getElementsByTagName('source')->item(0)->nodeValue,
58 (string) $translation->getElementsByTagName('translation')->item(0)->nodeValue,
59 $domain
60 );
61 $translation = $translation->nextSibling;
62 }
63 $catalogue->addResource(new FileResource($resource));
64 }
65
66 libxml_use_internal_errors($current);
67
68 return $catalogue;
69 }
70
71 /**
72 * Returns the XML errors of the internal XML parser
73 *
74 * @return array An array of errors
75 */
76 private function getXmlErrors()
77 {
78 $errors = array();
79 foreach (libxml_get_errors() as $error) {
80 $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
81 LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
82 $error->code,
83 trim($error->message),
84 $error->file ? $error->file : 'n/a',
85 $error->line,
86 $error->column
87 );
88 }
89
90 libxml_clear_errors();
91 libxml_use_internal_errors(false);
92
93 return $errors;
94 }
95}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php
new file mode 100644
index 00000000..0cafc043
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php
@@ -0,0 +1,163 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Exception\InvalidResourceException;
16use Symfony\Component\Translation\Exception\NotFoundResourceException;
17use Symfony\Component\Config\Resource\FileResource;
18
19/**
20 * XliffFileLoader loads translations from XLIFF files.
21 *
22 * @author Fabien Potencier <fabien@symfony.com>
23 *
24 * @api
25 */
26class XliffFileLoader implements LoaderInterface
27{
28 /**
29 * {@inheritdoc}
30 *
31 * @api
32 */
33 public function load($resource, $locale, $domain = 'messages')
34 {
35 if (!stream_is_local($resource)) {
36 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
37 }
38
39 if (!file_exists($resource)) {
40 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
41 }
42
43 list($xml, $encoding) = $this->parseFile($resource);
44 $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
45
46 $catalogue = new MessageCatalogue($locale);
47 foreach ($xml->xpath('//xliff:trans-unit') as $translation) {
48 $attributes = $translation->attributes();
49
50 if (!(isset($attributes['resname']) || isset($translation->source)) || !isset($translation->target)) {
51 continue;
52 }
53
54 $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source;
55 $target = (string) $translation->target;
56
57 // If the xlf file has another encoding specified, try to convert it because
58 // simple_xml will always return utf-8 encoded values
59 if ('UTF-8' !== $encoding && !empty($encoding)) {
60 if (function_exists('mb_convert_encoding')) {
61 $target = mb_convert_encoding($target, $encoding, 'UTF-8');
62 } elseif (function_exists('iconv')) {
63 $target = iconv('UTF-8', $encoding, $target);
64 } else {
65 throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
66 }
67 }
68
69 $catalogue->set((string) $source, $target, $domain);
70 }
71 $catalogue->addResource(new FileResource($resource));
72
73 return $catalogue;
74 }
75
76 /**
77 * Validates and parses the given file into a SimpleXMLElement
78 *
79 * @param string $file
80 *
81 * @throws \RuntimeException
82 *
83 * @return \SimpleXMLElement
84 *
85 * @throws InvalidResourceException
86 */
87 private function parseFile($file)
88 {
89 $internalErrors = libxml_use_internal_errors(true);
90 $disableEntities = libxml_disable_entity_loader(true);
91 libxml_clear_errors();
92
93 $dom = new \DOMDocument();
94 $dom->validateOnParse = true;
95 if (!@$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
96 libxml_disable_entity_loader($disableEntities);
97
98 throw new InvalidResourceException(implode("\n", $this->getXmlErrors($internalErrors)));
99 }
100
101 libxml_disable_entity_loader($disableEntities);
102
103 foreach ($dom->childNodes as $child) {
104 if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
105 libxml_use_internal_errors($internalErrors);
106
107 throw new InvalidResourceException('Document types are not allowed.');
108 }
109 }
110
111 $location = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd';
112 $parts = explode('/', $location);
113 if (0 === stripos($location, 'phar://')) {
114 $tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
115 if ($tmpfile) {
116 copy($location, $tmpfile);
117 $parts = explode('/', str_replace('\\', '/', $tmpfile));
118 }
119 }
120 $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
121 $location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
122
123 $source = file_get_contents(__DIR__.'/schema/dic/xliff-core/xliff-core-1.2-strict.xsd');
124 $source = str_replace('http://www.w3.org/2001/xml.xsd', $location, $source);
125
126 if (!@$dom->schemaValidateSource($source)) {
127 throw new InvalidResourceException(implode("\n", $this->getXmlErrors($internalErrors)));
128 }
129
130 $dom->normalizeDocument();
131
132 libxml_use_internal_errors($internalErrors);
133
134 return array(simplexml_import_dom($dom), strtoupper($dom->encoding));
135 }
136
137 /**
138 * Returns the XML errors of the internal XML parser
139 *
140 * @param Boolean $internalErrors
141 *
142 * @return array An array of errors
143 */
144 private function getXmlErrors($internalErrors)
145 {
146 $errors = array();
147 foreach (libxml_get_errors() as $error) {
148 $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
149 LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
150 $error->code,
151 trim($error->message),
152 $error->file ? $error->file : 'n/a',
153 $error->line,
154 $error->column
155 );
156 }
157
158 libxml_clear_errors();
159 libxml_use_internal_errors($internalErrors);
160
161 return $errors;
162 }
163}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/YamlFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/YamlFileLoader.php
new file mode 100644
index 00000000..66ab2ba5
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/YamlFileLoader.php
@@ -0,0 +1,71 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\Exception\InvalidResourceException;
15use Symfony\Component\Translation\Exception\NotFoundResourceException;
16use Symfony\Component\Config\Resource\FileResource;
17use Symfony\Component\Yaml\Parser as YamlParser;
18use Symfony\Component\Yaml\Exception\ParseException;
19
20/**
21 * YamlFileLoader loads translations from Yaml files.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 *
25 * @api
26 */
27class YamlFileLoader extends ArrayLoader implements LoaderInterface
28{
29 private $yamlParser;
30
31 /**
32 * {@inheritdoc}
33 *
34 * @api
35 */
36 public function load($resource, $locale, $domain = 'messages')
37 {
38 if (!stream_is_local($resource)) {
39 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
40 }
41
42 if (!file_exists($resource)) {
43 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
44 }
45
46 if (null === $this->yamlParser) {
47 $this->yamlParser = new YamlParser();
48 }
49
50 try {
51 $messages = $this->yamlParser->parse(file_get_contents($resource));
52 } catch (ParseException $e) {
53 throw new InvalidResourceException('Error parsing YAML.', 0, $e);
54 }
55
56 // empty file
57 if (null === $messages) {
58 $messages = array();
59 }
60
61 // not an array
62 if (!is_array($messages)) {
63 throw new InvalidResourceException(sprintf('The file "%s" must contain a YAML array.', $resource));
64 }
65
66 $catalogue = parent::load($messages, $locale, $domain);
67 $catalogue->addResource(new FileResource($resource));
68
69 return $catalogue;
70 }
71}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xliff-core-1.2-strict.xsd b/vendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xliff-core-1.2-strict.xsd
new file mode 100644
index 00000000..3ce2a8e8
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xliff-core-1.2-strict.xsd
@@ -0,0 +1,2223 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<!--
4
5May-19-2004:
6- Changed the <choice> for ElemType_header, moving minOccurs="0" maxOccurs="unbounded" from its elements
7to <choice> itself.
8- Added <choice> for ElemType_trans-unit to allow "any order" for <context-group>, <count-group>, <prop-group>, <note>, and
9<alt-trans>.
10
11Oct-2005
12- updated version info to 1.2
13- equiv-trans attribute to <trans-unit> element
14- merged-trans attribute for <group> element
15- Add the <seg-source> element as optional in the <trans-unit> and <alt-trans> content models, at the same level as <source>
16- Create a new value "seg" for the mtype attribute of the <mrk> element
17- Add mid as an optional attribute for the <alt-trans> element
18
19Nov-14-2005
20- Changed name attribute for <context-group> from required to optional
21- Added extension point at <xliff>
22
23Jan-9-2006
24- Added alttranstype type attribute to <alt-trans>, and values
25
26Jan-10-2006
27- Corrected error with overwritten purposeValueList
28- Corrected name="AttrType_Version", attribute should have been "name"
29
30-->
31<xsd:schema xmlns:xlf="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="urn:oasis:names:tc:xliff:document:1.2" xml:lang="en">
32 <!-- Import for xml:lang and xml:space -->
33 <xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
34 <!-- Attributes Lists -->
35 <xsd:simpleType name="XTend">
36 <xsd:restriction base="xsd:string">
37 <xsd:pattern value="x-[^\s]+"/>
38 </xsd:restriction>
39 </xsd:simpleType>
40 <xsd:simpleType name="context-typeValueList">
41 <xsd:annotation>
42 <xsd:documentation>Values for the attribute 'context-type'.</xsd:documentation>
43 </xsd:annotation>
44 <xsd:restriction base="xsd:string">
45 <xsd:enumeration value="database">
46 <xsd:annotation>
47 <xsd:documentation>Indicates a database content.</xsd:documentation>
48 </xsd:annotation>
49 </xsd:enumeration>
50 <xsd:enumeration value="element">
51 <xsd:annotation>
52 <xsd:documentation>Indicates the content of an element within an XML document.</xsd:documentation>
53 </xsd:annotation>
54 </xsd:enumeration>
55 <xsd:enumeration value="elementtitle">
56 <xsd:annotation>
57 <xsd:documentation>Indicates the name of an element within an XML document.</xsd:documentation>
58 </xsd:annotation>
59 </xsd:enumeration>
60 <xsd:enumeration value="linenumber">
61 <xsd:annotation>
62 <xsd:documentation>Indicates the line number from the sourcefile (see context-type="sourcefile") where the &lt;source&gt; is found.</xsd:documentation>
63 </xsd:annotation>
64 </xsd:enumeration>
65 <xsd:enumeration value="numparams">
66 <xsd:annotation>
67 <xsd:documentation>Indicates a the number of parameters contained within the &lt;source&gt;.</xsd:documentation>
68 </xsd:annotation>
69 </xsd:enumeration>
70 <xsd:enumeration value="paramnotes">
71 <xsd:annotation>
72 <xsd:documentation>Indicates notes pertaining to the parameters in the &lt;source&gt;.</xsd:documentation>
73 </xsd:annotation>
74 </xsd:enumeration>
75 <xsd:enumeration value="record">
76 <xsd:annotation>
77 <xsd:documentation>Indicates the content of a record within a database.</xsd:documentation>
78 </xsd:annotation>
79 </xsd:enumeration>
80 <xsd:enumeration value="recordtitle">
81 <xsd:annotation>
82 <xsd:documentation>Indicates the name of a record within a database.</xsd:documentation>
83 </xsd:annotation>
84 </xsd:enumeration>
85 <xsd:enumeration value="sourcefile">
86 <xsd:annotation>
87 <xsd:documentation>Indicates the original source file in the case that multiple files are merged to form the original file from which the XLIFF file is created. This differs from the original &lt;file&gt; attribute in that this sourcefile is one of many that make up that file.</xsd:documentation>
88 </xsd:annotation>
89 </xsd:enumeration>
90 </xsd:restriction>
91 </xsd:simpleType>
92 <xsd:simpleType name="count-typeValueList">
93 <xsd:annotation>
94 <xsd:documentation>Values for the attribute 'count-type'.</xsd:documentation>
95 </xsd:annotation>
96 <xsd:restriction base="xsd:NMTOKEN">
97 <xsd:enumeration value="num-usages">
98 <xsd:annotation>
99 <xsd:documentation>Indicates the count units are items that are used X times in a certain context; example: this is a reusable text unit which is used 42 times in other texts.</xsd:documentation>
100 </xsd:annotation>
101 </xsd:enumeration>
102 <xsd:enumeration value="repetition">
103 <xsd:annotation>
104 <xsd:documentation>Indicates the count units are translation units existing already in the same document.</xsd:documentation>
105 </xsd:annotation>
106 </xsd:enumeration>
107 <xsd:enumeration value="total">
108 <xsd:annotation>
109 <xsd:documentation>Indicates a total count.</xsd:documentation>
110 </xsd:annotation>
111 </xsd:enumeration>
112 </xsd:restriction>
113 </xsd:simpleType>
114 <xsd:simpleType name="InlineDelimitersValueList">
115 <xsd:annotation>
116 <xsd:documentation>Values for the attribute 'ctype' when used other elements than &lt;ph&gt; or &lt;x&gt;.</xsd:documentation>
117 </xsd:annotation>
118 <xsd:restriction base="xsd:NMTOKEN">
119 <xsd:enumeration value="bold">
120 <xsd:annotation>
121 <xsd:documentation>Indicates a run of bolded text.</xsd:documentation>
122 </xsd:annotation>
123 </xsd:enumeration>
124 <xsd:enumeration value="italic">
125 <xsd:annotation>
126 <xsd:documentation>Indicates a run of text in italics.</xsd:documentation>
127 </xsd:annotation>
128 </xsd:enumeration>
129 <xsd:enumeration value="underlined">
130 <xsd:annotation>
131 <xsd:documentation>Indicates a run of underlined text.</xsd:documentation>
132 </xsd:annotation>
133 </xsd:enumeration>
134 <xsd:enumeration value="link">
135 <xsd:annotation>
136 <xsd:documentation>Indicates a run of hyper-text.</xsd:documentation>
137 </xsd:annotation>
138 </xsd:enumeration>
139 </xsd:restriction>
140 </xsd:simpleType>
141 <xsd:simpleType name="InlinePlaceholdersValueList">
142 <xsd:annotation>
143 <xsd:documentation>Values for the attribute 'ctype' when used with &lt;ph&gt; or &lt;x&gt;.</xsd:documentation>
144 </xsd:annotation>
145 <xsd:restriction base="xsd:NMTOKEN">
146 <xsd:enumeration value="image">
147 <xsd:annotation>
148 <xsd:documentation>Indicates a inline image.</xsd:documentation>
149 </xsd:annotation>
150 </xsd:enumeration>
151 <xsd:enumeration value="pb">
152 <xsd:annotation>
153 <xsd:documentation>Indicates a page break.</xsd:documentation>
154 </xsd:annotation>
155 </xsd:enumeration>
156 <xsd:enumeration value="lb">
157 <xsd:annotation>
158 <xsd:documentation>Indicates a line break.</xsd:documentation>
159 </xsd:annotation>
160 </xsd:enumeration>
161 </xsd:restriction>
162 </xsd:simpleType>
163 <xsd:simpleType name="mime-typeValueList">
164 <xsd:restriction base="xsd:string">
165 <xsd:pattern value="(text|multipart|message|application|image|audio|video|model)(/.+)*"/>
166 </xsd:restriction>
167 </xsd:simpleType>
168 <xsd:simpleType name="datatypeValueList">
169 <xsd:annotation>
170 <xsd:documentation>Values for the attribute 'datatype'.</xsd:documentation>
171 </xsd:annotation>
172 <xsd:restriction base="xsd:NMTOKEN">
173 <xsd:enumeration value="asp">
174 <xsd:annotation>
175 <xsd:documentation>Indicates Active Server Page data.</xsd:documentation>
176 </xsd:annotation>
177 </xsd:enumeration>
178 <xsd:enumeration value="c">
179 <xsd:annotation>
180 <xsd:documentation>Indicates C source file data.</xsd:documentation>
181 </xsd:annotation>
182 </xsd:enumeration>
183 <xsd:enumeration value="cdf">
184 <xsd:annotation>
185 <xsd:documentation>Indicates Channel Definition Format (CDF) data.</xsd:documentation>
186 </xsd:annotation>
187 </xsd:enumeration>
188 <xsd:enumeration value="cfm">
189 <xsd:annotation>
190 <xsd:documentation>Indicates ColdFusion data.</xsd:documentation>
191 </xsd:annotation>
192 </xsd:enumeration>
193 <xsd:enumeration value="cpp">
194 <xsd:annotation>
195 <xsd:documentation>Indicates C++ source file data.</xsd:documentation>
196 </xsd:annotation>
197 </xsd:enumeration>
198 <xsd:enumeration value="csharp">
199 <xsd:annotation>
200 <xsd:documentation>Indicates C-Sharp data.</xsd:documentation>
201 </xsd:annotation>
202 </xsd:enumeration>
203 <xsd:enumeration value="cstring">
204 <xsd:annotation>
205 <xsd:documentation>Indicates strings from C, ASM, and driver files data.</xsd:documentation>
206 </xsd:annotation>
207 </xsd:enumeration>
208 <xsd:enumeration value="csv">
209 <xsd:annotation>
210 <xsd:documentation>Indicates comma-separated values data.</xsd:documentation>
211 </xsd:annotation>
212 </xsd:enumeration>
213 <xsd:enumeration value="database">
214 <xsd:annotation>
215 <xsd:documentation>Indicates database data.</xsd:documentation>
216 </xsd:annotation>
217 </xsd:enumeration>
218 <xsd:enumeration value="documentfooter">
219 <xsd:annotation>
220 <xsd:documentation>Indicates portions of document that follows data and contains metadata.</xsd:documentation>
221 </xsd:annotation>
222 </xsd:enumeration>
223 <xsd:enumeration value="documentheader">
224 <xsd:annotation>
225 <xsd:documentation>Indicates portions of document that precedes data and contains metadata.</xsd:documentation>
226 </xsd:annotation>
227 </xsd:enumeration>
228 <xsd:enumeration value="filedialog">
229 <xsd:annotation>
230 <xsd:documentation>Indicates data from standard UI file operations dialogs (e.g., Open, Save, Save As, Export, Import).</xsd:documentation>
231 </xsd:annotation>
232 </xsd:enumeration>
233 <xsd:enumeration value="form">
234 <xsd:annotation>
235 <xsd:documentation>Indicates standard user input screen data.</xsd:documentation>
236 </xsd:annotation>
237 </xsd:enumeration>
238 <xsd:enumeration value="html">
239 <xsd:annotation>
240 <xsd:documentation>Indicates HyperText Markup Language (HTML) data - document instance.</xsd:documentation>
241 </xsd:annotation>
242 </xsd:enumeration>
243 <xsd:enumeration value="htmlbody">
244 <xsd:annotation>
245 <xsd:documentation>Indicates content within an HTML document’s &lt;body&gt; element.</xsd:documentation>
246 </xsd:annotation>
247 </xsd:enumeration>
248 <xsd:enumeration value="ini">
249 <xsd:annotation>
250 <xsd:documentation>Indicates Windows INI file data.</xsd:documentation>
251 </xsd:annotation>
252 </xsd:enumeration>
253 <xsd:enumeration value="interleaf">
254 <xsd:annotation>
255 <xsd:documentation>Indicates Interleaf data.</xsd:documentation>
256 </xsd:annotation>
257 </xsd:enumeration>
258 <xsd:enumeration value="javaclass">
259 <xsd:annotation>
260 <xsd:documentation>Indicates Java source file data (extension '.java').</xsd:documentation>
261 </xsd:annotation>
262 </xsd:enumeration>
263 <xsd:enumeration value="javapropertyresourcebundle">
264 <xsd:annotation>
265 <xsd:documentation>Indicates Java property resource bundle data.</xsd:documentation>
266 </xsd:annotation>
267 </xsd:enumeration>
268 <xsd:enumeration value="javalistresourcebundle">
269 <xsd:annotation>
270 <xsd:documentation>Indicates Java list resource bundle data.</xsd:documentation>
271 </xsd:annotation>
272 </xsd:enumeration>
273 <xsd:enumeration value="javascript">
274 <xsd:annotation>
275 <xsd:documentation>Indicates JavaScript source file data.</xsd:documentation>
276 </xsd:annotation>
277 </xsd:enumeration>
278 <xsd:enumeration value="jscript">
279 <xsd:annotation>
280 <xsd:documentation>Indicates JScript source file data.</xsd:documentation>
281 </xsd:annotation>
282 </xsd:enumeration>
283 <xsd:enumeration value="layout">
284 <xsd:annotation>
285 <xsd:documentation>Indicates information relating to formatting.</xsd:documentation>
286 </xsd:annotation>
287 </xsd:enumeration>
288 <xsd:enumeration value="lisp">
289 <xsd:annotation>
290 <xsd:documentation>Indicates LISP source file data.</xsd:documentation>
291 </xsd:annotation>
292 </xsd:enumeration>
293 <xsd:enumeration value="margin">
294 <xsd:annotation>
295 <xsd:documentation>Indicates information relating to margin formats.</xsd:documentation>
296 </xsd:annotation>
297 </xsd:enumeration>
298 <xsd:enumeration value="menufile">
299 <xsd:annotation>
300 <xsd:documentation>Indicates a file containing menu.</xsd:documentation>
301 </xsd:annotation>
302 </xsd:enumeration>
303 <xsd:enumeration value="messagefile">
304 <xsd:annotation>
305 <xsd:documentation>Indicates numerically identified string table.</xsd:documentation>
306 </xsd:annotation>
307 </xsd:enumeration>
308 <xsd:enumeration value="mif">
309 <xsd:annotation>
310 <xsd:documentation>Indicates Maker Interchange Format (MIF) data.</xsd:documentation>
311 </xsd:annotation>
312 </xsd:enumeration>
313 <xsd:enumeration value="mimetype">
314 <xsd:annotation>
315 <xsd:documentation>Indicates that the datatype attribute value is a MIME Type value and is defined in the mime-type attribute.</xsd:documentation>
316 </xsd:annotation>
317 </xsd:enumeration>
318 <xsd:enumeration value="mo">
319 <xsd:annotation>
320 <xsd:documentation>Indicates GNU Machine Object data.</xsd:documentation>
321 </xsd:annotation>
322 </xsd:enumeration>
323 <xsd:enumeration value="msglib">
324 <xsd:annotation>
325 <xsd:documentation>Indicates Message Librarian strings created by Novell's Message Librarian Tool.</xsd:documentation>
326 </xsd:annotation>
327 </xsd:enumeration>
328 <xsd:enumeration value="pagefooter">
329 <xsd:annotation>
330 <xsd:documentation>Indicates information to be displayed at the bottom of each page of a document.</xsd:documentation>
331 </xsd:annotation>
332 </xsd:enumeration>
333 <xsd:enumeration value="pageheader">
334 <xsd:annotation>
335 <xsd:documentation>Indicates information to be displayed at the top of each page of a document.</xsd:documentation>
336 </xsd:annotation>
337 </xsd:enumeration>
338 <xsd:enumeration value="parameters">
339 <xsd:annotation>
340 <xsd:documentation>Indicates a list of property values (e.g., settings within INI files or preferences dialog).</xsd:documentation>
341 </xsd:annotation>
342 </xsd:enumeration>
343 <xsd:enumeration value="pascal">
344 <xsd:annotation>
345 <xsd:documentation>Indicates Pascal source file data.</xsd:documentation>
346 </xsd:annotation>
347 </xsd:enumeration>
348 <xsd:enumeration value="php">
349 <xsd:annotation>
350 <xsd:documentation>Indicates Hypertext Preprocessor data.</xsd:documentation>
351 </xsd:annotation>
352 </xsd:enumeration>
353 <xsd:enumeration value="plaintext">
354 <xsd:annotation>
355 <xsd:documentation>Indicates plain text file (no formatting other than, possibly, wrapping).</xsd:documentation>
356 </xsd:annotation>
357 </xsd:enumeration>
358 <xsd:enumeration value="po">
359 <xsd:annotation>
360 <xsd:documentation>Indicates GNU Portable Object file.</xsd:documentation>
361 </xsd:annotation>
362 </xsd:enumeration>
363 <xsd:enumeration value="report">
364 <xsd:annotation>
365 <xsd:documentation>Indicates dynamically generated user defined document. e.g. Oracle Report, Crystal Report, etc.</xsd:documentation>
366 </xsd:annotation>
367 </xsd:enumeration>
368 <xsd:enumeration value="resources">
369 <xsd:annotation>
370 <xsd:documentation>Indicates Windows .NET binary resources.</xsd:documentation>
371 </xsd:annotation>
372 </xsd:enumeration>
373 <xsd:enumeration value="resx">
374 <xsd:annotation>
375 <xsd:documentation>Indicates Windows .NET Resources.</xsd:documentation>
376 </xsd:annotation>
377 </xsd:enumeration>
378 <xsd:enumeration value="rtf">
379 <xsd:annotation>
380 <xsd:documentation>Indicates Rich Text Format (RTF) data.</xsd:documentation>
381 </xsd:annotation>
382 </xsd:enumeration>
383 <xsd:enumeration value="sgml">
384 <xsd:annotation>
385 <xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - document instance.</xsd:documentation>
386 </xsd:annotation>
387 </xsd:enumeration>
388 <xsd:enumeration value="sgmldtd">
389 <xsd:annotation>
390 <xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - Document Type Definition (DTD).</xsd:documentation>
391 </xsd:annotation>
392 </xsd:enumeration>
393 <xsd:enumeration value="svg">
394 <xsd:annotation>
395 <xsd:documentation>Indicates Scalable Vector Graphic (SVG) data.</xsd:documentation>
396 </xsd:annotation>
397 </xsd:enumeration>
398 <xsd:enumeration value="vbscript">
399 <xsd:annotation>
400 <xsd:documentation>Indicates VisualBasic Script source file.</xsd:documentation>
401 </xsd:annotation>
402 </xsd:enumeration>
403 <xsd:enumeration value="warning">
404 <xsd:annotation>
405 <xsd:documentation>Indicates warning message.</xsd:documentation>
406 </xsd:annotation>
407 </xsd:enumeration>
408 <xsd:enumeration value="winres">
409 <xsd:annotation>
410 <xsd:documentation>Indicates Windows (Win32) resources (i.e. resources extracted from an RC script, a message file, or a compiled file).</xsd:documentation>
411 </xsd:annotation>
412 </xsd:enumeration>
413 <xsd:enumeration value="xhtml">
414 <xsd:annotation>
415 <xsd:documentation>Indicates Extensible HyperText Markup Language (XHTML) data - document instance.</xsd:documentation>
416 </xsd:annotation>
417 </xsd:enumeration>
418 <xsd:enumeration value="xml">
419 <xsd:annotation>
420 <xsd:documentation>Indicates Extensible Markup Language (XML) data - document instance.</xsd:documentation>
421 </xsd:annotation>
422 </xsd:enumeration>
423 <xsd:enumeration value="xmldtd">
424 <xsd:annotation>
425 <xsd:documentation>Indicates Extensible Markup Language (XML) data - Document Type Definition (DTD).</xsd:documentation>
426 </xsd:annotation>
427 </xsd:enumeration>
428 <xsd:enumeration value="xsl">
429 <xsd:annotation>
430 <xsd:documentation>Indicates Extensible Stylesheet Language (XSL) data.</xsd:documentation>
431 </xsd:annotation>
432 </xsd:enumeration>
433 <xsd:enumeration value="xul">
434 <xsd:annotation>
435 <xsd:documentation>Indicates XUL elements.</xsd:documentation>
436 </xsd:annotation>
437 </xsd:enumeration>
438 </xsd:restriction>
439 </xsd:simpleType>
440 <xsd:simpleType name="mtypeValueList">
441 <xsd:annotation>
442 <xsd:documentation>Values for the attribute 'mtype'.</xsd:documentation>
443 </xsd:annotation>
444 <xsd:restriction base="xsd:NMTOKEN">
445 <xsd:enumeration value="abbrev">
446 <xsd:annotation>
447 <xsd:documentation>Indicates the marked text is an abbreviation.</xsd:documentation>
448 </xsd:annotation>
449 </xsd:enumeration>
450 <xsd:enumeration value="abbreviated-form">
451 <xsd:annotation>
452 <xsd:documentation>ISO-12620 2.1.8: A term resulting from the omission of any part of the full term while designating the same concept.</xsd:documentation>
453 </xsd:annotation>
454 </xsd:enumeration>
455 <xsd:enumeration value="abbreviation">
456 <xsd:annotation>
457 <xsd:documentation>ISO-12620 2.1.8.1: An abbreviated form of a simple term resulting from the omission of some of its letters (e.g. 'adj.' for 'adjective').</xsd:documentation>
458 </xsd:annotation>
459 </xsd:enumeration>
460 <xsd:enumeration value="acronym">
461 <xsd:annotation>
462 <xsd:documentation>ISO-12620 2.1.8.4: An abbreviated form of a term made up of letters from the full form of a multiword term strung together into a sequence pronounced only syllabically (e.g. 'radar' for 'radio detecting and ranging').</xsd:documentation>
463 </xsd:annotation>
464 </xsd:enumeration>
465 <xsd:enumeration value="appellation">
466 <xsd:annotation>
467 <xsd:documentation>ISO-12620: A proper-name term, such as the name of an agency or other proper entity.</xsd:documentation>
468 </xsd:annotation>
469 </xsd:enumeration>
470 <xsd:enumeration value="collocation">
471 <xsd:annotation>
472 <xsd:documentation>ISO-12620 2.1.18.1: A recurrent word combination characterized by cohesion in that the components of the collocation must co-occur within an utterance or series of utterances, even though they do not necessarily have to maintain immediate proximity to one another.</xsd:documentation>
473 </xsd:annotation>
474 </xsd:enumeration>
475 <xsd:enumeration value="common-name">
476 <xsd:annotation>
477 <xsd:documentation>ISO-12620 2.1.5: A synonym for an international scientific term that is used in general discourse in a given language.</xsd:documentation>
478 </xsd:annotation>
479 </xsd:enumeration>
480 <xsd:enumeration value="datetime">
481 <xsd:annotation>
482 <xsd:documentation>Indicates the marked text is a date and/or time.</xsd:documentation>
483 </xsd:annotation>
484 </xsd:enumeration>
485 <xsd:enumeration value="equation">
486 <xsd:annotation>
487 <xsd:documentation>ISO-12620 2.1.15: An expression used to represent a concept based on a statement that two mathematical expressions are, for instance, equal as identified by the equal sign (=), or assigned to one another by a similar sign.</xsd:documentation>
488 </xsd:annotation>
489 </xsd:enumeration>
490 <xsd:enumeration value="expanded-form">
491 <xsd:annotation>
492 <xsd:documentation>ISO-12620 2.1.7: The complete representation of a term for which there is an abbreviated form.</xsd:documentation>
493 </xsd:annotation>
494 </xsd:enumeration>
495 <xsd:enumeration value="formula">
496 <xsd:annotation>
497 <xsd:documentation>ISO-12620 2.1.14: Figures, symbols or the like used to express a concept briefly, such as a mathematical or chemical formula.</xsd:documentation>
498 </xsd:annotation>
499 </xsd:enumeration>
500 <xsd:enumeration value="head-term">
501 <xsd:annotation>
502 <xsd:documentation>ISO-12620 2.1.1: The concept designation that has been chosen to head a terminological record.</xsd:documentation>
503 </xsd:annotation>
504 </xsd:enumeration>
505 <xsd:enumeration value="initialism">
506 <xsd:annotation>
507 <xsd:documentation>ISO-12620 2.1.8.3: An abbreviated form of a term consisting of some of the initial letters of the words making up a multiword term or the term elements making up a compound term when these letters are pronounced individually (e.g. 'BSE' for 'bovine spongiform encephalopathy').</xsd:documentation>
508 </xsd:annotation>
509 </xsd:enumeration>
510 <xsd:enumeration value="international-scientific-term">
511 <xsd:annotation>
512 <xsd:documentation>ISO-12620 2.1.4: A term that is part of an international scientific nomenclature as adopted by an appropriate scientific body.</xsd:documentation>
513 </xsd:annotation>
514 </xsd:enumeration>
515 <xsd:enumeration value="internationalism">
516 <xsd:annotation>
517 <xsd:documentation>ISO-12620 2.1.6: A term that has the same or nearly identical orthographic or phonemic form in many languages.</xsd:documentation>
518 </xsd:annotation>
519 </xsd:enumeration>
520 <xsd:enumeration value="logical-expression">
521 <xsd:annotation>
522 <xsd:documentation>ISO-12620 2.1.16: An expression used to represent a concept based on mathematical or logical relations, such as statements of inequality, set relationships, Boolean operations, and the like.</xsd:documentation>
523 </xsd:annotation>
524 </xsd:enumeration>
525 <xsd:enumeration value="materials-management-unit">
526 <xsd:annotation>
527 <xsd:documentation>ISO-12620 2.1.17: A unit to track object.</xsd:documentation>
528 </xsd:annotation>
529 </xsd:enumeration>
530 <xsd:enumeration value="name">
531 <xsd:annotation>
532 <xsd:documentation>Indicates the marked text is a name.</xsd:documentation>
533 </xsd:annotation>
534 </xsd:enumeration>
535 <xsd:enumeration value="near-synonym">
536 <xsd:annotation>
537 <xsd:documentation>ISO-12620 2.1.3: A term that represents the same or a very similar concept as another term in the same language, but for which interchangeability is limited to some contexts and inapplicable in others.</xsd:documentation>
538 </xsd:annotation>
539 </xsd:enumeration>
540 <xsd:enumeration value="part-number">
541 <xsd:annotation>
542 <xsd:documentation>ISO-12620 2.1.17.2: A unique alphanumeric designation assigned to an object in a manufacturing system.</xsd:documentation>
543 </xsd:annotation>
544 </xsd:enumeration>
545 <xsd:enumeration value="phrase">
546 <xsd:annotation>
547 <xsd:documentation>Indicates the marked text is a phrase.</xsd:documentation>
548 </xsd:annotation>
549 </xsd:enumeration>
550 <xsd:enumeration value="phraseological-unit">
551 <xsd:annotation>
552 <xsd:documentation>ISO-12620 2.1.18: Any group of two or more words that form a unit, the meaning of which frequently cannot be deduced based on the combined sense of the words making up the phrase.</xsd:documentation>
553 </xsd:annotation>
554 </xsd:enumeration>
555 <xsd:enumeration value="protected">
556 <xsd:annotation>
557 <xsd:documentation>Indicates the marked text should not be translated.</xsd:documentation>
558 </xsd:annotation>
559 </xsd:enumeration>
560 <xsd:enumeration value="romanized-form">
561 <xsd:annotation>
562 <xsd:documentation>ISO-12620 2.1.12: A form of a term resulting from an operation whereby non-Latin writing systems are converted to the Latin alphabet.</xsd:documentation>
563 </xsd:annotation>
564 </xsd:enumeration>
565 <xsd:enumeration value="seg">
566 <xsd:annotation>
567 <xsd:documentation>Indicates that the marked text represents a segment.</xsd:documentation>
568 </xsd:annotation>
569 </xsd:enumeration>
570 <xsd:enumeration value="set-phrase">
571 <xsd:annotation>
572 <xsd:documentation>ISO-12620 2.1.18.2: A fixed, lexicalized phrase.</xsd:documentation>
573 </xsd:annotation>
574 </xsd:enumeration>
575 <xsd:enumeration value="short-form">
576 <xsd:annotation>
577 <xsd:documentation>ISO-12620 2.1.8.2: A variant of a multiword term that includes fewer words than the full form of the term (e.g. 'Group of Twenty-four' for 'Intergovernmental Group of Twenty-four on International Monetary Affairs').</xsd:documentation>
578 </xsd:annotation>
579 </xsd:enumeration>
580 <xsd:enumeration value="sku">
581 <xsd:annotation>
582 <xsd:documentation>ISO-12620 2.1.17.1: Stock keeping unit, an inventory item identified by a unique alphanumeric designation assigned to an object in an inventory control system.</xsd:documentation>
583 </xsd:annotation>
584 </xsd:enumeration>
585 <xsd:enumeration value="standard-text">
586 <xsd:annotation>
587 <xsd:documentation>ISO-12620 2.1.19: A fixed chunk of recurring text.</xsd:documentation>
588 </xsd:annotation>
589 </xsd:enumeration>
590 <xsd:enumeration value="symbol">
591 <xsd:annotation>
592 <xsd:documentation>ISO-12620 2.1.13: A designation of a concept by letters, numerals, pictograms or any combination thereof.</xsd:documentation>
593 </xsd:annotation>
594 </xsd:enumeration>
595 <xsd:enumeration value="synonym">
596 <xsd:annotation>
597 <xsd:documentation>ISO-12620 2.1.2: Any term that represents the same or a very similar concept as the main entry term in a term entry.</xsd:documentation>
598 </xsd:annotation>
599 </xsd:enumeration>
600 <xsd:enumeration value="synonymous-phrase">
601 <xsd:annotation>
602 <xsd:documentation>ISO-12620 2.1.18.3: Phraseological unit in a language that expresses the same semantic content as another phrase in that same language.</xsd:documentation>
603 </xsd:annotation>
604 </xsd:enumeration>
605 <xsd:enumeration value="term">
606 <xsd:annotation>
607 <xsd:documentation>Indicates the marked text is a term.</xsd:documentation>
608 </xsd:annotation>
609 </xsd:enumeration>
610 <xsd:enumeration value="transcribed-form">
611 <xsd:annotation>
612 <xsd:documentation>ISO-12620 2.1.11: A form of a term resulting from an operation whereby the characters of one writing system are represented by characters from another writing system, taking into account the pronunciation of the characters converted.</xsd:documentation>
613 </xsd:annotation>
614 </xsd:enumeration>
615 <xsd:enumeration value="transliterated-form">
616 <xsd:annotation>
617 <xsd:documentation>ISO-12620 2.1.10: A form of a term resulting from an operation whereby the characters of an alphabetic writing system are represented by characters from another alphabetic writing system.</xsd:documentation>
618 </xsd:annotation>
619 </xsd:enumeration>
620 <xsd:enumeration value="truncated-term">
621 <xsd:annotation>
622 <xsd:documentation>ISO-12620 2.1.8.5: An abbreviated form of a term resulting from the omission of one or more term elements or syllables (e.g. 'flu' for 'influenza').</xsd:documentation>
623 </xsd:annotation>
624 </xsd:enumeration>
625 <xsd:enumeration value="variant">
626 <xsd:annotation>
627 <xsd:documentation>ISO-12620 2.1.9: One of the alternate forms of a term.</xsd:documentation>
628 </xsd:annotation>
629 </xsd:enumeration>
630 </xsd:restriction>
631 </xsd:simpleType>
632 <xsd:simpleType name="restypeValueList">
633 <xsd:annotation>
634 <xsd:documentation>Values for the attribute 'restype'.</xsd:documentation>
635 </xsd:annotation>
636 <xsd:restriction base="xsd:NMTOKEN">
637 <xsd:enumeration value="auto3state">
638 <xsd:annotation>
639 <xsd:documentation>Indicates a Windows RC AUTO3STATE control.</xsd:documentation>
640 </xsd:annotation>
641 </xsd:enumeration>
642 <xsd:enumeration value="autocheckbox">
643 <xsd:annotation>
644 <xsd:documentation>Indicates a Windows RC AUTOCHECKBOX control.</xsd:documentation>
645 </xsd:annotation>
646 </xsd:enumeration>
647 <xsd:enumeration value="autoradiobutton">
648 <xsd:annotation>
649 <xsd:documentation>Indicates a Windows RC AUTORADIOBUTTON control.</xsd:documentation>
650 </xsd:annotation>
651 </xsd:enumeration>
652 <xsd:enumeration value="bedit">
653 <xsd:annotation>
654 <xsd:documentation>Indicates a Windows RC BEDIT control.</xsd:documentation>
655 </xsd:annotation>
656 </xsd:enumeration>
657 <xsd:enumeration value="bitmap">
658 <xsd:annotation>
659 <xsd:documentation>Indicates a bitmap, for example a BITMAP resource in Windows.</xsd:documentation>
660 </xsd:annotation>
661 </xsd:enumeration>
662 <xsd:enumeration value="button">
663 <xsd:annotation>
664 <xsd:documentation>Indicates a button object, for example a BUTTON control Windows.</xsd:documentation>
665 </xsd:annotation>
666 </xsd:enumeration>
667 <xsd:enumeration value="caption">
668 <xsd:annotation>
669 <xsd:documentation>Indicates a caption, such as the caption of a dialog box.</xsd:documentation>
670 </xsd:annotation>
671 </xsd:enumeration>
672 <xsd:enumeration value="cell">
673 <xsd:annotation>
674 <xsd:documentation>Indicates the cell in a table, for example the content of the &lt;td&gt; element in HTML.</xsd:documentation>
675 </xsd:annotation>
676 </xsd:enumeration>
677 <xsd:enumeration value="checkbox">
678 <xsd:annotation>
679 <xsd:documentation>Indicates check box object, for example a CHECKBOX control in Windows.</xsd:documentation>
680 </xsd:annotation>
681 </xsd:enumeration>
682 <xsd:enumeration value="checkboxmenuitem">
683 <xsd:annotation>
684 <xsd:documentation>Indicates a menu item with an associated checkbox.</xsd:documentation>
685 </xsd:annotation>
686 </xsd:enumeration>
687 <xsd:enumeration value="checkedlistbox">
688 <xsd:annotation>
689 <xsd:documentation>Indicates a list box, but with a check-box for each item.</xsd:documentation>
690 </xsd:annotation>
691 </xsd:enumeration>
692 <xsd:enumeration value="colorchooser">
693 <xsd:annotation>
694 <xsd:documentation>Indicates a color selection dialog.</xsd:documentation>
695 </xsd:annotation>
696 </xsd:enumeration>
697 <xsd:enumeration value="combobox">
698 <xsd:annotation>
699 <xsd:documentation>Indicates a combination of edit box and listbox object, for example a COMBOBOX control in Windows.</xsd:documentation>
700 </xsd:annotation>
701 </xsd:enumeration>
702 <xsd:enumeration value="comboboxexitem">
703 <xsd:annotation>
704 <xsd:documentation>Indicates an initialization entry of an extended combobox DLGINIT resource block. (code 0x1234).</xsd:documentation>
705 </xsd:annotation>
706 </xsd:enumeration>
707 <xsd:enumeration value="comboboxitem">
708 <xsd:annotation>
709 <xsd:documentation>Indicates an initialization entry of a combobox DLGINIT resource block (code 0x0403).</xsd:documentation>
710 </xsd:annotation>
711 </xsd:enumeration>
712 <xsd:enumeration value="component">
713 <xsd:annotation>
714 <xsd:documentation>Indicates a UI base class element that cannot be represented by any other element.</xsd:documentation>
715 </xsd:annotation>
716 </xsd:enumeration>
717 <xsd:enumeration value="contextmenu">
718 <xsd:annotation>
719 <xsd:documentation>Indicates a context menu.</xsd:documentation>
720 </xsd:annotation>
721 </xsd:enumeration>
722 <xsd:enumeration value="ctext">
723 <xsd:annotation>
724 <xsd:documentation>Indicates a Windows RC CTEXT control.</xsd:documentation>
725 </xsd:annotation>
726 </xsd:enumeration>
727 <xsd:enumeration value="cursor">
728 <xsd:annotation>
729 <xsd:documentation>Indicates a cursor, for example a CURSOR resource in Windows.</xsd:documentation>
730 </xsd:annotation>
731 </xsd:enumeration>
732 <xsd:enumeration value="datetimepicker">
733 <xsd:annotation>
734 <xsd:documentation>Indicates a date/time picker.</xsd:documentation>
735 </xsd:annotation>
736 </xsd:enumeration>
737 <xsd:enumeration value="defpushbutton">
738 <xsd:annotation>
739 <xsd:documentation>Indicates a Windows RC DEFPUSHBUTTON control.</xsd:documentation>
740 </xsd:annotation>
741 </xsd:enumeration>
742 <xsd:enumeration value="dialog">
743 <xsd:annotation>
744 <xsd:documentation>Indicates a dialog box.</xsd:documentation>
745 </xsd:annotation>
746 </xsd:enumeration>
747 <xsd:enumeration value="dlginit">
748 <xsd:annotation>
749 <xsd:documentation>Indicates a Windows RC DLGINIT resource block.</xsd:documentation>
750 </xsd:annotation>
751 </xsd:enumeration>
752 <xsd:enumeration value="edit">
753 <xsd:annotation>
754 <xsd:documentation>Indicates an edit box object, for example an EDIT control in Windows.</xsd:documentation>
755 </xsd:annotation>
756 </xsd:enumeration>
757 <xsd:enumeration value="file">
758 <xsd:annotation>
759 <xsd:documentation>Indicates a filename.</xsd:documentation>
760 </xsd:annotation>
761 </xsd:enumeration>
762 <xsd:enumeration value="filechooser">
763 <xsd:annotation>
764 <xsd:documentation>Indicates a file dialog.</xsd:documentation>
765 </xsd:annotation>
766 </xsd:enumeration>
767 <xsd:enumeration value="fn">
768 <xsd:annotation>
769 <xsd:documentation>Indicates a footnote.</xsd:documentation>
770 </xsd:annotation>
771 </xsd:enumeration>
772 <xsd:enumeration value="font">
773 <xsd:annotation>
774 <xsd:documentation>Indicates a font name.</xsd:documentation>
775 </xsd:annotation>
776 </xsd:enumeration>
777 <xsd:enumeration value="footer">
778 <xsd:annotation>
779 <xsd:documentation>Indicates a footer.</xsd:documentation>
780 </xsd:annotation>
781 </xsd:enumeration>
782 <xsd:enumeration value="frame">
783 <xsd:annotation>
784 <xsd:documentation>Indicates a frame object.</xsd:documentation>
785 </xsd:annotation>
786 </xsd:enumeration>
787 <xsd:enumeration value="grid">
788 <xsd:annotation>
789 <xsd:documentation>Indicates a XUL grid element.</xsd:documentation>
790 </xsd:annotation>
791 </xsd:enumeration>
792 <xsd:enumeration value="groupbox">
793 <xsd:annotation>
794 <xsd:documentation>Indicates a groupbox object, for example a GROUPBOX control in Windows.</xsd:documentation>
795 </xsd:annotation>
796 </xsd:enumeration>
797 <xsd:enumeration value="header">
798 <xsd:annotation>
799 <xsd:documentation>Indicates a header item.</xsd:documentation>
800 </xsd:annotation>
801 </xsd:enumeration>
802 <xsd:enumeration value="heading">
803 <xsd:annotation>
804 <xsd:documentation>Indicates a heading, such has the content of &lt;h1&gt;, &lt;h2&gt;, etc. in HTML.</xsd:documentation>
805 </xsd:annotation>
806 </xsd:enumeration>
807 <xsd:enumeration value="hedit">
808 <xsd:annotation>
809 <xsd:documentation>Indicates a Windows RC HEDIT control.</xsd:documentation>
810 </xsd:annotation>
811 </xsd:enumeration>
812 <xsd:enumeration value="hscrollbar">
813 <xsd:annotation>
814 <xsd:documentation>Indicates a horizontal scrollbar.</xsd:documentation>
815 </xsd:annotation>
816 </xsd:enumeration>
817 <xsd:enumeration value="icon">
818 <xsd:annotation>
819 <xsd:documentation>Indicates an icon, for example an ICON resource in Windows.</xsd:documentation>
820 </xsd:annotation>
821 </xsd:enumeration>
822 <xsd:enumeration value="iedit">
823 <xsd:annotation>
824 <xsd:documentation>Indicates a Windows RC IEDIT control.</xsd:documentation>
825 </xsd:annotation>
826 </xsd:enumeration>
827 <xsd:enumeration value="keywords">
828 <xsd:annotation>
829 <xsd:documentation>Indicates keyword list, such as the content of the Keywords meta-data in HTML, or a K footnote in WinHelp RTF.</xsd:documentation>
830 </xsd:annotation>
831 </xsd:enumeration>
832 <xsd:enumeration value="label">
833 <xsd:annotation>
834 <xsd:documentation>Indicates a label object.</xsd:documentation>
835 </xsd:annotation>
836 </xsd:enumeration>
837 <xsd:enumeration value="linklabel">
838 <xsd:annotation>
839 <xsd:documentation>Indicates a label that is also a HTML link (not necessarily a URL).</xsd:documentation>
840 </xsd:annotation>
841 </xsd:enumeration>
842 <xsd:enumeration value="list">
843 <xsd:annotation>
844 <xsd:documentation>Indicates a list (a group of list-items, for example an &lt;ol&gt; or &lt;ul&gt; element in HTML).</xsd:documentation>
845 </xsd:annotation>
846 </xsd:enumeration>
847 <xsd:enumeration value="listbox">
848 <xsd:annotation>
849 <xsd:documentation>Indicates a listbox object, for example an LISTBOX control in Windows.</xsd:documentation>
850 </xsd:annotation>
851 </xsd:enumeration>
852 <xsd:enumeration value="listitem">
853 <xsd:annotation>
854 <xsd:documentation>Indicates an list item (an entry in a list).</xsd:documentation>
855 </xsd:annotation>
856 </xsd:enumeration>
857 <xsd:enumeration value="ltext">
858 <xsd:annotation>
859 <xsd:documentation>Indicates a Windows RC LTEXT control.</xsd:documentation>
860 </xsd:annotation>
861 </xsd:enumeration>
862 <xsd:enumeration value="menu">
863 <xsd:annotation>
864 <xsd:documentation>Indicates a menu (a group of menu-items).</xsd:documentation>
865 </xsd:annotation>
866 </xsd:enumeration>
867 <xsd:enumeration value="menubar">
868 <xsd:annotation>
869 <xsd:documentation>Indicates a toolbar containing one or more tope level menus.</xsd:documentation>
870 </xsd:annotation>
871 </xsd:enumeration>
872 <xsd:enumeration value="menuitem">
873 <xsd:annotation>
874 <xsd:documentation>Indicates a menu item (an entry in a menu).</xsd:documentation>
875 </xsd:annotation>
876 </xsd:enumeration>
877 <xsd:enumeration value="menuseparator">
878 <xsd:annotation>
879 <xsd:documentation>Indicates a XUL menuseparator element.</xsd:documentation>
880 </xsd:annotation>
881 </xsd:enumeration>
882 <xsd:enumeration value="message">
883 <xsd:annotation>
884 <xsd:documentation>Indicates a message, for example an entry in a MESSAGETABLE resource in Windows.</xsd:documentation>
885 </xsd:annotation>
886 </xsd:enumeration>
887 <xsd:enumeration value="monthcalendar">
888 <xsd:annotation>
889 <xsd:documentation>Indicates a calendar control.</xsd:documentation>
890 </xsd:annotation>
891 </xsd:enumeration>
892 <xsd:enumeration value="numericupdown">
893 <xsd:annotation>
894 <xsd:documentation>Indicates an edit box beside a spin control.</xsd:documentation>
895 </xsd:annotation>
896 </xsd:enumeration>
897 <xsd:enumeration value="panel">
898 <xsd:annotation>
899 <xsd:documentation>Indicates a catch all for rectangular areas.</xsd:documentation>
900 </xsd:annotation>
901 </xsd:enumeration>
902 <xsd:enumeration value="popupmenu">
903 <xsd:annotation>
904 <xsd:documentation>Indicates a standalone menu not necessarily associated with a menubar.</xsd:documentation>
905 </xsd:annotation>
906 </xsd:enumeration>
907 <xsd:enumeration value="pushbox">
908 <xsd:annotation>
909 <xsd:documentation>Indicates a pushbox object, for example a PUSHBOX control in Windows.</xsd:documentation>
910 </xsd:annotation>
911 </xsd:enumeration>
912 <xsd:enumeration value="pushbutton">
913 <xsd:annotation>
914 <xsd:documentation>Indicates a Windows RC PUSHBUTTON control.</xsd:documentation>
915 </xsd:annotation>
916 </xsd:enumeration>
917 <xsd:enumeration value="radio">
918 <xsd:annotation>
919 <xsd:documentation>Indicates a radio button object.</xsd:documentation>
920 </xsd:annotation>
921 </xsd:enumeration>
922 <xsd:enumeration value="radiobuttonmenuitem">
923 <xsd:annotation>
924 <xsd:documentation>Indicates a menuitem with associated radio button.</xsd:documentation>
925 </xsd:annotation>
926 </xsd:enumeration>
927 <xsd:enumeration value="rcdata">
928 <xsd:annotation>
929 <xsd:documentation>Indicates raw data resources for an application.</xsd:documentation>
930 </xsd:annotation>
931 </xsd:enumeration>
932 <xsd:enumeration value="row">
933 <xsd:annotation>
934 <xsd:documentation>Indicates a row in a table.</xsd:documentation>
935 </xsd:annotation>
936 </xsd:enumeration>
937 <xsd:enumeration value="rtext">
938 <xsd:annotation>
939 <xsd:documentation>Indicates a Windows RC RTEXT control.</xsd:documentation>
940 </xsd:annotation>
941 </xsd:enumeration>
942 <xsd:enumeration value="scrollpane">
943 <xsd:annotation>
944 <xsd:documentation>Indicates a user navigable container used to show a portion of a document.</xsd:documentation>
945 </xsd:annotation>
946 </xsd:enumeration>
947 <xsd:enumeration value="separator">
948 <xsd:annotation>
949 <xsd:documentation>Indicates a generic divider object (e.g. menu group separator).</xsd:documentation>
950 </xsd:annotation>
951 </xsd:enumeration>
952 <xsd:enumeration value="shortcut">
953 <xsd:annotation>
954 <xsd:documentation>Windows accelerators, shortcuts in resource or property files.</xsd:documentation>
955 </xsd:annotation>
956 </xsd:enumeration>
957 <xsd:enumeration value="spinner">
958 <xsd:annotation>
959 <xsd:documentation>Indicates a UI control to indicate process activity but not progress.</xsd:documentation>
960 </xsd:annotation>
961 </xsd:enumeration>
962 <xsd:enumeration value="splitter">
963 <xsd:annotation>
964 <xsd:documentation>Indicates a splitter bar.</xsd:documentation>
965 </xsd:annotation>
966 </xsd:enumeration>
967 <xsd:enumeration value="state3">
968 <xsd:annotation>
969 <xsd:documentation>Indicates a Windows RC STATE3 control.</xsd:documentation>
970 </xsd:annotation>
971 </xsd:enumeration>
972 <xsd:enumeration value="statusbar">
973 <xsd:annotation>
974 <xsd:documentation>Indicates a window for providing feedback to the users, like 'read-only', etc.</xsd:documentation>
975 </xsd:annotation>
976 </xsd:enumeration>
977 <xsd:enumeration value="string">
978 <xsd:annotation>
979 <xsd:documentation>Indicates a string, for example an entry in a STRINGTABLE resource in Windows.</xsd:documentation>
980 </xsd:annotation>
981 </xsd:enumeration>
982 <xsd:enumeration value="tabcontrol">
983 <xsd:annotation>
984 <xsd:documentation>Indicates a layers of controls with a tab to select layers.</xsd:documentation>
985 </xsd:annotation>
986 </xsd:enumeration>
987 <xsd:enumeration value="table">
988 <xsd:annotation>
989 <xsd:documentation>Indicates a display and edits regular two-dimensional tables of cells.</xsd:documentation>
990 </xsd:annotation>
991 </xsd:enumeration>
992 <xsd:enumeration value="textbox">
993 <xsd:annotation>
994 <xsd:documentation>Indicates a XUL textbox element.</xsd:documentation>
995 </xsd:annotation>
996 </xsd:enumeration>
997 <xsd:enumeration value="togglebutton">
998 <xsd:annotation>
999 <xsd:documentation>Indicates a UI button that can be toggled to on or off state.</xsd:documentation>
1000 </xsd:annotation>
1001 </xsd:enumeration>
1002 <xsd:enumeration value="toolbar">
1003 <xsd:annotation>
1004 <xsd:documentation>Indicates an array of controls, usually buttons.</xsd:documentation>
1005 </xsd:annotation>
1006 </xsd:enumeration>
1007 <xsd:enumeration value="tooltip">
1008 <xsd:annotation>
1009 <xsd:documentation>Indicates a pop up tool tip text.</xsd:documentation>
1010 </xsd:annotation>
1011 </xsd:enumeration>
1012 <xsd:enumeration value="trackbar">
1013 <xsd:annotation>
1014 <xsd:documentation>Indicates a bar with a pointer indicating a position within a certain range.</xsd:documentation>
1015 </xsd:annotation>
1016 </xsd:enumeration>
1017 <xsd:enumeration value="tree">
1018 <xsd:annotation>
1019 <xsd:documentation>Indicates a control that displays a set of hierarchical data.</xsd:documentation>
1020 </xsd:annotation>
1021 </xsd:enumeration>
1022 <xsd:enumeration value="uri">
1023 <xsd:annotation>
1024 <xsd:documentation>Indicates a URI (URN or URL).</xsd:documentation>
1025 </xsd:annotation>
1026 </xsd:enumeration>
1027 <xsd:enumeration value="userbutton">
1028 <xsd:annotation>
1029 <xsd:documentation>Indicates a Windows RC USERBUTTON control.</xsd:documentation>
1030 </xsd:annotation>
1031 </xsd:enumeration>
1032 <xsd:enumeration value="usercontrol">
1033 <xsd:annotation>
1034 <xsd:documentation>Indicates a user-defined control like CONTROL control in Windows.</xsd:documentation>
1035 </xsd:annotation>
1036 </xsd:enumeration>
1037 <xsd:enumeration value="var">
1038 <xsd:annotation>
1039 <xsd:documentation>Indicates the text of a variable.</xsd:documentation>
1040 </xsd:annotation>
1041 </xsd:enumeration>
1042 <xsd:enumeration value="versioninfo">
1043 <xsd:annotation>
1044 <xsd:documentation>Indicates version information about a resource like VERSIONINFO in Windows.</xsd:documentation>
1045 </xsd:annotation>
1046 </xsd:enumeration>
1047 <xsd:enumeration value="vscrollbar">
1048 <xsd:annotation>
1049 <xsd:documentation>Indicates a vertical scrollbar.</xsd:documentation>
1050 </xsd:annotation>
1051 </xsd:enumeration>
1052 <xsd:enumeration value="window">
1053 <xsd:annotation>
1054 <xsd:documentation>Indicates a graphical window.</xsd:documentation>
1055 </xsd:annotation>
1056 </xsd:enumeration>
1057 </xsd:restriction>
1058 </xsd:simpleType>
1059 <xsd:simpleType name="size-unitValueList">
1060 <xsd:annotation>
1061 <xsd:documentation>Values for the attribute 'size-unit'.</xsd:documentation>
1062 </xsd:annotation>
1063 <xsd:restriction base="xsd:NMTOKEN">
1064 <xsd:enumeration value="byte">
1065 <xsd:annotation>
1066 <xsd:documentation>Indicates a size in 8-bit bytes.</xsd:documentation>
1067 </xsd:annotation>
1068 </xsd:enumeration>
1069 <xsd:enumeration value="char">
1070 <xsd:annotation>
1071 <xsd:documentation>Indicates a size in Unicode characters.</xsd:documentation>
1072 </xsd:annotation>
1073 </xsd:enumeration>
1074 <xsd:enumeration value="col">
1075 <xsd:annotation>
1076 <xsd:documentation>Indicates a size in columns. Used for HTML text area.</xsd:documentation>
1077 </xsd:annotation>
1078 </xsd:enumeration>
1079 <xsd:enumeration value="cm">
1080 <xsd:annotation>
1081 <xsd:documentation>Indicates a size in centimeters.</xsd:documentation>
1082 </xsd:annotation>
1083 </xsd:enumeration>
1084 <xsd:enumeration value="dlgunit">
1085 <xsd:annotation>
1086 <xsd:documentation>Indicates a size in dialog units, as defined in Windows resources.</xsd:documentation>
1087 </xsd:annotation>
1088 </xsd:enumeration>
1089 <xsd:enumeration value="em">
1090 <xsd:annotation>
1091 <xsd:documentation>Indicates a size in 'font-size' units (as defined in CSS).</xsd:documentation>
1092 </xsd:annotation>
1093 </xsd:enumeration>
1094 <xsd:enumeration value="ex">
1095 <xsd:annotation>
1096 <xsd:documentation>Indicates a size in 'x-height' units (as defined in CSS).</xsd:documentation>
1097 </xsd:annotation>
1098 </xsd:enumeration>
1099 <xsd:enumeration value="glyph">
1100 <xsd:annotation>
1101 <xsd:documentation>Indicates a size in glyphs. A glyph is considered to be one or more combined Unicode characters that represent a single displayable text character. Sometimes referred to as a 'grapheme cluster'</xsd:documentation>
1102 </xsd:annotation>
1103 </xsd:enumeration>
1104 <xsd:enumeration value="in">
1105 <xsd:annotation>
1106 <xsd:documentation>Indicates a size in inches.</xsd:documentation>
1107 </xsd:annotation>
1108 </xsd:enumeration>
1109 <xsd:enumeration value="mm">
1110 <xsd:annotation>
1111 <xsd:documentation>Indicates a size in millimeters.</xsd:documentation>
1112 </xsd:annotation>
1113 </xsd:enumeration>
1114 <xsd:enumeration value="percent">
1115 <xsd:annotation>
1116 <xsd:documentation>Indicates a size in percentage.</xsd:documentation>
1117 </xsd:annotation>
1118 </xsd:enumeration>
1119 <xsd:enumeration value="pixel">
1120 <xsd:annotation>
1121 <xsd:documentation>Indicates a size in pixels.</xsd:documentation>
1122 </xsd:annotation>
1123 </xsd:enumeration>
1124 <xsd:enumeration value="point">
1125 <xsd:annotation>
1126 <xsd:documentation>Indicates a size in point.</xsd:documentation>
1127 </xsd:annotation>
1128 </xsd:enumeration>
1129 <xsd:enumeration value="row">
1130 <xsd:annotation>
1131 <xsd:documentation>Indicates a size in rows. Used for HTML text area.</xsd:documentation>
1132 </xsd:annotation>
1133 </xsd:enumeration>
1134 </xsd:restriction>
1135 </xsd:simpleType>
1136 <xsd:simpleType name="stateValueList">
1137 <xsd:annotation>
1138 <xsd:documentation>Values for the attribute 'state'.</xsd:documentation>
1139 </xsd:annotation>
1140 <xsd:restriction base="xsd:NMTOKEN">
1141 <xsd:enumeration value="final">
1142 <xsd:annotation>
1143 <xsd:documentation>Indicates the terminating state.</xsd:documentation>
1144 </xsd:annotation>
1145 </xsd:enumeration>
1146 <xsd:enumeration value="needs-adaptation">
1147 <xsd:annotation>
1148 <xsd:documentation>Indicates only non-textual information needs adaptation.</xsd:documentation>
1149 </xsd:annotation>
1150 </xsd:enumeration>
1151 <xsd:enumeration value="needs-l10n">
1152 <xsd:annotation>
1153 <xsd:documentation>Indicates both text and non-textual information needs adaptation.</xsd:documentation>
1154 </xsd:annotation>
1155 </xsd:enumeration>
1156 <xsd:enumeration value="needs-review-adaptation">
1157 <xsd:annotation>
1158 <xsd:documentation>Indicates only non-textual information needs review.</xsd:documentation>
1159 </xsd:annotation>
1160 </xsd:enumeration>
1161 <xsd:enumeration value="needs-review-l10n">
1162 <xsd:annotation>
1163 <xsd:documentation>Indicates both text and non-textual information needs review.</xsd:documentation>
1164 </xsd:annotation>
1165 </xsd:enumeration>
1166 <xsd:enumeration value="needs-review-translation">
1167 <xsd:annotation>
1168 <xsd:documentation>Indicates that only the text of the item needs to be reviewed.</xsd:documentation>
1169 </xsd:annotation>
1170 </xsd:enumeration>
1171 <xsd:enumeration value="needs-translation">
1172 <xsd:annotation>
1173 <xsd:documentation>Indicates that the item needs to be translated.</xsd:documentation>
1174 </xsd:annotation>
1175 </xsd:enumeration>
1176 <xsd:enumeration value="new">
1177 <xsd:annotation>
1178 <xsd:documentation>Indicates that the item is new. For example, translation units that were not in a previous version of the document.</xsd:documentation>
1179 </xsd:annotation>
1180 </xsd:enumeration>
1181 <xsd:enumeration value="signed-off">
1182 <xsd:annotation>
1183 <xsd:documentation>Indicates that changes are reviewed and approved.</xsd:documentation>
1184 </xsd:annotation>
1185 </xsd:enumeration>
1186 <xsd:enumeration value="translated">
1187 <xsd:annotation>
1188 <xsd:documentation>Indicates that the item has been translated.</xsd:documentation>
1189 </xsd:annotation>
1190 </xsd:enumeration>
1191 </xsd:restriction>
1192 </xsd:simpleType>
1193 <xsd:simpleType name="state-qualifierValueList">
1194 <xsd:annotation>
1195 <xsd:documentation>Values for the attribute 'state-qualifier'.</xsd:documentation>
1196 </xsd:annotation>
1197 <xsd:restriction base="xsd:NMTOKEN">
1198 <xsd:enumeration value="exact-match">
1199 <xsd:annotation>
1200 <xsd:documentation>Indicates an exact match. An exact match occurs when a source text of a segment is exactly the same as the source text of a segment that was translated previously.</xsd:documentation>
1201 </xsd:annotation>
1202 </xsd:enumeration>
1203 <xsd:enumeration value="fuzzy-match">
1204 <xsd:annotation>
1205 <xsd:documentation>Indicates a fuzzy match. A fuzzy match occurs when a source text of a segment is very similar to the source text of a segment that was translated previously (e.g. when the difference is casing, a few changed words, white-space discripancy, etc.).</xsd:documentation>
1206 </xsd:annotation>
1207 </xsd:enumeration>
1208 <xsd:enumeration value="id-match">
1209 <xsd:annotation>
1210 <xsd:documentation>Indicates a match based on matching IDs (in addition to matching text).</xsd:documentation>
1211 </xsd:annotation>
1212 </xsd:enumeration>
1213 <xsd:enumeration value="leveraged-glossary">
1214 <xsd:annotation>
1215 <xsd:documentation>Indicates a translation derived from a glossary.</xsd:documentation>
1216 </xsd:annotation>
1217 </xsd:enumeration>
1218 <xsd:enumeration value="leveraged-inherited">
1219 <xsd:annotation>
1220 <xsd:documentation>Indicates a translation derived from existing translation.</xsd:documentation>
1221 </xsd:annotation>
1222 </xsd:enumeration>
1223 <xsd:enumeration value="leveraged-mt">
1224 <xsd:annotation>
1225 <xsd:documentation>Indicates a translation derived from machine translation.</xsd:documentation>
1226 </xsd:annotation>
1227 </xsd:enumeration>
1228 <xsd:enumeration value="leveraged-repository">
1229 <xsd:annotation>
1230 <xsd:documentation>Indicates a translation derived from a translation repository.</xsd:documentation>
1231 </xsd:annotation>
1232 </xsd:enumeration>
1233 <xsd:enumeration value="leveraged-tm">
1234 <xsd:annotation>
1235 <xsd:documentation>Indicates a translation derived from a translation memory.</xsd:documentation>
1236 </xsd:annotation>
1237 </xsd:enumeration>
1238 <xsd:enumeration value="mt-suggestion">
1239 <xsd:annotation>
1240 <xsd:documentation>Indicates the translation is suggested by machine translation.</xsd:documentation>
1241 </xsd:annotation>
1242 </xsd:enumeration>
1243 <xsd:enumeration value="rejected-grammar">
1244 <xsd:annotation>
1245 <xsd:documentation>Indicates that the item has been rejected because of incorrect grammar.</xsd:documentation>
1246 </xsd:annotation>
1247 </xsd:enumeration>
1248 <xsd:enumeration value="rejected-inaccurate">
1249 <xsd:annotation>
1250 <xsd:documentation>Indicates that the item has been rejected because it is incorrect.</xsd:documentation>
1251 </xsd:annotation>
1252 </xsd:enumeration>
1253 <xsd:enumeration value="rejected-length">
1254 <xsd:annotation>
1255 <xsd:documentation>Indicates that the item has been rejected because it is too long or too short.</xsd:documentation>
1256 </xsd:annotation>
1257 </xsd:enumeration>
1258 <xsd:enumeration value="rejected-spelling">
1259 <xsd:annotation>
1260 <xsd:documentation>Indicates that the item has been rejected because of incorrect spelling.</xsd:documentation>
1261 </xsd:annotation>
1262 </xsd:enumeration>
1263 <xsd:enumeration value="tm-suggestion">
1264 <xsd:annotation>
1265 <xsd:documentation>Indicates the translation is suggested by translation memory.</xsd:documentation>
1266 </xsd:annotation>
1267 </xsd:enumeration>
1268 </xsd:restriction>
1269 </xsd:simpleType>
1270 <xsd:simpleType name="unitValueList">
1271 <xsd:annotation>
1272 <xsd:documentation>Values for the attribute 'unit'.</xsd:documentation>
1273 </xsd:annotation>
1274 <xsd:restriction base="xsd:NMTOKEN">
1275 <xsd:enumeration value="word">
1276 <xsd:annotation>
1277 <xsd:documentation>Refers to words.</xsd:documentation>
1278 </xsd:annotation>
1279 </xsd:enumeration>
1280 <xsd:enumeration value="page">
1281 <xsd:annotation>
1282 <xsd:documentation>Refers to pages.</xsd:documentation>
1283 </xsd:annotation>
1284 </xsd:enumeration>
1285 <xsd:enumeration value="trans-unit">
1286 <xsd:annotation>
1287 <xsd:documentation>Refers to &lt;trans-unit&gt; elements.</xsd:documentation>
1288 </xsd:annotation>
1289 </xsd:enumeration>
1290 <xsd:enumeration value="bin-unit">
1291 <xsd:annotation>
1292 <xsd:documentation>Refers to &lt;bin-unit&gt; elements.</xsd:documentation>
1293 </xsd:annotation>
1294 </xsd:enumeration>
1295 <xsd:enumeration value="glyph">
1296 <xsd:annotation>
1297 <xsd:documentation>Refers to glyphs.</xsd:documentation>
1298 </xsd:annotation>
1299 </xsd:enumeration>
1300 <xsd:enumeration value="item">
1301 <xsd:annotation>
1302 <xsd:documentation>Refers to &lt;trans-unit&gt; and/or &lt;bin-unit&gt; elements.</xsd:documentation>
1303 </xsd:annotation>
1304 </xsd:enumeration>
1305 <xsd:enumeration value="instance">
1306 <xsd:annotation>
1307 <xsd:documentation>Refers to the occurrences of instances defined by the count-type value.</xsd:documentation>
1308 </xsd:annotation>
1309 </xsd:enumeration>
1310 <xsd:enumeration value="character">
1311 <xsd:annotation>
1312 <xsd:documentation>Refers to characters.</xsd:documentation>
1313 </xsd:annotation>
1314 </xsd:enumeration>
1315 <xsd:enumeration value="line">
1316 <xsd:annotation>
1317 <xsd:documentation>Refers to lines.</xsd:documentation>
1318 </xsd:annotation>
1319 </xsd:enumeration>
1320 <xsd:enumeration value="sentence">
1321 <xsd:annotation>
1322 <xsd:documentation>Refers to sentences.</xsd:documentation>
1323 </xsd:annotation>
1324 </xsd:enumeration>
1325 <xsd:enumeration value="paragraph">
1326 <xsd:annotation>
1327 <xsd:documentation>Refers to paragraphs.</xsd:documentation>
1328 </xsd:annotation>
1329 </xsd:enumeration>
1330 <xsd:enumeration value="segment">
1331 <xsd:annotation>
1332 <xsd:documentation>Refers to segments.</xsd:documentation>
1333 </xsd:annotation>
1334 </xsd:enumeration>
1335 <xsd:enumeration value="placeable">
1336 <xsd:annotation>
1337 <xsd:documentation>Refers to placeables (inline elements).</xsd:documentation>
1338 </xsd:annotation>
1339 </xsd:enumeration>
1340 </xsd:restriction>
1341 </xsd:simpleType>
1342 <xsd:simpleType name="priorityValueList">
1343 <xsd:annotation>
1344 <xsd:documentation>Values for the attribute 'priority'.</xsd:documentation>
1345 </xsd:annotation>
1346 <xsd:restriction base="xsd:positiveInteger">
1347 <xsd:enumeration value="1">
1348 <xsd:annotation>
1349 <xsd:documentation>Highest priority.</xsd:documentation>
1350 </xsd:annotation>
1351 </xsd:enumeration>
1352 <xsd:enumeration value="2">
1353 <xsd:annotation>
1354 <xsd:documentation>High priority.</xsd:documentation>
1355 </xsd:annotation>
1356 </xsd:enumeration>
1357 <xsd:enumeration value="3">
1358 <xsd:annotation>
1359 <xsd:documentation>High priority, but not as important as 2.</xsd:documentation>
1360 </xsd:annotation>
1361 </xsd:enumeration>
1362 <xsd:enumeration value="4">
1363 <xsd:annotation>
1364 <xsd:documentation>High priority, but not as important as 3.</xsd:documentation>
1365 </xsd:annotation>
1366 </xsd:enumeration>
1367 <xsd:enumeration value="5">
1368 <xsd:annotation>
1369 <xsd:documentation>Medium priority, but more important than 6.</xsd:documentation>
1370 </xsd:annotation>
1371 </xsd:enumeration>
1372 <xsd:enumeration value="6">
1373 <xsd:annotation>
1374 <xsd:documentation>Medium priority, but less important than 5.</xsd:documentation>
1375 </xsd:annotation>
1376 </xsd:enumeration>
1377 <xsd:enumeration value="7">
1378 <xsd:annotation>
1379 <xsd:documentation>Low priority, but more important than 8.</xsd:documentation>
1380 </xsd:annotation>
1381 </xsd:enumeration>
1382 <xsd:enumeration value="8">
1383 <xsd:annotation>
1384 <xsd:documentation>Low priority, but more important than 9.</xsd:documentation>
1385 </xsd:annotation>
1386 </xsd:enumeration>
1387 <xsd:enumeration value="9">
1388 <xsd:annotation>
1389 <xsd:documentation>Low priority.</xsd:documentation>
1390 </xsd:annotation>
1391 </xsd:enumeration>
1392 <xsd:enumeration value="10">
1393 <xsd:annotation>
1394 <xsd:documentation>Lowest priority.</xsd:documentation>
1395 </xsd:annotation>
1396 </xsd:enumeration>
1397 </xsd:restriction>
1398 </xsd:simpleType>
1399 <xsd:simpleType name="reformatValueYesNo">
1400 <xsd:restriction base="xsd:string">
1401 <xsd:enumeration value="yes">
1402 <xsd:annotation>
1403 <xsd:documentation>This value indicates that all properties can be reformatted. This value must be used alone.</xsd:documentation>
1404 </xsd:annotation>
1405 </xsd:enumeration>
1406 <xsd:enumeration value="no">
1407 <xsd:annotation>
1408 <xsd:documentation>This value indicates that no properties should be reformatted. This value must be used alone.</xsd:documentation>
1409 </xsd:annotation>
1410 </xsd:enumeration>
1411 </xsd:restriction>
1412 </xsd:simpleType>
1413 <xsd:simpleType name="reformatValueList">
1414 <xsd:list>
1415 <xsd:simpleType>
1416 <xsd:union memberTypes="xlf:XTend">
1417 <xsd:simpleType>
1418 <xsd:restriction base="xsd:string">
1419 <xsd:enumeration value="coord">
1420 <xsd:annotation>
1421 <xsd:documentation>This value indicates that all information in the coord attribute can be modified.</xsd:documentation>
1422 </xsd:annotation>
1423 </xsd:enumeration>
1424 <xsd:enumeration value="coord-x">
1425 <xsd:annotation>
1426 <xsd:documentation>This value indicates that the x information in the coord attribute can be modified.</xsd:documentation>
1427 </xsd:annotation>
1428 </xsd:enumeration>
1429 <xsd:enumeration value="coord-y">
1430 <xsd:annotation>
1431 <xsd:documentation>This value indicates that the y information in the coord attribute can be modified.</xsd:documentation>
1432 </xsd:annotation>
1433 </xsd:enumeration>
1434 <xsd:enumeration value="coord-cx">
1435 <xsd:annotation>
1436 <xsd:documentation>This value indicates that the cx information in the coord attribute can be modified.</xsd:documentation>
1437 </xsd:annotation>
1438 </xsd:enumeration>
1439 <xsd:enumeration value="coord-cy">
1440 <xsd:annotation>
1441 <xsd:documentation>This value indicates that the cy information in the coord attribute can be modified.</xsd:documentation>
1442 </xsd:annotation>
1443 </xsd:enumeration>
1444 <xsd:enumeration value="font">
1445 <xsd:annotation>
1446 <xsd:documentation>This value indicates that all the information in the font attribute can be modified.</xsd:documentation>
1447 </xsd:annotation>
1448 </xsd:enumeration>
1449 <xsd:enumeration value="font-name">
1450 <xsd:annotation>
1451 <xsd:documentation>This value indicates that the name information in the font attribute can be modified.</xsd:documentation>
1452 </xsd:annotation>
1453 </xsd:enumeration>
1454 <xsd:enumeration value="font-size">
1455 <xsd:annotation>
1456 <xsd:documentation>This value indicates that the size information in the font attribute can be modified.</xsd:documentation>
1457 </xsd:annotation>
1458 </xsd:enumeration>
1459 <xsd:enumeration value="font-weight">
1460 <xsd:annotation>
1461 <xsd:documentation>This value indicates that the weight information in the font attribute can be modified.</xsd:documentation>
1462 </xsd:annotation>
1463 </xsd:enumeration>
1464 <xsd:enumeration value="css-style">
1465 <xsd:annotation>
1466 <xsd:documentation>This value indicates that the information in the css-style attribute can be modified.</xsd:documentation>
1467 </xsd:annotation>
1468 </xsd:enumeration>
1469 <xsd:enumeration value="style">
1470 <xsd:annotation>
1471 <xsd:documentation>This value indicates that the information in the style attribute can be modified.</xsd:documentation>
1472 </xsd:annotation>
1473 </xsd:enumeration>
1474 <xsd:enumeration value="ex-style">
1475 <xsd:annotation>
1476 <xsd:documentation>This value indicates that the information in the exstyle attribute can be modified.</xsd:documentation>
1477 </xsd:annotation>
1478 </xsd:enumeration>
1479 </xsd:restriction>
1480 </xsd:simpleType>
1481 </xsd:union>
1482 </xsd:simpleType>
1483 </xsd:list>
1484 </xsd:simpleType>
1485 <xsd:simpleType name="purposeValueList">
1486 <xsd:restriction base="xsd:string">
1487 <xsd:enumeration value="information">
1488 <xsd:annotation>
1489 <xsd:documentation>Indicates that the context is informational in nature, specifying for example, how a term should be translated. Thus, should be displayed to anyone editing the XLIFF document.</xsd:documentation>
1490 </xsd:annotation>
1491 </xsd:enumeration>
1492 <xsd:enumeration value="location">
1493 <xsd:annotation>
1494 <xsd:documentation>Indicates that the context-group is used to specify where the term was found in the translatable source. Thus, it is not displayed.</xsd:documentation>
1495 </xsd:annotation>
1496 </xsd:enumeration>
1497 <xsd:enumeration value="match">
1498 <xsd:annotation>
1499 <xsd:documentation>Indicates that the context information should be used during translation memory lookups. Thus, it is not displayed.</xsd:documentation>
1500 </xsd:annotation>
1501 </xsd:enumeration>
1502 </xsd:restriction>
1503 </xsd:simpleType>
1504 <xsd:simpleType name="alttranstypeValueList">
1505 <xsd:restriction base="xsd:string">
1506 <xsd:enumeration value="proposal">
1507 <xsd:annotation>
1508 <xsd:documentation>Represents a translation proposal from a translation memory or other resource.</xsd:documentation>
1509 </xsd:annotation>
1510 </xsd:enumeration>
1511 <xsd:enumeration value="previous-version">
1512 <xsd:annotation>
1513 <xsd:documentation>Represents a previous version of the target element.</xsd:documentation>
1514 </xsd:annotation>
1515 </xsd:enumeration>
1516 <xsd:enumeration value="rejected">
1517 <xsd:annotation>
1518 <xsd:documentation>Represents a rejected version of the target element.</xsd:documentation>
1519 </xsd:annotation>
1520 </xsd:enumeration>
1521 <xsd:enumeration value="reference">
1522 <xsd:annotation>
1523 <xsd:documentation>Represents a translation to be used for reference purposes only, for example from a related product or a different language.</xsd:documentation>
1524 </xsd:annotation>
1525 </xsd:enumeration>
1526 <xsd:enumeration value="accepted">
1527 <xsd:annotation>
1528 <xsd:documentation>Represents a proposed translation that was used for the translation of the trans-unit, possibly modified.</xsd:documentation>
1529 </xsd:annotation>
1530 </xsd:enumeration>
1531 </xsd:restriction>
1532 </xsd:simpleType>
1533 <!-- Other Types -->
1534 <xsd:complexType name="ElemType_ExternalReference">
1535 <xsd:choice>
1536 <xsd:element ref="xlf:internal-file"/>
1537 <xsd:element ref="xlf:external-file"/>
1538 </xsd:choice>
1539 </xsd:complexType>
1540 <xsd:simpleType name="AttrType_purpose">
1541 <xsd:list>
1542 <xsd:simpleType>
1543 <xsd:union memberTypes="xlf:purposeValueList xlf:XTend"/>
1544 </xsd:simpleType>
1545 </xsd:list>
1546 </xsd:simpleType>
1547 <xsd:simpleType name="AttrType_datatype">
1548 <xsd:union memberTypes="xlf:datatypeValueList xlf:XTend"/>
1549 </xsd:simpleType>
1550 <xsd:simpleType name="AttrType_restype">
1551 <xsd:union memberTypes="xlf:restypeValueList xlf:XTend"/>
1552 </xsd:simpleType>
1553 <xsd:simpleType name="AttrType_alttranstype">
1554 <xsd:union memberTypes="xlf:alttranstypeValueList xlf:XTend"/>
1555 </xsd:simpleType>
1556 <xsd:simpleType name="AttrType_context-type">
1557 <xsd:union memberTypes="xlf:context-typeValueList xlf:XTend"/>
1558 </xsd:simpleType>
1559 <xsd:simpleType name="AttrType_state">
1560 <xsd:union memberTypes="xlf:stateValueList xlf:XTend"/>
1561 </xsd:simpleType>
1562 <xsd:simpleType name="AttrType_state-qualifier">
1563 <xsd:union memberTypes="xlf:state-qualifierValueList xlf:XTend"/>
1564 </xsd:simpleType>
1565 <xsd:simpleType name="AttrType_count-type">
1566 <xsd:union memberTypes="xlf:restypeValueList xlf:count-typeValueList xlf:datatypeValueList xlf:stateValueList xlf:state-qualifierValueList xlf:XTend"/>
1567 </xsd:simpleType>
1568 <xsd:simpleType name="AttrType_InlineDelimiters">
1569 <xsd:union memberTypes="xlf:InlineDelimitersValueList xlf:XTend"/>
1570 </xsd:simpleType>
1571 <xsd:simpleType name="AttrType_InlinePlaceholders">
1572 <xsd:union memberTypes="xlf:InlinePlaceholdersValueList xlf:XTend"/>
1573 </xsd:simpleType>
1574 <xsd:simpleType name="AttrType_size-unit">
1575 <xsd:union memberTypes="xlf:size-unitValueList xlf:XTend"/>
1576 </xsd:simpleType>
1577 <xsd:simpleType name="AttrType_mtype">
1578 <xsd:union memberTypes="xlf:mtypeValueList xlf:XTend"/>
1579 </xsd:simpleType>
1580 <xsd:simpleType name="AttrType_unit">
1581 <xsd:union memberTypes="xlf:unitValueList xlf:XTend"/>
1582 </xsd:simpleType>
1583 <xsd:simpleType name="AttrType_priority">
1584 <xsd:union memberTypes="xlf:priorityValueList"/>
1585 </xsd:simpleType>
1586 <xsd:simpleType name="AttrType_reformat">
1587 <xsd:union memberTypes="xlf:reformatValueYesNo xlf:reformatValueList"/>
1588 </xsd:simpleType>
1589 <xsd:simpleType name="AttrType_YesNo">
1590 <xsd:restriction base="xsd:NMTOKEN">
1591 <xsd:enumeration value="yes"/>
1592 <xsd:enumeration value="no"/>
1593 </xsd:restriction>
1594 </xsd:simpleType>
1595 <xsd:simpleType name="AttrType_Position">
1596 <xsd:restriction base="xsd:NMTOKEN">
1597 <xsd:enumeration value="open"/>
1598 <xsd:enumeration value="close"/>
1599 </xsd:restriction>
1600 </xsd:simpleType>
1601 <xsd:simpleType name="AttrType_assoc">
1602 <xsd:restriction base="xsd:NMTOKEN">
1603 <xsd:enumeration value="preceding"/>
1604 <xsd:enumeration value="following"/>
1605 <xsd:enumeration value="both"/>
1606 </xsd:restriction>
1607 </xsd:simpleType>
1608 <xsd:simpleType name="AttrType_annotates">
1609 <xsd:restriction base="xsd:NMTOKEN">
1610 <xsd:enumeration value="source"/>
1611 <xsd:enumeration value="target"/>
1612 <xsd:enumeration value="general"/>
1613 </xsd:restriction>
1614 </xsd:simpleType>
1615 <xsd:simpleType name="AttrType_Coordinates">
1616 <xsd:annotation>
1617 <xsd:documentation>Values for the attribute 'coord'.</xsd:documentation>
1618 </xsd:annotation>
1619 <xsd:restriction base="xsd:string">
1620 <xsd:pattern value="(-?\d+|#);(-?\d+|#);(-?\d+|#);(-?\d+|#)"/>
1621 </xsd:restriction>
1622 </xsd:simpleType>
1623 <xsd:simpleType name="AttrType_Version">
1624 <xsd:annotation>
1625 <xsd:documentation>Version values: 1.0 and 1.1 are allowed for backward compatibility.</xsd:documentation>
1626 </xsd:annotation>
1627 <xsd:restriction base="xsd:string">
1628 <xsd:enumeration value="1.2"/>
1629 <xsd:enumeration value="1.1"/>
1630 <xsd:enumeration value="1.0"/>
1631 </xsd:restriction>
1632 </xsd:simpleType>
1633 <!-- Groups -->
1634 <xsd:group name="ElemGroup_TextContent">
1635 <xsd:choice>
1636 <xsd:element ref="xlf:g"/>
1637 <xsd:element ref="xlf:bpt"/>
1638 <xsd:element ref="xlf:ept"/>
1639 <xsd:element ref="xlf:ph"/>
1640 <xsd:element ref="xlf:it"/>
1641 <xsd:element ref="xlf:mrk"/>
1642 <xsd:element ref="xlf:x"/>
1643 <xsd:element ref="xlf:bx"/>
1644 <xsd:element ref="xlf:ex"/>
1645 </xsd:choice>
1646 </xsd:group>
1647 <xsd:attributeGroup name="AttrGroup_TextContent">
1648 <xsd:attribute name="id" type="xsd:string" use="required"/>
1649 <xsd:attribute name="xid" type="xsd:string" use="optional"/>
1650 <xsd:attribute name="equiv-text" type="xsd:string" use="optional"/>
1651 <xsd:anyAttribute namespace="##other" processContents="strict"/>
1652 </xsd:attributeGroup>
1653 <!-- XLIFF Structure -->
1654 <xsd:element name="xliff">
1655 <xsd:complexType>
1656 <xsd:sequence maxOccurs="unbounded">
1657 <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
1658 <xsd:element ref="xlf:file"/>
1659 </xsd:sequence>
1660 <xsd:attribute name="version" type="xlf:AttrType_Version" use="required"/>
1661 <xsd:attribute ref="xml:lang" use="optional"/>
1662 <xsd:anyAttribute namespace="##other" processContents="strict"/>
1663 </xsd:complexType>
1664 </xsd:element>
1665 <xsd:element name="file">
1666 <xsd:complexType>
1667 <xsd:sequence>
1668 <xsd:element minOccurs="0" ref="xlf:header"/>
1669 <xsd:element ref="xlf:body"/>
1670 </xsd:sequence>
1671 <xsd:attribute name="original" type="xsd:string" use="required"/>
1672 <xsd:attribute name="source-language" type="xsd:language" use="required"/>
1673 <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="required"/>
1674 <xsd:attribute name="tool-id" type="xsd:string" use="optional"/>
1675 <xsd:attribute name="date" type="xsd:dateTime" use="optional"/>
1676 <xsd:attribute ref="xml:space" use="optional"/>
1677 <xsd:attribute name="category" type="xsd:string" use="optional"/>
1678 <xsd:attribute name="target-language" type="xsd:language" use="optional"/>
1679 <xsd:attribute name="product-name" type="xsd:string" use="optional"/>
1680 <xsd:attribute name="product-version" type="xsd:string" use="optional"/>
1681 <xsd:attribute name="build-num" type="xsd:string" use="optional"/>
1682 <xsd:anyAttribute namespace="##other" processContents="strict"/>
1683 </xsd:complexType>
1684 <xsd:unique name="U_group_id">
1685 <xsd:selector xpath=".//xlf:group"/>
1686 <xsd:field xpath="@id"/>
1687 </xsd:unique>
1688 <xsd:key name="K_unit_id">
1689 <xsd:selector xpath=".//xlf:trans-unit|.//xlf:bin-unit"/>
1690 <xsd:field xpath="@id"/>
1691 </xsd:key>
1692 <xsd:keyref name="KR_unit_id" refer="xlf:K_unit_id">
1693 <xsd:selector xpath=".//bpt|.//ept|.//it|.//ph|.//g|.//x|.//bx|.//ex|.//sub"/>
1694 <xsd:field xpath="@xid"/>
1695 </xsd:keyref>
1696 <xsd:key name="K_tool-id">
1697 <xsd:selector xpath="xlf:header/xlf:tool"/>
1698 <xsd:field xpath="@tool-id"/>
1699 </xsd:key>
1700 <xsd:keyref name="KR_file_tool-id" refer="xlf:K_tool-id">
1701 <xsd:selector xpath="."/>
1702 <xsd:field xpath="@tool-id"/>
1703 </xsd:keyref>
1704 <xsd:keyref name="KR_phase_tool-id" refer="xlf:K_tool-id">
1705 <xsd:selector xpath="xlf:header/xlf:phase-group/xlf:phase"/>
1706 <xsd:field xpath="@tool-id"/>
1707 </xsd:keyref>
1708 <xsd:keyref name="KR_alt-trans_tool-id" refer="xlf:K_tool-id">
1709 <xsd:selector xpath=".//xlf:trans-unit/xlf:alt-trans"/>
1710 <xsd:field xpath="@tool-id"/>
1711 </xsd:keyref>
1712 <xsd:key name="K_count-group_name">
1713 <xsd:selector xpath=".//xlf:count-group"/>
1714 <xsd:field xpath="@name"/>
1715 </xsd:key>
1716 <xsd:unique name="U_context-group_name">
1717 <xsd:selector xpath=".//xlf:context-group"/>
1718 <xsd:field xpath="@name"/>
1719 </xsd:unique>
1720 <xsd:key name="K_phase-name">
1721 <xsd:selector xpath="xlf:header/xlf:phase-group/xlf:phase"/>
1722 <xsd:field xpath="@phase-name"/>
1723 </xsd:key>
1724 <xsd:keyref name="KR_phase-name" refer="xlf:K_phase-name">
1725 <xsd:selector xpath=".//xlf:count|.//xlf:trans-unit|.//xlf:target|.//bin-unit|.//bin-target"/>
1726 <xsd:field xpath="@phase-name"/>
1727 </xsd:keyref>
1728 <xsd:unique name="U_uid">
1729 <xsd:selector xpath=".//xlf:external-file"/>
1730 <xsd:field xpath="@uid"/>
1731 </xsd:unique>
1732 </xsd:element>
1733 <xsd:element name="header">
1734 <xsd:complexType>
1735 <xsd:sequence>
1736 <xsd:element minOccurs="0" name="skl" type="xlf:ElemType_ExternalReference"/>
1737 <xsd:element minOccurs="0" ref="xlf:phase-group"/>
1738 <xsd:choice maxOccurs="unbounded" minOccurs="0">
1739 <xsd:element name="glossary" type="xlf:ElemType_ExternalReference"/>
1740 <xsd:element name="reference" type="xlf:ElemType_ExternalReference"/>
1741 <xsd:element ref="xlf:count-group"/>
1742 <xsd:element ref="xlf:note"/>
1743 <xsd:element ref="xlf:tool"/>
1744 </xsd:choice>
1745 <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
1746 </xsd:sequence>
1747 </xsd:complexType>
1748 </xsd:element>
1749 <xsd:element name="internal-file">
1750 <xsd:complexType>
1751 <xsd:simpleContent>
1752 <xsd:extension base="xsd:string">
1753 <xsd:attribute name="form" type="xsd:string"/>
1754 <xsd:attribute name="crc" type="xsd:NMTOKEN"/>
1755 </xsd:extension>
1756 </xsd:simpleContent>
1757 </xsd:complexType>
1758 </xsd:element>
1759 <xsd:element name="external-file">
1760 <xsd:complexType>
1761 <xsd:attribute name="href" type="xsd:string" use="required"/>
1762 <xsd:attribute name="crc" type="xsd:NMTOKEN"/>
1763 <xsd:attribute name="uid" type="xsd:NMTOKEN"/>
1764 </xsd:complexType>
1765 </xsd:element>
1766 <xsd:element name="note">
1767 <xsd:complexType>
1768 <xsd:simpleContent>
1769 <xsd:extension base="xsd:string">
1770 <xsd:attribute ref="xml:lang" use="optional"/>
1771 <xsd:attribute default="1" name="priority" type="xlf:AttrType_priority" use="optional"/>
1772 <xsd:attribute name="from" type="xsd:string" use="optional"/>
1773 <xsd:attribute default="general" name="annotates" type="xlf:AttrType_annotates" use="optional"/>
1774 </xsd:extension>
1775 </xsd:simpleContent>
1776 </xsd:complexType>
1777 </xsd:element>
1778 <xsd:element name="phase-group">
1779 <xsd:complexType>
1780 <xsd:sequence maxOccurs="unbounded">
1781 <xsd:element ref="xlf:phase"/>
1782 </xsd:sequence>
1783 </xsd:complexType>
1784 </xsd:element>
1785 <xsd:element name="phase">
1786 <xsd:complexType>
1787 <xsd:sequence maxOccurs="unbounded" minOccurs="0">
1788 <xsd:element ref="xlf:note"/>
1789 </xsd:sequence>
1790 <xsd:attribute name="phase-name" type="xsd:string" use="required"/>
1791 <xsd:attribute name="process-name" type="xsd:string" use="required"/>
1792 <xsd:attribute name="company-name" type="xsd:string" use="optional"/>
1793 <xsd:attribute name="tool-id" type="xsd:string" use="optional"/>
1794 <xsd:attribute name="date" type="xsd:dateTime" use="optional"/>
1795 <xsd:attribute name="job-id" type="xsd:string" use="optional"/>
1796 <xsd:attribute name="contact-name" type="xsd:string" use="optional"/>
1797 <xsd:attribute name="contact-email" type="xsd:string" use="optional"/>
1798 <xsd:attribute name="contact-phone" type="xsd:string" use="optional"/>
1799 </xsd:complexType>
1800 </xsd:element>
1801 <xsd:element name="count-group">
1802 <xsd:complexType>
1803 <xsd:sequence maxOccurs="unbounded" minOccurs="0">
1804 <xsd:element ref="xlf:count"/>
1805 </xsd:sequence>
1806 <xsd:attribute name="name" type="xsd:string" use="required"/>
1807 </xsd:complexType>
1808 </xsd:element>
1809 <xsd:element name="count">
1810 <xsd:complexType>
1811 <xsd:simpleContent>
1812 <xsd:extension base="xsd:string">
1813 <xsd:attribute name="count-type" type="xlf:AttrType_count-type" use="optional"/>
1814 <xsd:attribute name="phase-name" type="xsd:string" use="optional"/>
1815 <xsd:attribute default="word" name="unit" type="xlf:AttrType_unit" use="optional"/>
1816 </xsd:extension>
1817 </xsd:simpleContent>
1818 </xsd:complexType>
1819 </xsd:element>
1820 <xsd:element name="context-group">
1821 <xsd:complexType>
1822 <xsd:sequence maxOccurs="unbounded">
1823 <xsd:element ref="xlf:context"/>
1824 </xsd:sequence>
1825 <xsd:attribute name="name" type="xsd:string" use="optional"/>
1826 <xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>
1827 <xsd:attribute name="purpose" type="xlf:AttrType_purpose" use="optional"/>
1828 </xsd:complexType>
1829 </xsd:element>
1830 <xsd:element name="context">
1831 <xsd:complexType>
1832 <xsd:simpleContent>
1833 <xsd:extension base="xsd:string">
1834 <xsd:attribute name="context-type" type="xlf:AttrType_context-type" use="required"/>
1835 <xsd:attribute default="no" name="match-mandatory" type="xlf:AttrType_YesNo" use="optional"/>
1836 <xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>
1837 </xsd:extension>
1838 </xsd:simpleContent>
1839 </xsd:complexType>
1840 </xsd:element>
1841 <xsd:element name="tool">
1842 <xsd:complexType mixed="true">
1843 <xsd:sequence>
1844 <xsd:any namespace="##any" processContents="strict" minOccurs="0" maxOccurs="unbounded"/>
1845 </xsd:sequence>
1846 <xsd:attribute name="tool-id" type="xsd:string" use="required"/>
1847 <xsd:attribute name="tool-name" type="xsd:string" use="required"/>
1848 <xsd:attribute name="tool-version" type="xsd:string" use="optional"/>
1849 <xsd:attribute name="tool-company" type="xsd:string" use="optional"/>
1850 <xsd:anyAttribute namespace="##other" processContents="strict"/>
1851 </xsd:complexType>
1852 </xsd:element>
1853 <xsd:element name="body">
1854 <xsd:complexType>
1855 <xsd:choice maxOccurs="unbounded" minOccurs="0">
1856 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:group"/>
1857 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:trans-unit"/>
1858 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:bin-unit"/>
1859 </xsd:choice>
1860 </xsd:complexType>
1861 </xsd:element>
1862 <xsd:element name="group">
1863 <xsd:complexType>
1864 <xsd:sequence>
1865 <xsd:sequence>
1866 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:context-group"/>
1867 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:count-group"/>
1868 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:note"/>
1869 <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
1870 </xsd:sequence>
1871 <xsd:choice maxOccurs="unbounded">
1872 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:group"/>
1873 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:trans-unit"/>
1874 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:bin-unit"/>
1875 </xsd:choice>
1876 </xsd:sequence>
1877 <xsd:attribute name="id" type="xsd:string" use="optional"/>
1878 <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
1879 <xsd:attribute default="default" ref="xml:space" use="optional"/>
1880 <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
1881 <xsd:attribute name="resname" type="xsd:string" use="optional"/>
1882 <xsd:attribute name="extradata" type="xsd:string" use="optional"/>
1883 <xsd:attribute name="extype" type="xsd:string" use="optional"/>
1884 <xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>
1885 <xsd:attribute name="menu" type="xsd:string" use="optional"/>
1886 <xsd:attribute name="menu-option" type="xsd:string" use="optional"/>
1887 <xsd:attribute name="menu-name" type="xsd:string" use="optional"/>
1888 <xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
1889 <xsd:attribute name="font" type="xsd:string" use="optional"/>
1890 <xsd:attribute name="css-style" type="xsd:string" use="optional"/>
1891 <xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
1892 <xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
1893 <xsd:attribute default="yes" name="translate" type="xlf:AttrType_YesNo" use="optional"/>
1894 <xsd:attribute default="yes" name="reformat" type="xlf:AttrType_reformat" use="optional"/>
1895 <xsd:attribute default="pixel" name="size-unit" type="xlf:AttrType_size-unit" use="optional"/>
1896 <xsd:attribute name="maxwidth" type="xsd:NMTOKEN" use="optional"/>
1897 <xsd:attribute name="minwidth" type="xsd:NMTOKEN" use="optional"/>
1898 <xsd:attribute name="maxheight" type="xsd:NMTOKEN" use="optional"/>
1899 <xsd:attribute name="minheight" type="xsd:NMTOKEN" use="optional"/>
1900 <xsd:attribute name="maxbytes" type="xsd:NMTOKEN" use="optional"/>
1901 <xsd:attribute name="minbytes" type="xsd:NMTOKEN" use="optional"/>
1902 <xsd:attribute name="charclass" type="xsd:string" use="optional"/>
1903 <xsd:attribute default="no" name="merged-trans" type="xlf:AttrType_YesNo" use="optional"/>
1904 <xsd:anyAttribute namespace="##other" processContents="strict"/>
1905 </xsd:complexType>
1906 </xsd:element>
1907 <xsd:element name="trans-unit">
1908 <xsd:complexType>
1909 <xsd:sequence>
1910 <xsd:element ref="xlf:source"/>
1911 <xsd:element minOccurs="0" ref="xlf:seg-source"/>
1912 <xsd:element minOccurs="0" ref="xlf:target"/>
1913 <xsd:choice maxOccurs="unbounded" minOccurs="0">
1914 <xsd:element ref="xlf:context-group"/>
1915 <xsd:element ref="xlf:count-group"/>
1916 <xsd:element ref="xlf:note"/>
1917 <xsd:element ref="xlf:alt-trans"/>
1918 </xsd:choice>
1919 <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
1920 </xsd:sequence>
1921 <xsd:attribute name="id" type="xsd:string" use="required"/>
1922 <xsd:attribute name="approved" type="xlf:AttrType_YesNo" use="optional"/>
1923 <xsd:attribute default="yes" name="translate" type="xlf:AttrType_YesNo" use="optional"/>
1924 <xsd:attribute default="yes" name="reformat" type="xlf:AttrType_reformat" use="optional"/>
1925 <xsd:attribute default="default" ref="xml:space" use="optional"/>
1926 <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
1927 <xsd:attribute name="phase-name" type="xsd:string" use="optional"/>
1928 <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
1929 <xsd:attribute name="resname" type="xsd:string" use="optional"/>
1930 <xsd:attribute name="extradata" type="xsd:string" use="optional"/>
1931 <xsd:attribute name="extype" type="xsd:string" use="optional"/>
1932 <xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>
1933 <xsd:attribute name="menu" type="xsd:string" use="optional"/>
1934 <xsd:attribute name="menu-option" type="xsd:string" use="optional"/>
1935 <xsd:attribute name="menu-name" type="xsd:string" use="optional"/>
1936 <xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
1937 <xsd:attribute name="font" type="xsd:string" use="optional"/>
1938 <xsd:attribute name="css-style" type="xsd:string" use="optional"/>
1939 <xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
1940 <xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
1941 <xsd:attribute default="pixel" name="size-unit" type="xlf:AttrType_size-unit" use="optional"/>
1942 <xsd:attribute name="maxwidth" type="xsd:NMTOKEN" use="optional"/>
1943 <xsd:attribute name="minwidth" type="xsd:NMTOKEN" use="optional"/>
1944 <xsd:attribute name="maxheight" type="xsd:NMTOKEN" use="optional"/>
1945 <xsd:attribute name="minheight" type="xsd:NMTOKEN" use="optional"/>
1946 <xsd:attribute name="maxbytes" type="xsd:NMTOKEN" use="optional"/>
1947 <xsd:attribute name="minbytes" type="xsd:NMTOKEN" use="optional"/>
1948 <xsd:attribute name="charclass" type="xsd:string" use="optional"/>
1949 <xsd:attribute default="yes" name="merged-trans" type="xlf:AttrType_YesNo" use="optional"/>
1950 <xsd:anyAttribute namespace="##other" processContents="strict"/>
1951 </xsd:complexType>
1952 <xsd:unique name="U_tu_segsrc_mid">
1953 <xsd:selector xpath="./xlf:seg-source/xlf:mrk"/>
1954 <xsd:field xpath="@mid"/>
1955 </xsd:unique>
1956 <xsd:keyref name="KR_tu_segsrc_mid" refer="xlf:U_tu_segsrc_mid">
1957 <xsd:selector xpath="./xlf:target/xlf:mrk|./xlf:alt-trans"/>
1958 <xsd:field xpath="@mid"/>
1959 </xsd:keyref>
1960 </xsd:element>
1961 <xsd:element name="source">
1962 <xsd:complexType mixed="true">
1963 <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
1964 <xsd:attribute ref="xml:lang" use="optional"/>
1965 <xsd:anyAttribute namespace="##other" processContents="strict"/>
1966 </xsd:complexType>
1967 <xsd:unique name="U_source_bpt_rid">
1968 <xsd:selector xpath=".//xlf:bpt"/>
1969 <xsd:field xpath="@rid"/>
1970 </xsd:unique>
1971 <xsd:keyref name="KR_source_ept_rid" refer="xlf:U_source_bpt_rid">
1972 <xsd:selector xpath=".//xlf:ept"/>
1973 <xsd:field xpath="@rid"/>
1974 </xsd:keyref>
1975 <xsd:unique name="U_source_bx_rid">
1976 <xsd:selector xpath=".//xlf:bx"/>
1977 <xsd:field xpath="@rid"/>
1978 </xsd:unique>
1979 <xsd:keyref name="KR_source_ex_rid" refer="xlf:U_source_bx_rid">
1980 <xsd:selector xpath=".//xlf:ex"/>
1981 <xsd:field xpath="@rid"/>
1982 </xsd:keyref>
1983 </xsd:element>
1984 <xsd:element name="seg-source">
1985 <xsd:complexType mixed="true">
1986 <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
1987 <xsd:attribute ref="xml:lang" use="optional"/>
1988 <xsd:anyAttribute namespace="##other" processContents="strict"/>
1989 </xsd:complexType>
1990 <xsd:unique name="U_segsrc_bpt_rid">
1991 <xsd:selector xpath=".//xlf:bpt"/>
1992 <xsd:field xpath="@rid"/>
1993 </xsd:unique>
1994 <xsd:keyref name="KR_segsrc_ept_rid" refer="xlf:U_segsrc_bpt_rid">
1995 <xsd:selector xpath=".//xlf:ept"/>
1996 <xsd:field xpath="@rid"/>
1997 </xsd:keyref>
1998 <xsd:unique name="U_segsrc_bx_rid">
1999 <xsd:selector xpath=".//xlf:bx"/>
2000 <xsd:field xpath="@rid"/>
2001 </xsd:unique>
2002 <xsd:keyref name="KR_segsrc_ex_rid" refer="xlf:U_segsrc_bx_rid">
2003 <xsd:selector xpath=".//xlf:ex"/>
2004 <xsd:field xpath="@rid"/>
2005 </xsd:keyref>
2006 </xsd:element>
2007 <xsd:element name="target">
2008 <xsd:complexType mixed="true">
2009 <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
2010 <xsd:attribute name="state" type="xlf:AttrType_state" use="optional"/>
2011 <xsd:attribute name="state-qualifier" type="xlf:AttrType_state-qualifier" use="optional"/>
2012 <xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>
2013 <xsd:attribute ref="xml:lang" use="optional"/>
2014 <xsd:attribute name="resname" type="xsd:string" use="optional"/>
2015 <xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
2016 <xsd:attribute name="font" type="xsd:string" use="optional"/>
2017 <xsd:attribute name="css-style" type="xsd:string" use="optional"/>
2018 <xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
2019 <xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
2020 <xsd:attribute default="yes" name="equiv-trans" type="xlf:AttrType_YesNo" use="optional"/>
2021 <xsd:anyAttribute namespace="##other" processContents="strict"/>
2022 </xsd:complexType>
2023 <xsd:unique name="U_target_bpt_rid">
2024 <xsd:selector xpath=".//xlf:bpt"/>
2025 <xsd:field xpath="@rid"/>
2026 </xsd:unique>
2027 <xsd:keyref name="KR_target_ept_rid" refer="xlf:U_target_bpt_rid">
2028 <xsd:selector xpath=".//xlf:ept"/>
2029 <xsd:field xpath="@rid"/>
2030 </xsd:keyref>
2031 <xsd:unique name="U_target_bx_rid">
2032 <xsd:selector xpath=".//xlf:bx"/>
2033 <xsd:field xpath="@rid"/>
2034 </xsd:unique>
2035 <xsd:keyref name="KR_target_ex_rid" refer="xlf:U_target_bx_rid">
2036 <xsd:selector xpath=".//xlf:ex"/>
2037 <xsd:field xpath="@rid"/>
2038 </xsd:keyref>
2039 </xsd:element>
2040 <xsd:element name="alt-trans">
2041 <xsd:complexType>
2042 <xsd:sequence>
2043 <xsd:element minOccurs="0" ref="xlf:source"/>
2044 <xsd:element minOccurs="0" ref="xlf:seg-source"/>
2045 <xsd:element maxOccurs="1" ref="xlf:target"/>
2046 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:context-group"/>
2047 <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:note"/>
2048 <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
2049 </xsd:sequence>
2050 <xsd:attribute name="match-quality" type="xsd:string" use="optional"/>
2051 <xsd:attribute name="tool-id" type="xsd:string" use="optional"/>
2052 <xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>
2053 <xsd:attribute ref="xml:lang" use="optional"/>
2054 <xsd:attribute name="origin" type="xsd:string" use="optional"/>
2055 <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
2056 <xsd:attribute default="default" ref="xml:space" use="optional"/>
2057 <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
2058 <xsd:attribute name="resname" type="xsd:string" use="optional"/>
2059 <xsd:attribute name="extradata" type="xsd:string" use="optional"/>
2060 <xsd:attribute name="extype" type="xsd:string" use="optional"/>
2061 <xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>
2062 <xsd:attribute name="menu" type="xsd:string" use="optional"/>
2063 <xsd:attribute name="menu-option" type="xsd:string" use="optional"/>
2064 <xsd:attribute name="menu-name" type="xsd:string" use="optional"/>
2065 <xsd:attribute name="mid" type="xsd:NMTOKEN" use="optional"/>
2066 <xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
2067 <xsd:attribute name="font" type="xsd:string" use="optional"/>
2068 <xsd:attribute name="css-style" type="xsd:string" use="optional"/>
2069 <xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
2070 <xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
2071 <xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>
2072 <xsd:attribute default="proposal" name="alttranstype" type="xlf:AttrType_alttranstype" use="optional"/>
2073 <xsd:anyAttribute namespace="##other" processContents="strict"/>
2074 </xsd:complexType>
2075 <xsd:unique name="U_at_segsrc_mid">
2076 <xsd:selector xpath="./xlf:seg-source/xlf:mrk"/>
2077 <xsd:field xpath="@mid"/>
2078 </xsd:unique>
2079 <xsd:keyref name="KR_at_segsrc_mid" refer="xlf:U_at_segsrc_mid">
2080 <xsd:selector xpath="./xlf:target/xlf:mrk"/>
2081 <xsd:field xpath="@mid"/>
2082 </xsd:keyref>
2083 </xsd:element>
2084 <xsd:element name="bin-unit">
2085 <xsd:complexType>
2086 <xsd:sequence>
2087 <xsd:element ref="xlf:bin-source"/>
2088 <xsd:element minOccurs="0" ref="xlf:bin-target"/>
2089 <xsd:choice maxOccurs="unbounded" minOccurs="0">
2090 <xsd:element ref="xlf:context-group"/>
2091 <xsd:element ref="xlf:count-group"/>
2092 <xsd:element ref="xlf:note"/>
2093 <xsd:element ref="xlf:trans-unit"/>
2094 </xsd:choice>
2095 <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
2096 </xsd:sequence>
2097 <xsd:attribute name="id" type="xsd:string" use="required"/>
2098 <xsd:attribute name="mime-type" type="xlf:mime-typeValueList" use="required"/>
2099 <xsd:attribute name="approved" type="xlf:AttrType_YesNo" use="optional"/>
2100 <xsd:attribute default="yes" name="translate" type="xlf:AttrType_YesNo" use="optional"/>
2101 <xsd:attribute default="yes" name="reformat" type="xlf:AttrType_reformat" use="optional"/>
2102 <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
2103 <xsd:attribute name="resname" type="xsd:string" use="optional"/>
2104 <xsd:attribute name="phase-name" type="xsd:string" use="optional"/>
2105 <xsd:anyAttribute namespace="##other" processContents="strict"/>
2106 </xsd:complexType>
2107 </xsd:element>
2108 <xsd:element name="bin-source">
2109 <xsd:complexType>
2110 <xsd:choice>
2111 <xsd:element ref="xlf:internal-file"/>
2112 <xsd:element ref="xlf:external-file"/>
2113 </xsd:choice>
2114 <xsd:anyAttribute namespace="##other" processContents="strict"/>
2115 </xsd:complexType>
2116 </xsd:element>
2117 <xsd:element name="bin-target">
2118 <xsd:complexType>
2119 <xsd:choice>
2120 <xsd:element ref="xlf:internal-file"/>
2121 <xsd:element ref="xlf:external-file"/>
2122 </xsd:choice>
2123 <xsd:attribute name="mime-type" type="xlf:mime-typeValueList" use="optional"/>
2124 <xsd:attribute name="state" type="xlf:AttrType_state" use="optional"/>
2125 <xsd:attribute name="state-qualifier" type="xlf:AttrType_state-qualifier" use="optional"/>
2126 <xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>
2127 <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
2128 <xsd:attribute name="resname" type="xsd:string" use="optional"/>
2129 <xsd:anyAttribute namespace="##other" processContents="strict"/>
2130 </xsd:complexType>
2131 </xsd:element>
2132 <!-- Element for inline codes -->
2133 <xsd:element name="g">
2134 <xsd:complexType mixed="true">
2135 <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
2136 <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
2137 <xsd:attribute default="yes" name="clone" type="xlf:AttrType_YesNo" use="optional"/>
2138 <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
2139 </xsd:complexType>
2140 </xsd:element>
2141 <xsd:element name="x">
2142 <xsd:complexType>
2143 <xsd:attribute name="ctype" type="xlf:AttrType_InlinePlaceholders" use="optional"/>
2144 <xsd:attribute default="yes" name="clone" type="xlf:AttrType_YesNo" use="optional"/>
2145 <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
2146 </xsd:complexType>
2147 </xsd:element>
2148 <xsd:element name="bx">
2149 <xsd:complexType>
2150 <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
2151 <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
2152 <xsd:attribute default="yes" name="clone" type="xlf:AttrType_YesNo" use="optional"/>
2153 <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
2154 </xsd:complexType>
2155 </xsd:element>
2156 <xsd:element name="ex">
2157 <xsd:complexType>
2158 <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
2159 <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
2160 </xsd:complexType>
2161 </xsd:element>
2162 <xsd:element name="ph">
2163 <xsd:complexType mixed="true">
2164 <xsd:sequence maxOccurs="unbounded" minOccurs="0">
2165 <xsd:element ref="xlf:sub"/>
2166 </xsd:sequence>
2167 <xsd:attribute name="ctype" type="xlf:AttrType_InlinePlaceholders" use="optional"/>
2168 <xsd:attribute name="crc" type="xsd:string" use="optional"/>
2169 <xsd:attribute name="assoc" type="xlf:AttrType_assoc" use="optional"/>
2170 <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
2171 </xsd:complexType>
2172 </xsd:element>
2173 <xsd:element name="bpt">
2174 <xsd:complexType mixed="true">
2175 <xsd:sequence maxOccurs="unbounded" minOccurs="0">
2176 <xsd:element ref="xlf:sub"/>
2177 </xsd:sequence>
2178 <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
2179 <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
2180 <xsd:attribute name="crc" type="xsd:string" use="optional"/>
2181 <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
2182 </xsd:complexType>
2183 </xsd:element>
2184 <xsd:element name="ept">
2185 <xsd:complexType mixed="true">
2186 <xsd:sequence maxOccurs="unbounded" minOccurs="0">
2187 <xsd:element ref="xlf:sub"/>
2188 </xsd:sequence>
2189 <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
2190 <xsd:attribute name="crc" type="xsd:string" use="optional"/>
2191 <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
2192 </xsd:complexType>
2193 </xsd:element>
2194 <xsd:element name="it">
2195 <xsd:complexType mixed="true">
2196 <xsd:sequence maxOccurs="unbounded" minOccurs="0">
2197 <xsd:element ref="xlf:sub"/>
2198 </xsd:sequence>
2199 <xsd:attribute name="pos" type="xlf:AttrType_Position" use="required"/>
2200 <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
2201 <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
2202 <xsd:attribute name="crc" type="xsd:string" use="optional"/>
2203 <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
2204 </xsd:complexType>
2205 </xsd:element>
2206 <xsd:element name="sub">
2207 <xsd:complexType mixed="true">
2208 <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
2209 <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
2210 <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
2211 <xsd:attribute name="xid" type="xsd:string" use="optional"/>
2212 </xsd:complexType>
2213 </xsd:element>
2214 <xsd:element name="mrk">
2215 <xsd:complexType mixed="true">
2216 <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
2217 <xsd:attribute name="mtype" type="xlf:AttrType_mtype" use="required"/>
2218 <xsd:attribute name="mid" type="xsd:NMTOKEN" use="optional"/>
2219 <xsd:attribute name="comment" type="xsd:string" use="optional"/>
2220 <xsd:anyAttribute namespace="##other" processContents="strict"/>
2221 </xsd:complexType>
2222 </xsd:element>
2223</xsd:schema>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xml.xsd b/vendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xml.xsd
new file mode 100644
index 00000000..8fcb991a
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xml.xsd
@@ -0,0 +1,309 @@
1<?xml version='1.0'?>
2<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
3<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
4 xmlns:xs="http://www.w3.org/2001/XMLSchema"
5 xmlns ="http://www.w3.org/1999/xhtml"
6 xml:lang="en">
7
8 <xs:annotation>
9 <xs:documentation>
10 <div>
11 <h1>About the XML namespace</h1>
12
13 <div class="bodytext">
14 <p>
15
16 This schema document describes the XML namespace, in a form
17 suitable for import by other schema documents.
18 </p>
19 <p>
20 See <a href="http://www.w3.org/XML/1998/namespace.html">
21 http://www.w3.org/XML/1998/namespace.html</a> and
22 <a href="http://www.w3.org/TR/REC-xml">
23 http://www.w3.org/TR/REC-xml</a> for information
24 about this namespace.
25 </p>
26
27 <p>
28 Note that local names in this namespace are intended to be
29 defined only by the World Wide Web Consortium or its subgroups.
30 The names currently defined in this namespace are listed below.
31 They should not be used with conflicting semantics by any Working
32 Group, specification, or document instance.
33 </p>
34 <p>
35 See further below in this document for more information about <a
36 href="#usage">how to refer to this schema document from your own
37 XSD schema documents</a> and about <a href="#nsversioning">the
38 namespace-versioning policy governing this schema document</a>.
39 </p>
40 </div>
41 </div>
42
43 </xs:documentation>
44 </xs:annotation>
45
46 <xs:attribute name="lang">
47 <xs:annotation>
48 <xs:documentation>
49 <div>
50
51 <h3>lang (as an attribute name)</h3>
52 <p>
53
54 denotes an attribute whose value
55 is a language code for the natural language of the content of
56 any element; its value is inherited. This name is reserved
57 by virtue of its definition in the XML specification.</p>
58
59 </div>
60 <div>
61 <h4>Notes</h4>
62 <p>
63 Attempting to install the relevant ISO 2- and 3-letter
64 codes as the enumerated possible values is probably never
65 going to be a realistic possibility.
66 </p>
67 <p>
68
69 See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
70 http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
71 and the IANA language subtag registry at
72 <a href="http://www.iana.org/assignments/language-subtag-registry">
73 http://www.iana.org/assignments/language-subtag-registry</a>
74 for further information.
75 </p>
76 <p>
77
78 The union allows for the 'un-declaration' of xml:lang with
79 the empty string.
80 </p>
81 </div>
82 </xs:documentation>
83 </xs:annotation>
84 <xs:simpleType>
85 <xs:union memberTypes="xs:language">
86 <xs:simpleType>
87 <xs:restriction base="xs:string">
88 <xs:enumeration value=""/>
89
90 </xs:restriction>
91 </xs:simpleType>
92 </xs:union>
93 </xs:simpleType>
94 </xs:attribute>
95
96 <xs:attribute name="space">
97 <xs:annotation>
98 <xs:documentation>
99
100 <div>
101
102 <h3>space (as an attribute name)</h3>
103 <p>
104 denotes an attribute whose
105 value is a keyword indicating what whitespace processing
106 discipline is intended for the content of the element; its
107 value is inherited. This name is reserved by virtue of its
108 definition in the XML specification.</p>
109
110 </div>
111 </xs:documentation>
112 </xs:annotation>
113 <xs:simpleType>
114
115 <xs:restriction base="xs:NCName">
116 <xs:enumeration value="default"/>
117 <xs:enumeration value="preserve"/>
118 </xs:restriction>
119 </xs:simpleType>
120 </xs:attribute>
121
122 <xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
123 <xs:documentation>
124
125 <div>
126
127 <h3>base (as an attribute name)</h3>
128 <p>
129 denotes an attribute whose value
130 provides a URI to be used as the base for interpreting any
131 relative URIs in the scope of the element on which it
132 appears; its value is inherited. This name is reserved
133 by virtue of its definition in the XML Base specification.</p>
134
135 <p>
136 See <a
137 href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
138 for information about this attribute.
139 </p>
140
141 </div>
142 </xs:documentation>
143 </xs:annotation>
144 </xs:attribute>
145
146 <xs:attribute name="id" type="xs:ID">
147 <xs:annotation>
148 <xs:documentation>
149 <div>
150
151 <h3>id (as an attribute name)</h3>
152 <p>
153
154 denotes an attribute whose value
155 should be interpreted as if declared to be of type ID.
156 This name is reserved by virtue of its definition in the
157 xml:id specification.</p>
158
159 <p>
160 See <a
161 href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
162 for information about this attribute.
163 </p>
164 </div>
165 </xs:documentation>
166 </xs:annotation>
167
168 </xs:attribute>
169
170 <xs:attributeGroup name="specialAttrs">
171 <xs:attribute ref="xml:base"/>
172 <xs:attribute ref="xml:lang"/>
173 <xs:attribute ref="xml:space"/>
174 <xs:attribute ref="xml:id"/>
175 </xs:attributeGroup>
176
177 <xs:annotation>
178
179 <xs:documentation>
180 <div>
181
182 <h3>Father (in any context at all)</h3>
183
184 <div class="bodytext">
185 <p>
186 denotes Jon Bosak, the chair of
187 the original XML Working Group. This name is reserved by
188 the following decision of the W3C XML Plenary and
189 XML Coordination groups:
190 </p>
191 <blockquote>
192 <p>
193
194 In appreciation for his vision, leadership and
195 dedication the W3C XML Plenary on this 10th day of
196 February, 2000, reserves for Jon Bosak in perpetuity
197 the XML name "xml:Father".
198 </p>
199 </blockquote>
200 </div>
201 </div>
202 </xs:documentation>
203 </xs:annotation>
204
205 <xs:annotation>
206 <xs:documentation>
207
208 <div xml:id="usage" id="usage">
209 <h2><a name="usage">About this schema document</a></h2>
210
211 <div class="bodytext">
212 <p>
213 This schema defines attributes and an attribute group suitable
214 for use by schemas wishing to allow <code>xml:base</code>,
215 <code>xml:lang</code>, <code>xml:space</code> or
216 <code>xml:id</code> attributes on elements they define.
217 </p>
218
219 <p>
220 To enable this, such a schema must import this schema for
221 the XML namespace, e.g. as follows:
222 </p>
223 <pre>
224 &lt;schema.. .>
225 .. .
226 &lt;import namespace="http://www.w3.org/XML/1998/namespace"
227 schemaLocation="http://www.w3.org/2001/xml.xsd"/>
228 </pre>
229 <p>
230 or
231 </p>
232 <pre>
233
234 &lt;import namespace="http://www.w3.org/XML/1998/namespace"
235 schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
236 </pre>
237 <p>
238 Subsequently, qualified reference to any of the attributes or the
239 group defined below will have the desired effect, e.g.
240 </p>
241 <pre>
242 &lt;type.. .>
243 .. .
244 &lt;attributeGroup ref="xml:specialAttrs"/>
245 </pre>
246 <p>
247 will define a type which will schema-validate an instance element
248 with any of those attributes.
249 </p>
250
251 </div>
252 </div>
253 </xs:documentation>
254 </xs:annotation>
255
256 <xs:annotation>
257 <xs:documentation>
258 <div id="nsversioning" xml:id="nsversioning">
259 <h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
260
261 <div class="bodytext">
262 <p>
263 In keeping with the XML Schema WG's standard versioning
264 policy, this schema document will persist at
265 <a href="http://www.w3.org/2009/01/xml.xsd">
266 http://www.w3.org/2009/01/xml.xsd</a>.
267 </p>
268 <p>
269 At the date of issue it can also be found at
270 <a href="http://www.w3.org/2001/xml.xsd">
271 http://www.w3.org/2001/xml.xsd</a>.
272 </p>
273
274 <p>
275 The schema document at that URI may however change in the future,
276 in order to remain compatible with the latest version of XML
277 Schema itself, or with the XML namespace itself. In other words,
278 if the XML Schema or XML namespaces change, the version of this
279 document at <a href="http://www.w3.org/2001/xml.xsd">
280 http://www.w3.org/2001/xml.xsd
281 </a>
282 will change accordingly; the version at
283 <a href="http://www.w3.org/2009/01/xml.xsd">
284 http://www.w3.org/2009/01/xml.xsd
285 </a>
286 will not change.
287 </p>
288 <p>
289
290 Previous dated (and unchanging) versions of this schema
291 document are at:
292 </p>
293 <ul>
294 <li><a href="http://www.w3.org/2009/01/xml.xsd">
295 http://www.w3.org/2009/01/xml.xsd</a></li>
296 <li><a href="http://www.w3.org/2007/08/xml.xsd">
297 http://www.w3.org/2007/08/xml.xsd</a></li>
298 <li><a href="http://www.w3.org/2004/10/xml.xsd">
299
300 http://www.w3.org/2004/10/xml.xsd</a></li>
301 <li><a href="http://www.w3.org/2001/03/xml.xsd">
302 http://www.w3.org/2001/03/xml.xsd</a></li>
303 </ul>
304 </div>
305 </div>
306 </xs:documentation>
307 </xs:annotation>
308
309</xs:schema>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/MessageCatalogue.php b/vendor/symfony/translation/Symfony/Component/Translation/MessageCatalogue.php
new file mode 100644
index 00000000..1d8a08d8
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/MessageCatalogue.php
@@ -0,0 +1,295 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation;
13
14use Symfony\Component\Config\Resource\ResourceInterface;
15
16/**
17 * MessageCatalogue.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 *
21 * @api
22 */
23class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface
24{
25 private $messages = array();
26 private $metadata = array();
27 private $resources = array();
28 private $locale;
29 private $fallbackCatalogue;
30 private $parent;
31
32 /**
33 * Constructor.
34 *
35 * @param string $locale The locale
36 * @param array $messages An array of messages classified by domain
37 *
38 * @api
39 */
40 public function __construct($locale, array $messages = array())
41 {
42 $this->locale = $locale;
43 $this->messages = $messages;
44 }
45
46 /**
47 * {@inheritdoc}
48 *
49 * @api
50 */
51 public function getLocale()
52 {
53 return $this->locale;
54 }
55
56 /**
57 * {@inheritdoc}
58 *
59 * @api
60 */
61 public function getDomains()
62 {
63 return array_keys($this->messages);
64 }
65
66 /**
67 * {@inheritdoc}
68 *
69 * @api
70 */
71 public function all($domain = null)
72 {
73 if (null === $domain) {
74 return $this->messages;
75 }
76
77 return isset($this->messages[$domain]) ? $this->messages[$domain] : array();
78 }
79
80 /**
81 * {@inheritdoc}
82 *
83 * @api
84 */
85 public function set($id, $translation, $domain = 'messages')
86 {
87 $this->add(array($id => $translation), $domain);
88 }
89
90 /**
91 * {@inheritdoc}
92 *
93 * @api
94 */
95 public function has($id, $domain = 'messages')
96 {
97 if (isset($this->messages[$domain][$id])) {
98 return true;
99 }
100
101 if (null !== $this->fallbackCatalogue) {
102 return $this->fallbackCatalogue->has($id, $domain);
103 }
104
105 return false;
106 }
107
108 /**
109 * {@inheritdoc}
110 */
111 public function defines($id, $domain = 'messages')
112 {
113 return isset($this->messages[$domain][$id]);
114 }
115
116 /**
117 * {@inheritdoc}
118 *
119 * @api
120 */
121 public function get($id, $domain = 'messages')
122 {
123 if (isset($this->messages[$domain][$id])) {
124 return $this->messages[$domain][$id];
125 }
126
127 if (null !== $this->fallbackCatalogue) {
128 return $this->fallbackCatalogue->get($id, $domain);
129 }
130
131 return $id;
132 }
133
134 /**
135 * {@inheritdoc}
136 *
137 * @api
138 */
139 public function replace($messages, $domain = 'messages')
140 {
141 $this->messages[$domain] = array();
142
143 $this->add($messages, $domain);
144 }
145
146 /**
147 * {@inheritdoc}
148 *
149 * @api
150 */
151 public function add($messages, $domain = 'messages')
152 {
153 if (!isset($this->messages[$domain])) {
154 $this->messages[$domain] = $messages;
155 } else {
156 $this->messages[$domain] = array_replace($this->messages[$domain], $messages);
157 }
158 }
159
160 /**
161 * {@inheritdoc}
162 *
163 * @api
164 */
165 public function addCatalogue(MessageCatalogueInterface $catalogue)
166 {
167 if ($catalogue->getLocale() !== $this->locale) {
168 throw new \LogicException(sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s"', $catalogue->getLocale(), $this->locale));
169 }
170
171 foreach ($catalogue->all() as $domain => $messages) {
172 $this->add($messages, $domain);
173 }
174
175 foreach ($catalogue->getResources() as $resource) {
176 $this->addResource($resource);
177 }
178
179 if ($catalogue instanceof MetadataAwareInterface) {
180 $metadata = $catalogue->getMetadata('', '');
181 $this->addMetadata($metadata);
182 }
183 }
184
185 /**
186 * {@inheritdoc}
187 *
188 * @api
189 */
190 public function addFallbackCatalogue(MessageCatalogueInterface $catalogue)
191 {
192 // detect circular references
193 $c = $this;
194 do {
195 if ($c->getLocale() === $catalogue->getLocale()) {
196 throw new \LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
197 }
198 } while ($c = $c->parent);
199
200 $catalogue->parent = $this;
201 $this->fallbackCatalogue = $catalogue;
202
203 foreach ($catalogue->getResources() as $resource) {
204 $this->addResource($resource);
205 }
206 }
207
208 /**
209 * {@inheritdoc}
210 *
211 * @api
212 */
213 public function getFallbackCatalogue()
214 {
215 return $this->fallbackCatalogue;
216 }
217
218 /**
219 * {@inheritdoc}
220 *
221 * @api
222 */
223 public function getResources()
224 {
225 return array_values($this->resources);
226 }
227
228 /**
229 * {@inheritdoc}
230 *
231 * @api
232 */
233 public function addResource(ResourceInterface $resource)
234 {
235 $this->resources[$resource->__toString()] = $resource;
236 }
237
238 /**
239 * {@inheritdoc}
240 */
241 public function getMetadata($key = '', $domain = 'messages')
242 {
243 if ('' == $domain) {
244 return $this->metadata;
245 }
246
247 if (isset($this->metadata[$domain])) {
248 if ('' == $key) {
249 return $this->metadata[$domain];
250 }
251
252 if (isset($this->metadata[$domain][$key])) {
253 return $this->metadata[$domain][$key];
254 }
255 }
256
257 return null;
258 }
259
260 /**
261 * {@inheritdoc}
262 */
263 public function setMetadata($key, $value, $domain = 'messages')
264 {
265 $this->metadata[$domain][$key] = $value;
266 }
267
268 /**
269 * {@inheritdoc}
270 */
271 public function deleteMetadata($key = '', $domain = 'messages')
272 {
273 if ('' == $domain) {
274 $this->metadata = array();
275 } elseif ('' == $key) {
276 unset($this->metadata[$domain]);
277 } else {
278 unset($this->metadata[$domain][$key]);
279 }
280 }
281
282 /**
283 * Adds current values with the new values.
284 *
285 * @param array $values Values to add
286 */
287 private function addMetadata(array $values)
288 {
289 foreach ($values as $domain => $keys) {
290 foreach ($keys as $key => $value) {
291 $this->setMetadata($key, $value, $domain);
292 }
293 }
294 }
295}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/MessageCatalogueInterface.php b/vendor/symfony/translation/Symfony/Component/Translation/MessageCatalogueInterface.php
new file mode 100644
index 00000000..5e9be20c
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/MessageCatalogueInterface.php
@@ -0,0 +1,172 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation;
13
14use Symfony\Component\Config\Resource\ResourceInterface;
15
16/**
17 * MessageCatalogueInterface.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 *
21 * @api
22 */
23interface MessageCatalogueInterface
24{
25 /**
26 * Gets the catalogue locale.
27 *
28 * @return string The locale
29 *
30 * @api
31 */
32 public function getLocale();
33
34 /**
35 * Gets the domains.
36 *
37 * @return array An array of domains
38 *
39 * @api
40 */
41 public function getDomains();
42
43 /**
44 * Gets the messages within a given domain.
45 *
46 * If $domain is null, it returns all messages.
47 *
48 * @param string $domain The domain name
49 *
50 * @return array An array of messages
51 *
52 * @api
53 */
54 public function all($domain = null);
55
56 /**
57 * Sets a message translation.
58 *
59 * @param string $id The message id
60 * @param string $translation The messages translation
61 * @param string $domain The domain name
62 *
63 * @api
64 */
65 public function set($id, $translation, $domain = 'messages');
66
67 /**
68 * Checks if a message has a translation.
69 *
70 * @param string $id The message id
71 * @param string $domain The domain name
72 *
73 * @return Boolean true if the message has a translation, false otherwise
74 *
75 * @api
76 */
77 public function has($id, $domain = 'messages');
78
79 /**
80 * Checks if a message has a translation (it does not take into account the fallback mechanism).
81 *
82 * @param string $id The message id
83 * @param string $domain The domain name
84 *
85 * @return Boolean true if the message has a translation, false otherwise
86 *
87 * @api
88 */
89 public function defines($id, $domain = 'messages');
90
91 /**
92 * Gets a message translation.
93 *
94 * @param string $id The message id
95 * @param string $domain The domain name
96 *
97 * @return string The message translation
98 *
99 * @api
100 */
101 public function get($id, $domain = 'messages');
102
103 /**
104 * Sets translations for a given domain.
105 *
106 * @param array $messages An array of translations
107 * @param string $domain The domain name
108 *
109 * @api
110 */
111 public function replace($messages, $domain = 'messages');
112
113 /**
114 * Adds translations for a given domain.
115 *
116 * @param array $messages An array of translations
117 * @param string $domain The domain name
118 *
119 * @api
120 */
121 public function add($messages, $domain = 'messages');
122
123 /**
124 * Merges translations from the given Catalogue into the current one.
125 *
126 * The two catalogues must have the same locale.
127 *
128 * @param MessageCatalogueInterface $catalogue A MessageCatalogueInterface instance
129 *
130 * @api
131 */
132 public function addCatalogue(MessageCatalogueInterface $catalogue);
133
134 /**
135 * Merges translations from the given Catalogue into the current one
136 * only when the translation does not exist.
137 *
138 * This is used to provide default translations when they do not exist for the current locale.
139 *
140 * @param MessageCatalogueInterface $catalogue A MessageCatalogueInterface instance
141 *
142 * @api
143 */
144 public function addFallbackCatalogue(MessageCatalogueInterface $catalogue);
145
146 /**
147 * Gets the fallback catalogue.
148 *
149 * @return MessageCatalogueInterface|null A MessageCatalogueInterface instance or null when no fallback has been set
150 *
151 * @api
152 */
153 public function getFallbackCatalogue();
154
155 /**
156 * Returns an array of resources loaded to build this collection.
157 *
158 * @return ResourceInterface[] An array of resources
159 *
160 * @api
161 */
162 public function getResources();
163
164 /**
165 * Adds a resource for this collection.
166 *
167 * @param ResourceInterface $resource A resource instance
168 *
169 * @api
170 */
171 public function addResource(ResourceInterface $resource);
172}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/MessageSelector.php b/vendor/symfony/translation/Symfony/Component/Translation/MessageSelector.php
new file mode 100644
index 00000000..387c964d
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/MessageSelector.php
@@ -0,0 +1,82 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation;
13
14/**
15 * MessageSelector.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 *
19 * @api
20 */
21class MessageSelector
22{
23 /**
24 * Given a message with different plural translations separated by a
25 * pipe (|), this method returns the correct portion of the message based
26 * on the given number, locale and the pluralization rules in the message
27 * itself.
28 *
29 * The message supports two different types of pluralization rules:
30 *
31 * interval: {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples
32 * indexed: There is one apple|There are %count% apples
33 *
34 * The indexed solution can also contain labels (e.g. one: There is one apple).
35 * This is purely for making the translations more clear - it does not
36 * affect the functionality.
37 *
38 * The two methods can also be mixed:
39 * {0} There are no apples|one: There is one apple|more: There are %count% apples
40 *
41 * @param string $message The message being translated
42 * @param integer $number The number of items represented for the message
43 * @param string $locale The locale to use for choosing
44 *
45 * @return string
46 *
47 * @throws \InvalidArgumentException
48 *
49 * @api
50 */
51 public function choose($message, $number, $locale)
52 {
53 $parts = explode('|', $message);
54 $explicitRules = array();
55 $standardRules = array();
56 foreach ($parts as $part) {
57 $part = trim($part);
58
59 if (preg_match('/^(?P<interval>'.Interval::getIntervalRegexp().')\s*(?P<message>.*?)$/x', $part, $matches)) {
60 $explicitRules[$matches['interval']] = $matches['message'];
61 } elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) {
62 $standardRules[] = $matches[1];
63 } else {
64 $standardRules[] = $part;
65 }
66 }
67
68 // try to match an explicit rule, then fallback to the standard ones
69 foreach ($explicitRules as $interval => $m) {
70 if (Interval::test($number, $interval)) {
71 return $m;
72 }
73 }
74
75 $position = PluralizationRules::get($number, $locale);
76 if (!isset($standardRules[$position])) {
77 throw new \InvalidArgumentException(sprintf('Unable to choose a translation for "%s" with locale "%s". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $message, $locale));
78 }
79
80 return $standardRules[$position];
81 }
82}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/MetadataAwareInterface.php b/vendor/symfony/translation/Symfony/Component/Translation/MetadataAwareInterface.php
new file mode 100644
index 00000000..1c439351
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/MetadataAwareInterface.php
@@ -0,0 +1,54 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation;
13
14/**
15 * MetadataAwareInterface.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19interface MetadataAwareInterface
20{
21 /**
22 * Gets metadata for the given domain and key.
23 *
24 * Passing an empty domain will return an array with all metadata indexed by
25 * domain and then by key. Passing an empty key will return an array with all
26 * metadata for the given domain.
27 *
28 * @param string $domain The domain name
29 * @param string $key The key
30 *
31 * @return mixed The value that was set or an array with the domains/keys or null
32 */
33 public function getMetadata($key = '', $domain = 'messages');
34
35 /**
36 * Adds metadata to a message domain.
37 *
38 * @param string $key The key
39 * @param mixed $value The value
40 * @param string $domain The domain name
41 */
42 public function setMetadata($key, $value, $domain = 'messages');
43
44 /**
45 * Deletes metadata for the given key and domain.
46 *
47 * Passing an empty domain will delete all metadata. Passing an empty key will
48 * delete all metadata for the given domain.
49 *
50 * @param string $domain The domain name
51 * @param string $key The key
52 */
53 public function deleteMetadata($key = '', $domain = 'messages');
54}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/PluralizationRules.php b/vendor/symfony/translation/Symfony/Component/Translation/PluralizationRules.php
new file mode 100644
index 00000000..5c63b8d0
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/PluralizationRules.php
@@ -0,0 +1,219 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation;
13
14/**
15 * Returns the plural rules for a given locale.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19class PluralizationRules
20{
21 // @codeCoverageIgnoreStart
22 private static $rules = array();
23
24 /**
25 * Returns the plural position to use for the given locale and number.
26 *
27 * @param integer $number The number
28 * @param string $locale The locale
29 *
30 * @return integer The plural position
31 */
32 public static function get($number, $locale)
33 {
34 if ("pt_BR" == $locale) {
35 // temporary set a locale for brazilian
36 $locale = "xbr";
37 }
38
39 if (strlen($locale) > 3) {
40 $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
41 }
42
43 if (isset(self::$rules[$locale])) {
44 $return = call_user_func(self::$rules[$locale], $number);
45
46 if (!is_int($return) || $return < 0) {
47 return 0;
48 }
49
50 return $return;
51 }
52
53 /*
54 * The plural rules are derived from code of the Zend Framework (2010-09-25),
55 * which is subject to the new BSD license (http://framework.zend.com/license/new-bsd).
56 * Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
57 */
58 switch ($locale) {
59 case 'bo':
60 case 'dz':
61 case 'id':
62 case 'ja':
63 case 'jv':
64 case 'ka':
65 case 'km':
66 case 'kn':
67 case 'ko':
68 case 'ms':
69 case 'th':
70 case 'tr':
71 case 'vi':
72 case 'zh':
73 return 0;
74 break;
75
76 case 'af':
77 case 'az':
78 case 'bn':
79 case 'bg':
80 case 'ca':
81 case 'da':
82 case 'de':
83 case 'el':
84 case 'en':
85 case 'eo':
86 case 'es':
87 case 'et':
88 case 'eu':
89 case 'fa':
90 case 'fi':
91 case 'fo':
92 case 'fur':
93 case 'fy':
94 case 'gl':
95 case 'gu':
96 case 'ha':
97 case 'he':
98 case 'hu':
99 case 'is':
100 case 'it':
101 case 'ku':
102 case 'lb':
103 case 'ml':
104 case 'mn':
105 case 'mr':
106 case 'nah':
107 case 'nb':
108 case 'ne':
109 case 'nl':
110 case 'nn':
111 case 'no':
112 case 'om':
113 case 'or':
114 case 'pa':
115 case 'pap':
116 case 'ps':
117 case 'pt':
118 case 'so':
119 case 'sq':
120 case 'sv':
121 case 'sw':
122 case 'ta':
123 case 'te':
124 case 'tk':
125 case 'ur':
126 case 'zu':
127 return ($number == 1) ? 0 : 1;
128
129 case 'am':
130 case 'bh':
131 case 'fil':
132 case 'fr':
133 case 'gun':
134 case 'hi':
135 case 'ln':
136 case 'mg':
137 case 'nso':
138 case 'xbr':
139 case 'ti':
140 case 'wa':
141 return (($number == 0) || ($number == 1)) ? 0 : 1;
142
143 case 'be':
144 case 'bs':
145 case 'hr':
146 case 'ru':
147 case 'sr':
148 case 'uk':
149 return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
150
151 case 'cs':
152 case 'sk':
153 return ($number == 1) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2);
154
155 case 'ga':
156 return ($number == 1) ? 0 : (($number == 2) ? 1 : 2);
157
158 case 'lt':
159 return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
160
161 case 'sl':
162 return ($number % 100 == 1) ? 0 : (($number % 100 == 2) ? 1 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 2 : 3));
163
164 case 'mk':
165 return ($number % 10 == 1) ? 0 : 1;
166
167 case 'mt':
168 return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3));
169
170 case 'lv':
171 return ($number == 0) ? 0 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2);
172
173 case 'pl':
174 return ($number == 1) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2);
175
176 case 'cy':
177 return ($number == 1) ? 0 : (($number == 2) ? 1 : ((($number == 8) || ($number == 11)) ? 2 : 3));
178
179 case 'ro':
180 return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2);
181
182 case 'ar':
183 return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number >= 3) && ($number <= 10)) ? 3 : ((($number >= 11) && ($number <= 99)) ? 4 : 5))));
184
185 default:
186 return 0;
187 }
188 }
189
190 /**
191 * Overrides the default plural rule for a given locale.
192 *
193 * @param string $rule A PHP callable
194 * @param string $locale The locale
195 *
196 * @return null
197 *
198 * @throws \LogicException
199 */
200 public static function set($rule, $locale)
201 {
202 if ("pt_BR" == $locale) {
203 // temporary set a locale for brazilian
204 $locale = "xbr";
205 }
206
207 if (strlen($locale) > 3) {
208 $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
209 }
210
211 if (!is_callable($rule)) {
212 throw new \LogicException('The given rule can not be called');
213 }
214
215 self::$rules[$locale] = $rule;
216 }
217
218 // @codeCoverageIgnoreEnd
219}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/README.md b/vendor/symfony/translation/Symfony/Component/Translation/README.md
new file mode 100644
index 00000000..24e6210c
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/README.md
@@ -0,0 +1,35 @@
1Translation Component
2=====================
3
4Translation provides tools for loading translation files and generating
5translated strings from these including support for pluralization.
6
7 use Symfony\Component\Translation\Translator;
8 use Symfony\Component\Translation\MessageSelector;
9 use Symfony\Component\Translation\Loader\ArrayLoader;
10
11 $translator = new Translator('fr_FR', new MessageSelector());
12 $translator->setFallbackLocales(array('fr'));
13 $translator->addLoader('array', new ArrayLoader());
14 $translator->addResource('array', array(
15 'Hello World!' => 'Bonjour',
16 ), 'fr');
17
18 echo $translator->trans('Hello World!')."\n";
19
20Resources
21---------
22
23Silex integration:
24
25https://github.com/fabpot/Silex/blob/master/src/Silex/Provider/TranslationServiceProvider.php
26
27Documentation:
28
29http://symfony.com/doc/2.3/book/translation.html
30
31You can run the unit tests with the following command:
32
33 $ cd path/to/Symfony/Component/Translation/
34 $ composer.phar install --dev
35 $ phpunit
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTest.php
new file mode 100644
index 00000000..78023e1b
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTest.php
@@ -0,0 +1,74 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Test\Catalogue;
13
14use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
15use Symfony\Component\Translation\MessageCatalogue;
16use Symfony\Component\Translation\MessageCatalogueInterface;
17
18abstract class AbstractOperationTest extends TestCase
19{
20 public function testGetEmptyDomains()
21 {
22 $this->assertEquals(
23 array(),
24 $this->createOperation(
25 new MessageCatalogue('en'),
26 new MessageCatalogue('en')
27 )->getDomains()
28 );
29 }
30
31 public function testGetMergedDomains()
32 {
33 $this->assertEquals(
34 array('a', 'b', 'c'),
35 $this->createOperation(
36 new MessageCatalogue('en', array('a' => array(), 'b' => array())),
37 new MessageCatalogue('en', array('b' => array(), 'c' => array()))
38 )->getDomains()
39 );
40 }
41
42 public function testGetMessagesFromUnknownDomain()
43 {
44 $this->setExpectedException('InvalidArgumentException');
45 $this->createOperation(
46 new MessageCatalogue('en'),
47 new MessageCatalogue('en')
48 )->getMessages('domain');
49 }
50
51 public function testGetEmptyMessages()
52 {
53 $this->assertEquals(
54 array(),
55 $this->createOperation(
56 new MessageCatalogue('en', array('a' => array())),
57 new MessageCatalogue('en')
58 )->getMessages('a')
59 );
60 }
61
62 public function testGetEmptyResult()
63 {
64 $this->assertEquals(
65 new MessageCatalogue('en'),
66 $this->createOperation(
67 new MessageCatalogue('en'),
68 new MessageCatalogue('en')
69 )->getResult()
70 );
71 }
72
73 abstract protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target);
74}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/DiffOperationTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/DiffOperationTest.php
new file mode 100644
index 00000000..b2e852d9
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/DiffOperationTest.php
@@ -0,0 +1,60 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Test\Catalogue;
13
14use Symfony\Component\Translation\Catalogue\DiffOperation;
15use Symfony\Component\Translation\MessageCatalogue;
16use Symfony\Component\Translation\MessageCatalogueInterface;
17
18class DiffOperationTest extends AbstractOperationTest
19{
20 public function testGetMessagesFromSingleDomain()
21 {
22 $operation = $this->createOperation(
23 new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
24 new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
25 );
26
27 $this->assertEquals(
28 array('a' => 'old_a', 'c' => 'new_c'),
29 $operation->getMessages('messages')
30 );
31
32 $this->assertEquals(
33 array('c' => 'new_c'),
34 $operation->getNewMessages('messages')
35 );
36
37 $this->assertEquals(
38 array('b' => 'old_b'),
39 $operation->getObsoleteMessages('messages')
40 );
41 }
42
43 public function testGetResultFromSingleDomain()
44 {
45 $this->assertEquals(
46 new MessageCatalogue('en', array(
47 'messages' => array('a' => 'old_a', 'c' => 'new_c')
48 )),
49 $this->createOperation(
50 new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
51 new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
52 )->getResult()
53 );
54 }
55
56 protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
57 {
58 return new DiffOperation($source, $target);
59 }
60}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php
new file mode 100644
index 00000000..fa5118a7
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php
@@ -0,0 +1,60 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Test\Catalogue;
13
14use Symfony\Component\Translation\Catalogue\MergeOperation;
15use Symfony\Component\Translation\MessageCatalogue;
16use Symfony\Component\Translation\MessageCatalogueInterface;
17
18class MergeOperationTest extends AbstractOperationTest
19{
20 public function testGetMessagesFromSingleDomain()
21 {
22 $operation = $this->createOperation(
23 new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
24 new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
25 );
26
27 $this->assertEquals(
28 array('a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c'),
29 $operation->getMessages('messages')
30 );
31
32 $this->assertEquals(
33 array('c' => 'new_c'),
34 $operation->getNewMessages('messages')
35 );
36
37 $this->assertEquals(
38 array(),
39 $operation->getObsoleteMessages('messages')
40 );
41 }
42
43 public function testGetResultFromSingleDomain()
44 {
45 $this->assertEquals(
46 new MessageCatalogue('en', array(
47 'messages' => array('a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c')
48 )),
49 $this->createOperation(
50 new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
51 new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
52 )->getResult()
53 );
54 }
55
56 protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
57 {
58 return new MergeOperation($source, $target);
59 }
60}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/CsvFileDumperTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/CsvFileDumperTest.php
new file mode 100644
index 00000000..29177ff5
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/CsvFileDumperTest.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\CsvFileDumper;
16
17class CsvFileDumperTest extends \PHPUnit_Framework_TestCase
18{
19 public function testDump()
20 {
21 $catalogue = new MessageCatalogue('en');
22 $catalogue->add(array('foo' => 'bar', 'bar' => 'foo
23foo', 'foo;foo' => 'bar'));
24
25 $tempDir = sys_get_temp_dir();
26 $dumper = new CsvFileDumper();
27 $dumper->dump($catalogue, array('path' => $tempDir));
28
29 $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/valid.csv'), file_get_contents($tempDir.'/messages.en.csv'));
30
31 unlink($tempDir.'/messages.en.csv');
32 }
33}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/IcuResFileDumperTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/IcuResFileDumperTest.php
new file mode 100644
index 00000000..d187ef1d
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/IcuResFileDumperTest.php
@@ -0,0 +1,37 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\IcuResFileDumper;
16
17class IcuResFileDumperTest extends \PHPUnit_Framework_TestCase
18{
19 public function testDump()
20 {
21 if (!extension_loaded('mbstring')) {
22 $this->markTestSkipped('This test requires mbstring to work.');
23 }
24
25 $catalogue = new MessageCatalogue('en');
26 $catalogue->add(array('foo' => 'bar'));
27
28 $tempDir = sys_get_temp_dir();
29 $dumper = new IcuResFileDumper();
30 $dumper->dump($catalogue, array('path' => $tempDir));
31
32 $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resourcebundle/res/en.res'), file_get_contents($tempDir.'/messages/en.res'));
33
34 unlink($tempDir.'/messages/en.res');
35 rmdir($tempDir.'/messages');
36 }
37}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/IniFileDumperTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/IniFileDumperTest.php
new file mode 100644
index 00000000..2a2cefde
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/IniFileDumperTest.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\IniFileDumper;
16
17class IniFileDumperTest extends \PHPUnit_Framework_TestCase
18{
19 public function testDump()
20 {
21 $catalogue = new MessageCatalogue('en');
22 $catalogue->add(array('foo' => 'bar'));
23
24 $tempDir = sys_get_temp_dir();
25 $dumper = new IniFileDumper();
26 $dumper->dump($catalogue, array('path' => $tempDir));
27
28 $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.ini'), file_get_contents($tempDir.'/messages.en.ini'));
29
30 unlink($tempDir.'/messages.en.ini');
31 }
32}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/MoFileDumperTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/MoFileDumperTest.php
new file mode 100644
index 00000000..439a25cd
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/MoFileDumperTest.php
@@ -0,0 +1,31 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\MoFileDumper;
16
17class MoFileDumperTest extends \PHPUnit_Framework_TestCase
18{
19 public function testDump()
20 {
21 $catalogue = new MessageCatalogue('en');
22 $catalogue->add(array('foo' => 'bar'));
23
24 $tempDir = sys_get_temp_dir();
25 $dumper = new MoFileDumper();
26 $dumper->dump($catalogue, array('path' => $tempDir));
27 $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.mo'), file_get_contents($tempDir.'/messages.en.mo'));
28
29 unlink($tempDir.'/messages.en.mo');
30 }
31}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/PhpFileDumperTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/PhpFileDumperTest.php
new file mode 100644
index 00000000..18be5a0d
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/PhpFileDumperTest.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\PhpFileDumper;
16
17class PhpFileDumperTest extends \PHPUnit_Framework_TestCase
18{
19 public function testDump()
20 {
21 $catalogue = new MessageCatalogue('en');
22 $catalogue->add(array('foo' => 'bar'));
23
24 $tempDir = sys_get_temp_dir();
25 $dumper = new PhpFileDumper();
26 $dumper->dump($catalogue, array('path' => $tempDir));
27
28 $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.php'), file_get_contents($tempDir.'/messages.en.php'));
29
30 unlink($tempDir.'/messages.en.php');
31 }
32}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/PoFileDumperTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/PoFileDumperTest.php
new file mode 100644
index 00000000..0296d6b2
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/PoFileDumperTest.php
@@ -0,0 +1,31 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\PoFileDumper;
16
17class PoFileDumperTest extends \PHPUnit_Framework_TestCase
18{
19 public function testDump()
20 {
21 $catalogue = new MessageCatalogue('en');
22 $catalogue->add(array('foo' => 'bar'));
23
24 $tempDir = sys_get_temp_dir();
25 $dumper = new PoFileDumper();
26 $dumper->dump($catalogue, array('path' => $tempDir));
27 $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.po'), file_get_contents($tempDir.'/messages.en.po'));
28
29 unlink($tempDir.'/messages.en.po');
30 }
31}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/QtFileDumperTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/QtFileDumperTest.php
new file mode 100644
index 00000000..d7d8fb7e
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/QtFileDumperTest.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\QtFileDumper;
16
17class QtFileDumperTest extends \PHPUnit_Framework_TestCase
18{
19 public function testDump()
20 {
21 $catalogue = new MessageCatalogue('en');
22 $catalogue->add(array('foo' => 'bar'), 'resources');
23
24 $tempDir = sys_get_temp_dir();
25 $dumper = new QtFileDumper();
26 $dumper->dump($catalogue, array('path' => $tempDir));
27
28 $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.ts'), file_get_contents($tempDir.'/resources.en.ts'));
29
30 unlink($tempDir.'/resources.en.ts');
31 }
32}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php
new file mode 100644
index 00000000..bef31358
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\XliffFileDumper;
16
17class XliffFileDumperTest extends \PHPUnit_Framework_TestCase
18{
19 public function testDump()
20 {
21 $catalogue = new MessageCatalogue('en');
22 $catalogue->add(array('foo' => 'bar', 'key' => ''));
23
24 $tempDir = sys_get_temp_dir();
25 $dumper = new XliffFileDumper();
26 $dumper->dump($catalogue, array('path' => $tempDir));
27
28 $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources-clean.xlf'), file_get_contents($tempDir.'/messages.en.xlf'));
29
30 unlink($tempDir.'/messages.en.xlf');
31 }
32}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/YamlFileDumperTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/YamlFileDumperTest.php
new file mode 100644
index 00000000..e4e68e02
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Dumper/YamlFileDumperTest.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\YamlFileDumper;
16
17class YamlFileDumperTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Yaml\Yaml')) {
22 $this->markTestSkipped('The "Yaml" component is not available');
23 }
24 }
25
26 public function testDump()
27 {
28 $catalogue = new MessageCatalogue('en');
29 $catalogue->add(array('foo' => 'bar'));
30
31 $tempDir = sys_get_temp_dir();
32 $dumper = new YamlFileDumper();
33 $dumper->dump($catalogue, array('path' => $tempDir));
34
35 $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.yml'), file_get_contents($tempDir.'/messages.en.yml'));
36
37 unlink($tempDir.'/messages.en.yml');
38 }
39}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php
new file mode 100644
index 00000000..435f0c28
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests;
13
14use Symfony\Component\Translation\IdentityTranslator;
15use Symfony\Component\Translation\MessageSelector;
16
17class IdentityTranslatorTest extends \PHPUnit_Framework_TestCase
18{
19 /**
20 * @dataProvider getTransTests
21 */
22 public function testTrans($expected, $id, $parameters)
23 {
24 $translator = new IdentityTranslator(new MessageSelector());
25
26 $this->assertEquals($expected, $translator->trans($id, $parameters));
27 }
28
29 /**
30 * @dataProvider getTransChoiceTests
31 */
32 public function testTransChoice($expected, $id, $number, $parameters)
33 {
34 $translator = new IdentityTranslator(new MessageSelector());
35
36 $this->assertEquals($expected, $translator->transChoice($id, $number, $parameters));
37 }
38
39 // noop
40 public function testGetSetLocale()
41 {
42 $translator = new IdentityTranslator(new MessageSelector());
43 $translator->setLocale('en');
44 $translator->getLocale();
45 }
46
47 public function getTransTests()
48 {
49 return array(
50 array('Symfony2 is great!', 'Symfony2 is great!', array()),
51 array('Symfony2 is awesome!', 'Symfony2 is %what%!', array('%what%' => 'awesome')),
52 );
53 }
54
55 public function getTransChoiceTests()
56 {
57 return array(
58 array('There is 10 apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 10, array('%count%' => 10)),
59 );
60 }
61}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/IntervalTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/IntervalTest.php
new file mode 100644
index 00000000..075c98b7
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/IntervalTest.php
@@ -0,0 +1,48 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests;
13
14use Symfony\Component\Translation\Interval;
15
16class IntervalTest extends \PHPUnit_Framework_TestCase
17{
18 /**
19 * @dataProvider getTests
20 */
21 public function testTest($expected, $number, $interval)
22 {
23 $this->assertEquals($expected, Interval::test($number, $interval));
24 }
25
26 /**
27 * @expectedException \InvalidArgumentException
28 */
29 public function testTestException()
30 {
31 Interval::test(1, 'foobar');
32 }
33
34 public function getTests()
35 {
36 return array(
37 array(true, 3, '{1,2, 3 ,4}'),
38 array(false, 10, '{1,2, 3 ,4}'),
39 array(false, 3, '[1,2]'),
40 array(true, 1, '[1,2]'),
41 array(true, 2, '[1,2]'),
42 array(false, 1, ']1,2['),
43 array(false, 2, ']1,2['),
44 array(true, log(0), '[-Inf,2['),
45 array(true, -log(0), '[-2,+Inf]'),
46 );
47 }
48}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/CsvFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/CsvFileLoaderTest.php
new file mode 100644
index 00000000..59569a3d
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/CsvFileLoaderTest.php
@@ -0,0 +1,67 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\CsvFileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16
17class CsvFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24 }
25
26 public function testLoad()
27 {
28 $loader = new CsvFileLoader();
29 $resource = __DIR__.'/../fixtures/resources.csv';
30 $catalogue = $loader->load($resource, 'en', 'domain1');
31
32 $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
33 $this->assertEquals('en', $catalogue->getLocale());
34 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
35 }
36
37 public function testLoadDoesNothingIfEmpty()
38 {
39 $loader = new CsvFileLoader();
40 $resource = __DIR__.'/../fixtures/empty.csv';
41 $catalogue = $loader->load($resource, 'en', 'domain1');
42
43 $this->assertEquals(array(), $catalogue->all('domain1'));
44 $this->assertEquals('en', $catalogue->getLocale());
45 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
46 }
47
48 /**
49 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
50 */
51 public function testLoadNonExistingResource()
52 {
53 $loader = new CsvFileLoader();
54 $resource = __DIR__.'/../fixtures/not-exists.csv';
55 $loader->load($resource, 'en', 'domain1');
56 }
57
58 /**
59 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
60 */
61 public function testLoadNonLocalResource()
62 {
63 $loader = new CsvFileLoader();
64 $resource = 'http://example.com/resources.csv';
65 $loader->load($resource, 'en', 'domain1');
66 }
67}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IcuDatFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IcuDatFileLoaderTest.php
new file mode 100644
index 00000000..a3bd67ab
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IcuDatFileLoaderTest.php
@@ -0,0 +1,72 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\IcuDatFileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16
17class IcuDatFileLoaderTest extends LocalizedTestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24
25 if (!extension_loaded('intl')) {
26 $this->markTestSkipped('This test requires intl extension to work.');
27 }
28 }
29
30 /**
31 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
32 */
33 public function testLoadInvalidResource()
34 {
35 $loader = new IcuDatFileLoader();
36 $loader->load(__DIR__.'/../fixtures/resourcebundle/corrupted/resources', 'es', 'domain2');
37 }
38
39 public function testDatEnglishLoad()
40 {
41 // bundled resource is build using pkgdata command which at least in ICU 4.2 comes in extremely! buggy form
42 // you must specify an temporary build directory which is not the same as current directory and
43 // MUST reside on the same partition. pkgdata -p resources -T /srv -d.packagelist.txt
44 $loader = new IcuDatFileLoader();
45 $resource = __DIR__.'/../fixtures/resourcebundle/dat/resources';
46 $catalogue = $loader->load($resource, 'en', 'domain1');
47
48 $this->assertEquals(array('symfony' => 'Symfony 2 is great'), $catalogue->all('domain1'));
49 $this->assertEquals('en', $catalogue->getLocale());
50 $this->assertEquals(array(new FileResource($resource.'.dat')), $catalogue->getResources());
51 }
52
53 public function testDatFrenchLoad()
54 {
55 $loader = new IcuDatFileLoader();
56 $resource = __DIR__.'/../fixtures/resourcebundle/dat/resources';
57 $catalogue = $loader->load($resource, 'fr', 'domain1');
58
59 $this->assertEquals(array('symfony' => 'Symfony 2 est génial'), $catalogue->all('domain1'));
60 $this->assertEquals('fr', $catalogue->getLocale());
61 $this->assertEquals(array(new FileResource($resource.'.dat')), $catalogue->getResources());
62 }
63
64 /**
65 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
66 */
67 public function testLoadNonExistingResource()
68 {
69 $loader = new IcuDatFileLoader();
70 $loader->load(__DIR__.'/../fixtures/non-existing.txt', 'en', 'domain1');
71 }
72}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IcuResFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IcuResFileLoaderTest.php
new file mode 100644
index 00000000..233e1897
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IcuResFileLoaderTest.php
@@ -0,0 +1,59 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\IcuResFileLoader;
15use Symfony\Component\Config\Resource\DirectoryResource;
16
17class IcuResFileLoaderTest extends LocalizedTestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24
25 if (!extension_loaded('intl')) {
26 $this->markTestSkipped('This test requires intl extension to work.');
27 }
28 }
29
30 public function testLoad()
31 {
32 // resource is build using genrb command
33 $loader = new IcuResFileLoader();
34 $resource = __DIR__.'/../fixtures/resourcebundle/res';
35 $catalogue = $loader->load($resource, 'en', 'domain1');
36
37 $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
38 $this->assertEquals('en', $catalogue->getLocale());
39 $this->assertEquals(array(new DirectoryResource($resource)), $catalogue->getResources());
40 }
41
42 /**
43 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
44 */
45 public function testLoadNonExistingResource()
46 {
47 $loader = new IcuResFileLoader();
48 $loader->load(__DIR__.'/../fixtures/non-existing.txt', 'en', 'domain1');
49 }
50
51 /**
52 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
53 */
54 public function testLoadInvalidResource()
55 {
56 $loader = new IcuResFileLoader();
57 $loader->load(__DIR__.'/../fixtures/resourcebundle/corrupted', 'en', 'domain1');
58 }
59}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IniFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IniFileLoaderTest.php
new file mode 100644
index 00000000..ae1289d0
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/IniFileLoaderTest.php
@@ -0,0 +1,57 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\IniFileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16
17class IniFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24 }
25
26 public function testLoad()
27 {
28 $loader = new IniFileLoader();
29 $resource = __DIR__.'/../fixtures/resources.ini';
30 $catalogue = $loader->load($resource, 'en', 'domain1');
31
32 $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
33 $this->assertEquals('en', $catalogue->getLocale());
34 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
35 }
36
37 public function testLoadDoesNothingIfEmpty()
38 {
39 $loader = new IniFileLoader();
40 $resource = __DIR__.'/../fixtures/empty.ini';
41 $catalogue = $loader->load($resource, 'en', 'domain1');
42
43 $this->assertEquals(array(), $catalogue->all('domain1'));
44 $this->assertEquals('en', $catalogue->getLocale());
45 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
46 }
47
48 /**
49 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
50 */
51 public function testLoadNonExistingResource()
52 {
53 $loader = new IniFileLoader();
54 $resource = __DIR__.'/../fixtures/non-existing.ini';
55 $loader->load($resource, 'en', 'domain1');
56 }
57}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/LocalizedTestCase.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/LocalizedTestCase.php
new file mode 100644
index 00000000..9d7c5d70
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/LocalizedTestCase.php
@@ -0,0 +1,22 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14abstract class LocalizedTestCase extends \PHPUnit_Framework_TestCase
15{
16 protected function setUp()
17 {
18 if (!extension_loaded('intl')) {
19 $this->markTestSkipped('The "intl" extension is not available');
20 }
21 }
22}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/MoFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/MoFileLoaderTest.php
new file mode 100644
index 00000000..c2616bda
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/MoFileLoaderTest.php
@@ -0,0 +1,67 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\MoFileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16
17class MoFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24 }
25
26 public function testLoad()
27 {
28 $loader = new MoFileLoader();
29 $resource = __DIR__.'/../fixtures/resources.mo';
30 $catalogue = $loader->load($resource, 'en', 'domain1');
31
32 $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
33 $this->assertEquals('en', $catalogue->getLocale());
34 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
35 }
36
37 public function testLoadPlurals()
38 {
39 $loader = new MoFileLoader();
40 $resource = __DIR__.'/../fixtures/plurals.mo';
41 $catalogue = $loader->load($resource, 'en', 'domain1');
42
43 $this->assertEquals(array('foo' => 'bar', 'foos' => '{0} bar|{1} bars'), $catalogue->all('domain1'));
44 $this->assertEquals('en', $catalogue->getLocale());
45 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
46 }
47
48 /**
49 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
50 */
51 public function testLoadNonExistingResource()
52 {
53 $loader = new MoFileLoader();
54 $resource = __DIR__.'/../fixtures/non-existing.mo';
55 $loader->load($resource, 'en', 'domain1');
56 }
57
58 /**
59 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
60 */
61 public function testLoadInvalidResource()
62 {
63 $loader = new MoFileLoader();
64 $resource = __DIR__.'/../fixtures/empty.mo';
65 $loader->load($resource, 'en', 'domain1');
66 }
67}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/PhpFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/PhpFileLoaderTest.php
new file mode 100644
index 00000000..5dfe837d
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/PhpFileLoaderTest.php
@@ -0,0 +1,56 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\PhpFileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16
17class PhpFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24 }
25
26 public function testLoad()
27 {
28 $loader = new PhpFileLoader();
29 $resource = __DIR__.'/../fixtures/resources.php';
30 $catalogue = $loader->load($resource, 'en', 'domain1');
31
32 $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
33 $this->assertEquals('en', $catalogue->getLocale());
34 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
35 }
36
37 /**
38 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
39 */
40 public function testLoadNonExistingResource()
41 {
42 $loader = new PhpFileLoader();
43 $resource = __DIR__.'/../fixtures/non-existing.php';
44 $loader->load($resource, 'en', 'domain1');
45 }
46
47 /**
48 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
49 */
50 public function testLoadThrowsAnExceptionIfFileNotLocal()
51 {
52 $loader = new PhpFileLoader();
53 $resource = 'http://example.com/resources.php';
54 $loader->load($resource, 'en', 'domain1');
55 }
56}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/PoFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/PoFileLoaderTest.php
new file mode 100644
index 00000000..cd3d85a1
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/PoFileLoaderTest.php
@@ -0,0 +1,79 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\PoFileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16
17class PoFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24 }
25
26 public function testLoad()
27 {
28 $loader = new PoFileLoader();
29 $resource = __DIR__.'/../fixtures/resources.po';
30 $catalogue = $loader->load($resource, 'en', 'domain1');
31
32 $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
33 $this->assertEquals('en', $catalogue->getLocale());
34 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
35 }
36
37 public function testLoadPlurals()
38 {
39 $loader = new PoFileLoader();
40 $resource = __DIR__.'/../fixtures/plurals.po';
41 $catalogue = $loader->load($resource, 'en', 'domain1');
42
43 $this->assertEquals(array('foo' => 'bar', 'foos' => 'bar|bars'), $catalogue->all('domain1'));
44 $this->assertEquals('en', $catalogue->getLocale());
45 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
46 }
47
48 public function testLoadDoesNothingIfEmpty()
49 {
50 $loader = new PoFileLoader();
51 $resource = __DIR__.'/../fixtures/empty.po';
52 $catalogue = $loader->load($resource, 'en', 'domain1');
53
54 $this->assertEquals(array(), $catalogue->all('domain1'));
55 $this->assertEquals('en', $catalogue->getLocale());
56 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
57 }
58
59 /**
60 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
61 */
62 public function testLoadNonExistingResource()
63 {
64 $loader = new PoFileLoader();
65 $resource = __DIR__.'/../fixtures/non-existing.po';
66 $loader->load($resource, 'en', 'domain1');
67 }
68
69 public function testLoadEmptyTranslation()
70 {
71 $loader = new PoFileLoader();
72 $resource = __DIR__.'/../fixtures/empty-translation.po';
73 $catalogue = $loader->load($resource, 'en', 'domain1');
74
75 $this->assertEquals(array('foo' => ''), $catalogue->all('domain1'));
76 $this->assertEquals('en', $catalogue->getLocale());
77 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
78 }
79}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/QtFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/QtFileLoaderTest.php
new file mode 100644
index 00000000..c1dd7b10
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/QtFileLoaderTest.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\QtFileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16
17class QtFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24 }
25
26 public function testLoad()
27 {
28 $loader = new QtFileLoader();
29 $resource = __DIR__.'/../fixtures/resources.ts';
30 $catalogue = $loader->load($resource, 'en', 'resources');
31
32 $this->assertEquals(array('foo' => 'bar'), $catalogue->all('resources'));
33 $this->assertEquals('en', $catalogue->getLocale());
34 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
35 }
36
37 /**
38 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
39 */
40 public function testLoadNonExistingResource()
41 {
42 $loader = new QtFileLoader();
43 $resource = __DIR__.'/../fixtures/non-existing.ts';
44 $loader->load($resource, 'en', 'domain1');
45 }
46
47 /**
48 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
49 */
50 public function testLoadNonLocalResource()
51 {
52 $loader = new QtFileLoader();
53 $resource = 'http://domain1.com/resources.ts';
54 $loader->load($resource, 'en', 'domain1');
55 }
56
57 /**
58 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
59 */
60 public function testLoadInvalidResource()
61 {
62 $loader = new QtFileLoader();
63 $resource = __DIR__.'/../fixtures/invalid-xml-resources.xlf';
64 $loader->load($resource, 'en', 'domain1');
65 }
66}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php
new file mode 100644
index 00000000..1d58e0ee
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php
@@ -0,0 +1,113 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\XliffFileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16
17class XliffFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24 }
25
26 public function testLoad()
27 {
28 $loader = new XliffFileLoader();
29 $resource = __DIR__.'/../fixtures/resources.xlf';
30 $catalogue = $loader->load($resource, 'en', 'domain1');
31
32 $this->assertEquals('en', $catalogue->getLocale());
33 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
34 }
35
36 public function testLoadWithResname()
37 {
38 $loader = new XliffFileLoader();
39 $catalogue = $loader->load(__DIR__.'/../fixtures/resname.xlf', 'en', 'domain1');
40
41 $this->assertEquals(array('foo' => 'bar', 'bar' => 'baz', 'baz' => 'foo'), $catalogue->all('domain1'));
42 }
43
44 public function testIncompleteResource()
45 {
46 $loader = new XliffFileLoader();
47 $catalogue = $loader->load(__DIR__.'/../fixtures/resources.xlf', 'en', 'domain1');
48
49 $this->assertEquals(array('foo' => 'bar', 'key' => '', 'test' => 'with'), $catalogue->all('domain1'));
50 $this->assertFalse($catalogue->has('extra', 'domain1'));
51 }
52
53 public function testEncoding()
54 {
55 if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
56 $this->markTestSkipped('The iconv and mbstring extensions are not available.');
57 }
58
59 $loader = new XliffFileLoader();
60 $catalogue = $loader->load(__DIR__.'/../fixtures/encoding.xlf', 'en', 'domain1');
61
62 $this->assertEquals(utf8_decode('föö'), $catalogue->get('bar', 'domain1'));
63 $this->assertEquals(utf8_decode('bär'), $catalogue->get('foo', 'domain1'));
64 }
65
66 /**
67 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
68 */
69 public function testLoadInvalidResource()
70 {
71 $loader = new XliffFileLoader();
72 $loader->load(__DIR__.'/../fixtures/resources.php', 'en', 'domain1');
73 }
74
75 /**
76 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
77 */
78 public function testLoadResourceDoesNotValidate()
79 {
80 $loader = new XliffFileLoader();
81 $loader->load(__DIR__.'/../fixtures/non-valid.xlf', 'en', 'domain1');
82 }
83
84 /**
85 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
86 */
87 public function testLoadNonExistingResource()
88 {
89 $loader = new XliffFileLoader();
90 $resource = __DIR__.'/../fixtures/non-existing.xlf';
91 $loader->load($resource, 'en', 'domain1');
92 }
93
94 /**
95 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
96 */
97 public function testLoadThrowsAnExceptionIfFileNotLocal()
98 {
99 $loader = new XliffFileLoader();
100 $resource = 'http://example.com/resources.xlf';
101 $loader->load($resource, 'en', 'domain1');
102 }
103
104 /**
105 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
106 * @expectedExceptionMessage Document types are not allowed.
107 */
108 public function testDocTypeIsNotAllowed()
109 {
110 $loader = new XliffFileLoader();
111 $loader->load(__DIR__.'/../fixtures/withdoctype.xlf', 'en', 'domain1');
112 }
113}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/YamlFileLoaderTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/YamlFileLoaderTest.php
new file mode 100644
index 00000000..511b1279
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/Loader/YamlFileLoaderTest.php
@@ -0,0 +1,81 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests\Loader;
13
14use Symfony\Component\Translation\Loader\YamlFileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16
17class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24
25 if (!class_exists('Symfony\Component\Yaml\Yaml')) {
26 $this->markTestSkipped('The "Yaml" component is not available');
27 }
28 }
29
30 public function testLoad()
31 {
32 $loader = new YamlFileLoader();
33 $resource = __DIR__.'/../fixtures/resources.yml';
34 $catalogue = $loader->load($resource, 'en', 'domain1');
35
36 $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
37 $this->assertEquals('en', $catalogue->getLocale());
38 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
39 }
40
41 public function testLoadDoesNothingIfEmpty()
42 {
43 $loader = new YamlFileLoader();
44 $resource = __DIR__.'/../fixtures/empty.yml';
45 $catalogue = $loader->load($resource, 'en', 'domain1');
46
47 $this->assertEquals(array(), $catalogue->all('domain1'));
48 $this->assertEquals('en', $catalogue->getLocale());
49 $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
50 }
51
52 /**
53 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
54 */
55 public function testLoadNonExistingResource()
56 {
57 $loader = new YamlFileLoader();
58 $resource = __DIR__.'/../fixtures/non-existing.yml';
59 $loader->load($resource, 'en', 'domain1');
60 }
61
62 /**
63 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
64 */
65 public function testLoadThrowsAnExceptionIfFileNotLocal()
66 {
67 $loader = new YamlFileLoader();
68 $resource = 'http://example.com/resources.yml';
69 $loader->load($resource, 'en', 'domain1');
70 }
71
72 /**
73 * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
74 */
75 public function testLoadThrowsAnExceptionIfNotAnArray()
76 {
77 $loader = new YamlFileLoader();
78 $resource = __DIR__.'/../fixtures/non-valid.yml';
79 $loader->load($resource, 'en', 'domain1');
80 }
81}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/MessageCatalogueTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/MessageCatalogueTest.php
new file mode 100644
index 00000000..aa6f8707
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/MessageCatalogueTest.php
@@ -0,0 +1,212 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16class MessageCatalogueTest extends \PHPUnit_Framework_TestCase
17{
18 public function testGetLocale()
19 {
20 $catalogue = new MessageCatalogue('en');
21
22 $this->assertEquals('en', $catalogue->getLocale());
23 }
24
25 public function testGetDomains()
26 {
27 $catalogue = new MessageCatalogue('en', array('domain1' => array(), 'domain2' => array()));
28
29 $this->assertEquals(array('domain1', 'domain2'), $catalogue->getDomains());
30 }
31
32 public function testAll()
33 {
34 $catalogue = new MessageCatalogue('en', $messages = array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
35
36 $this->assertEquals(array('foo' => 'foo'), $catalogue->all('domain1'));
37 $this->assertEquals(array(), $catalogue->all('domain88'));
38 $this->assertEquals($messages, $catalogue->all());
39 }
40
41 public function testHas()
42 {
43 $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
44
45 $this->assertTrue($catalogue->has('foo', 'domain1'));
46 $this->assertFalse($catalogue->has('bar', 'domain1'));
47 $this->assertFalse($catalogue->has('foo', 'domain88'));
48 }
49
50 public function testGetSet()
51 {
52 $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
53 $catalogue->set('foo1', 'foo1', 'domain1');
54
55 $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
56 $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
57 }
58
59 public function testAdd()
60 {
61 $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
62 $catalogue->add(array('foo1' => 'foo1'), 'domain1');
63
64 $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
65 $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
66
67 $catalogue->add(array('foo' => 'bar'), 'domain1');
68 $this->assertEquals('bar', $catalogue->get('foo', 'domain1'));
69 $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
70
71 $catalogue->add(array('foo' => 'bar'), 'domain88');
72 $this->assertEquals('bar', $catalogue->get('foo', 'domain88'));
73 }
74
75 public function testReplace()
76 {
77 $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
78 $catalogue->replace($messages = array('foo1' => 'foo1'), 'domain1');
79
80 $this->assertEquals($messages, $catalogue->all('domain1'));
81 }
82
83 public function testAddCatalogue()
84 {
85 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
86 $this->markTestSkipped('The "Config" component is not available');
87 }
88
89 $r = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
90 $r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
91
92 $r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
93 $r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
94
95 $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
96 $catalogue->addResource($r);
97
98 $catalogue1 = new MessageCatalogue('en', array('domain1' => array('foo1' => 'foo1')));
99 $catalogue1->addResource($r1);
100
101 $catalogue->addCatalogue($catalogue1);
102
103 $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
104 $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
105
106 $this->assertEquals(array($r, $r1), $catalogue->getResources());
107 }
108
109 public function testAddFallbackCatalogue()
110 {
111 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
112 $this->markTestSkipped('The "Config" component is not available');
113 }
114
115 $r = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
116 $r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
117
118 $r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
119 $r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
120
121 $catalogue = new MessageCatalogue('en_US', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
122 $catalogue->addResource($r);
123
124 $catalogue1 = new MessageCatalogue('en', array('domain1' => array('foo' => 'bar', 'foo1' => 'foo1')));
125 $catalogue1->addResource($r1);
126
127 $catalogue->addFallbackCatalogue($catalogue1);
128
129 $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
130 $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
131
132 $this->assertEquals(array($r, $r1), $catalogue->getResources());
133 }
134
135 /**
136 * @expectedException LogicException
137 */
138 public function testAddFallbackCatalogueWithCircularReference()
139 {
140 $main = new MessageCatalogue('en_US');
141 $fallback = new MessageCatalogue('fr_FR');
142
143 $fallback->addFallbackCatalogue($main);
144 $main->addFallbackCatalogue($fallback);
145 }
146
147 /**
148 * @expectedException LogicException
149 */
150 public function testAddCatalogueWhenLocaleIsNotTheSameAsTheCurrentOne()
151 {
152 $catalogue = new MessageCatalogue('en');
153 $catalogue->addCatalogue(new MessageCatalogue('fr', array()));
154 }
155
156 public function testGetAddResource()
157 {
158 if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
159 $this->markTestSkipped('The "Config" component is not available');
160 }
161
162 $catalogue = new MessageCatalogue('en');
163 $r = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
164 $r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
165 $catalogue->addResource($r);
166 $catalogue->addResource($r);
167 $r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
168 $r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
169 $catalogue->addResource($r1);
170
171 $this->assertEquals(array($r, $r1), $catalogue->getResources());
172 }
173
174 public function testMetadataDelete()
175 {
176 $catalogue = new MessageCatalogue('en');
177 $this->assertEquals(array(), $catalogue->getMetadata('', ''), 'Metadata is empty');
178 $catalogue->deleteMetadata('key', 'messages');
179 $catalogue->deleteMetadata('', 'messages');
180 $catalogue->deleteMetadata();
181 }
182
183 public function testMetadataSetGetDelete()
184 {
185 $catalogue = new MessageCatalogue('en');
186 $catalogue->setMetadata('key', 'value');
187 $this->assertEquals('value', $catalogue->getMetadata('key', 'messages'), "Metadata 'key' = 'value'");
188
189 $catalogue->setMetadata('key2', array());
190 $this->assertEquals(array(), $catalogue->getMetadata('key2', 'messages'), 'Metadata key2 is array');
191
192 $catalogue->deleteMetadata('key2', 'messages');
193 $this->assertEquals(null, $catalogue->getMetadata('key2', 'messages'), 'Metadata key2 should is deleted.');
194
195 $catalogue->deleteMetadata('key2', 'domain');
196 $this->assertEquals(null, $catalogue->getMetadata('key2', 'domain'), 'Metadata key2 should is deleted.');
197 }
198
199 public function testMetadataMerge()
200 {
201 $cat1 = new MessageCatalogue('en');
202 $cat1->setMetadata('a', 'b');
203 $this->assertEquals(array('messages' => array('a' => 'b')), $cat1->getMetadata('', ''), 'Cat1 contains messages metadata.');
204
205 $cat2 = new MessageCatalogue('en');
206 $cat2->setMetadata('b', 'c', 'domain');
207 $this->assertEquals(array('domain' => array('b' => 'c')), $cat2->getMetadata('', ''), 'Cat2 contains domain metadata.');
208
209 $cat1->addCatalogue($cat2);
210 $this->assertEquals(array('messages' => array('a' => 'b'), 'domain' => array('b' => 'c')), $cat1->getMetadata('', ''), 'Cat1 contains merged metadata.');
211 }
212}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/MessageSelectorTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/MessageSelectorTest.php
new file mode 100644
index 00000000..74956294
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/MessageSelectorTest.php
@@ -0,0 +1,80 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests;
13
14use Symfony\Component\Translation\MessageSelector;
15
16class MessageSelectorTest extends \PHPUnit_Framework_TestCase
17{
18 /**
19 * @dataProvider getChooseTests
20 */
21 public function testChoose($expected, $id, $number)
22 {
23 $selector = new MessageSelector();
24
25 $this->assertEquals($expected, $selector->choose($id, $number, 'en'));
26 }
27
28 /**
29 * @expectedException InvalidArgumentException
30 */
31 public function testChooseWhenNoEnoughChoices()
32 {
33 $selector = new MessageSelector();
34
35 $selector->choose('foo', 10, 'en');
36 }
37
38 public function getChooseTests()
39 {
40 return array(
41 array('There is no apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 0),
42 array('There is no apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 0),
43 array('There is no apples', '{0}There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 0),
44
45 array('There is one apple', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 1),
46
47 array('There is %count% apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 10),
48 array('There is %count% apples', '{0} There is no apples|{1} There is one apple|]1,Inf]There is %count% apples', 10),
49 array('There is %count% apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 10),
50
51 array('There is %count% apples', 'There is one apple|There is %count% apples', 0),
52 array('There is one apple', 'There is one apple|There is %count% apples', 1),
53 array('There is %count% apples', 'There is one apple|There is %count% apples', 10),
54
55 array('There is %count% apples', 'one: There is one apple|more: There is %count% apples', 0),
56 array('There is one apple', 'one: There is one apple|more: There is %count% apples', 1),
57 array('There is %count% apples', 'one: There is one apple|more: There is %count% apples', 10),
58
59 array('There is no apples', '{0} There is no apples|one: There is one apple|more: There is %count% apples', 0),
60 array('There is one apple', '{0} There is no apples|one: There is one apple|more: There is %count% apples', 1),
61 array('There is %count% apples', '{0} There is no apples|one: There is one apple|more: There is %count% apples', 10),
62
63 array('', '{0}|{1} There is one apple|]1,Inf] There is %count% apples', 0),
64 array('', '{0} There is no apples|{1}|]1,Inf] There is %count% apples', 1),
65
66 // Indexed only tests which are Gettext PoFile* compatible strings.
67 array('There are %count% apples', 'There is one apple|There are %count% apples', 0),
68 array('There is one apple', 'There is one apple|There are %count% apples', 1),
69 array('There are %count% apples', 'There is one apple|There are %count% apples', 2),
70
71 // Tests for float numbers
72 array('There is almost one apple', '{0} There is no apples|]0,1[ There is almost one apple|{1} There is one apple|[1,Inf] There is more than one apple', 0.7),
73 array('There is one apple', '{0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1),
74 array('There is more than one apple', '{0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1.7),
75 array('There is no apples', '{0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0),
76 array('There is no apples', '{0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0.0),
77 array('There is no apples', '{0.0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0),
78 );
79 }
80}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/PluralizationRulesTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/PluralizationRulesTest.php
new file mode 100644
index 00000000..26f9e2f9
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/PluralizationRulesTest.php
@@ -0,0 +1,124 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests;
13
14use Symfony\Component\Translation\PluralizationRules;
15
16/**
17 * Test should cover all languages mentioned on http://translate.sourceforge.net/wiki/l10n/pluralforms
18 * and Plural forms mentioned on http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms
19 *
20 * See also https://developer.mozilla.org/en/Localization_and_Plurals which mentions 15 rules having a maximum of 6 forms.
21 * The mozilla code is also interesting to check for.
22 *
23 * As mentioned by chx http://drupal.org/node/1273968 we can cover all by testing number from 0 to 199
24 *
25 * The goal to cover all languages is to far fetched so this test case is smaller.
26 *
27 * @author Clemens Tolboom clemens@build2be.nl
28 */
29class PluralizationRulesTest extends \PHPUnit_Framework_TestCase
30{
31
32 /**
33 * We test failed langcode here.
34 *
35 * TODO: The languages mentioned in the data provide need to get fixed somehow within PluralizationRules.
36 *
37 * @dataProvider failingLangcodes
38 */
39 public function testFailedLangcodes($nplural, $langCodes)
40 {
41 $matrix = $this->generateTestData($nplural, $langCodes);
42 $this->validateMatrix($nplural, $matrix, false);
43 }
44
45 /**
46 * @dataProvider successLangcodes
47 */
48 public function testLangcodes($nplural, $langCodes)
49 {
50 $matrix = $this->generateTestData($nplural, $langCodes);
51 $this->validateMatrix($nplural, $matrix);
52 }
53
54 /**
55 * This array should contain all currently known langcodes.
56 *
57 * As it is impossible to have this ever complete we should try as hard as possible to have it almost complete.
58 *
59 * @return type
60 */
61 public function successLangcodes()
62 {
63 return array(
64 array('1' , array('ay','bo', 'cgg','dz','id', 'ja', 'jbo', 'ka','kk','km','ko','ky')),
65 array('2' , array('nl', 'fr', 'en', 'de', 'de_GE')),
66 array('3' , array('be','bs','cs','hr')),
67 array('4' , array('cy','mt', 'sl')),
68 array('5' , array()),
69 array('6' , array('ar')),
70 );
71 }
72
73 /**
74 * This array should be at least empty within the near future.
75 *
76 * This both depends on a complete list trying to add above as understanding
77 * the plural rules of the current failing languages.
78 *
79 * @return array with nplural together with langcodes
80 */
81 public function failingLangcodes()
82 {
83 return array(
84 array('1' , array('fa')),
85 array('2' , array('jbo')),
86 array('3' , array('cbs')),
87 array('4' , array('gd','kw')),
88 array('5' , array('ga')),
89 array('6' , array()),
90 );
91 }
92
93 /**
94 * We validate only on the plural coverage. Thus the real rules is not tested.
95 *
96 * @param string $nplural plural expected
97 * @param array $matrix containing langcodes and their plural index values.
98 * @param boolean $expectSuccess
99 */
100 protected function validateMatrix($nplural, $matrix, $expectSuccess = true)
101 {
102 foreach ($matrix as $langCode => $data) {
103 $indexes = array_flip($data);
104 if ($expectSuccess) {
105 $this->assertEquals($nplural, count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
106 } else {
107 $this->assertNotEquals((int) $nplural, count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
108 }
109 }
110 }
111
112 protected function generateTestData($plural, $langCodes)
113 {
114 $matrix = array();
115 foreach ($langCodes as $langCode) {
116 for ($count=0; $count<200; $count++) {
117 $plural = PluralizationRules::get($count, $langCode);
118 $matrix[$langCode][$count] = $plural;
119 }
120 }
121
122 return $matrix;
123 }
124}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/TranslatorTest.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/TranslatorTest.php
new file mode 100644
index 00000000..fb843d72
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/TranslatorTest.php
@@ -0,0 +1,306 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Tests;
13
14use Symfony\Component\Translation\Translator;
15use Symfony\Component\Translation\MessageSelector;
16use Symfony\Component\Translation\Loader\ArrayLoader;
17
18class TranslatorTest extends \PHPUnit_Framework_TestCase
19{
20 public function testSetGetLocale()
21 {
22 $translator = new Translator('en', new MessageSelector());
23
24 $this->assertEquals('en', $translator->getLocale());
25
26 $translator->setLocale('fr');
27 $this->assertEquals('fr', $translator->getLocale());
28 }
29
30 public function testSetFallbackLocales()
31 {
32 $translator = new Translator('en', new MessageSelector());
33 $translator->addLoader('array', new ArrayLoader());
34 $translator->addResource('array', array('foo' => 'foofoo'), 'en');
35 $translator->addResource('array', array('bar' => 'foobar'), 'fr');
36
37 // force catalogue loading
38 $translator->trans('bar');
39
40 $translator->setFallbackLocales(array('fr'));
41 $this->assertEquals('foobar', $translator->trans('bar'));
42 }
43
44 public function testSetFallbackLocalesMultiple()
45 {
46 $translator = new Translator('en', new MessageSelector());
47 $translator->addLoader('array', new ArrayLoader());
48 $translator->addResource('array', array('foo' => 'foo (en)'), 'en');
49 $translator->addResource('array', array('bar' => 'bar (fr)'), 'fr');
50
51 // force catalogue loading
52 $translator->trans('bar');
53
54 $translator->setFallbackLocales(array('fr_FR', 'fr'));
55 $this->assertEquals('bar (fr)', $translator->trans('bar'));
56 }
57
58 public function testTransWithFallbackLocale()
59 {
60 $translator = new Translator('fr_FR', new MessageSelector());
61 $translator->addLoader('array', new ArrayLoader());
62 $translator->addResource('array', array('foo' => 'foofoo'), 'en_US');
63 $translator->addResource('array', array('bar' => 'foobar'), 'en');
64
65 $translator->setFallbackLocales(array('en'));
66
67 $this->assertEquals('foobar', $translator->trans('bar'));
68 }
69
70 public function testAddResourceAfterTrans()
71 {
72 $translator = new Translator('fr', new MessageSelector());
73 $translator->addLoader('array', new ArrayLoader());
74
75 $translator->setFallbackLocale(array('en'));
76
77 $translator->addResource('array', array('foo' => 'foofoo'), 'en');
78 $this->assertEquals('foofoo', $translator->trans('foo'));
79
80 $translator->addResource('array', array('bar' => 'foobar'), 'en');
81 $this->assertEquals('foobar', $translator->trans('bar'));
82 }
83
84 /**
85 * @dataProvider getTransFileTests
86 * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
87 */
88 public function testTransWithoutFallbackLocaleFile($format, $loader)
89 {
90 $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
91 $translator = new Translator('en', new MessageSelector());
92 $translator->addLoader($format, new $loaderClass());
93 $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en');
94 $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en');
95
96 // force catalogue loading
97 $translator->trans('foo');
98 }
99
100 /**
101 * @dataProvider getTransFileTests
102 */
103 public function testTransWithFallbackLocaleFile($format, $loader)
104 {
105 $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
106 $translator = new Translator('en_GB', new MessageSelector());
107 $translator->addLoader($format, new $loaderClass());
108 $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en_GB');
109 $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en', 'resources');
110
111 $this->assertEquals('bar', $translator->trans('foo', array(), 'resources'));
112 }
113
114 public function testTransWithFallbackLocaleBis()
115 {
116 $translator = new Translator('en_US', new MessageSelector());
117 $translator->addLoader('array', new ArrayLoader());
118 $translator->addResource('array', array('foo' => 'foofoo'), 'en_US');
119 $translator->addResource('array', array('bar' => 'foobar'), 'en');
120 $this->assertEquals('foobar', $translator->trans('bar'));
121 }
122
123 public function testTransWithFallbackLocaleTer()
124 {
125 $translator = new Translator('fr_FR', new MessageSelector());
126 $translator->addLoader('array', new ArrayLoader());
127 $translator->addResource('array', array('foo' => 'foo (en_US)'), 'en_US');
128 $translator->addResource('array', array('bar' => 'bar (en)'), 'en');
129
130 $translator->setFallbackLocales(array('en_US', 'en'));
131
132 $this->assertEquals('foo (en_US)', $translator->trans('foo'));
133 $this->assertEquals('bar (en)', $translator->trans('bar'));
134 }
135
136 public function testTransNonExistentWithFallback()
137 {
138 $translator = new Translator('fr', new MessageSelector());
139 $translator->setFallbackLocales(array('en'));
140 $translator->addLoader('array', new ArrayLoader());
141 $this->assertEquals('non-existent', $translator->trans('non-existent'));
142 }
143
144 /**
145 * @expectedException RuntimeException
146 */
147 public function testWhenAResourceHasNoRegisteredLoader()
148 {
149 $translator = new Translator('en', new MessageSelector());
150 $translator->addResource('array', array('foo' => 'foofoo'), 'en');
151
152 $translator->trans('foo');
153 }
154
155 /**
156 * @dataProvider getTransTests
157 */
158 public function testTrans($expected, $id, $translation, $parameters, $locale, $domain)
159 {
160 $translator = new Translator('en', new MessageSelector());
161 $translator->addLoader('array', new ArrayLoader());
162 $translator->addResource('array', array((string) $id => $translation), $locale, $domain);
163
164 $this->assertEquals($expected, $translator->trans($id, $parameters, $domain, $locale));
165 }
166
167 /**
168 * @dataProvider getFlattenedTransTests
169 */
170 public function testFlattenedTrans($expected, $messages, $id)
171 {
172 $translator = new Translator('en', new MessageSelector());
173 $translator->addLoader('array', new ArrayLoader());
174 $translator->addResource('array', $messages, 'fr', '');
175
176 $this->assertEquals($expected, $translator->trans($id, array(), '', 'fr'));
177 }
178
179 /**
180 * @dataProvider getTransChoiceTests
181 */
182 public function testTransChoice($expected, $id, $translation, $number, $parameters, $locale, $domain)
183 {
184 $translator = new Translator('en', new MessageSelector());
185 $translator->addLoader('array', new ArrayLoader());
186 $translator->addResource('array', array((string) $id => $translation), $locale, $domain);
187
188 $this->assertEquals($expected, $translator->transChoice($id, $number, $parameters, $domain, $locale));
189 }
190
191 public function getTransFileTests()
192 {
193 return array(
194 array('csv', 'CsvFileLoader'),
195 array('ini', 'IniFileLoader'),
196 array('mo', 'MoFileLoader'),
197 array('po', 'PoFileLoader'),
198 array('php', 'PhpFileLoader'),
199 array('ts', 'QtFileLoader'),
200 array('xlf', 'XliffFileLoader'),
201 array('yml', 'YamlFileLoader'),
202 );
203 }
204
205 public function getTransTests()
206 {
207 return array(
208 array('Symfony2 est super !', 'Symfony2 is great!', 'Symfony2 est super !', array(), 'fr', ''),
209 array('Symfony2 est awesome !', 'Symfony2 is %what%!', 'Symfony2 est %what% !', array('%what%' => 'awesome'), 'fr', ''),
210 array('Symfony2 est super !', new String('Symfony2 is great!'), 'Symfony2 est super !', array(), 'fr', ''),
211 );
212 }
213
214 public function getFlattenedTransTests()
215 {
216 $messages = array(
217 'symfony2' => array(
218 'is' => array(
219 'great' => 'Symfony2 est super!'
220 )
221 ),
222 'foo' => array(
223 'bar' => array(
224 'baz' => 'Foo Bar Baz'
225 ),
226 'baz' => 'Foo Baz',
227 ),
228 );
229
230 return array(
231 array('Symfony2 est super!', $messages, 'symfony2.is.great'),
232 array('Foo Bar Baz', $messages, 'foo.bar.baz'),
233 array('Foo Baz', $messages, 'foo.baz'),
234 );
235 }
236
237 public function getTransChoiceTests()
238 {
239 return array(
240 array('Il y a 0 pomme', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
241 array('Il y a 1 pomme', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
242 array('Il y a 10 pommes', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
243
244 array('Il y a 0 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
245 array('Il y a 1 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
246 array('Il y a 10 pommes', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
247
248 array('Il y a 0 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
249 array('Il y a 1 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
250 array('Il y a 10 pommes', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
251
252 array('Il n\'y a aucune pomme', '{0} There is no apple|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
253 array('Il y a 1 pomme', '{0} There is no apple|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
254 array('Il y a 10 pommes', '{0} There is no apple|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
255
256 array('Il y a 0 pomme', new String('{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples'), '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
257 );
258 }
259
260 public function testTransChoiceFallback()
261 {
262 $translator = new Translator('ru', new MessageSelector());
263 $translator->setFallbackLocales(array('en'));
264 $translator->addLoader('array', new ArrayLoader());
265 $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en');
266
267 $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
268 }
269
270 public function testTransChoiceFallbackBis()
271 {
272 $translator = new Translator('ru', new MessageSelector());
273 $translator->setFallbackLocales(array('en_US', 'en'));
274 $translator->addLoader('array', new ArrayLoader());
275 $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en_US');
276
277 $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
278 }
279
280 /**
281 * @expectedException \InvalidArgumentException
282 */
283 public function testTransChoiceFallbackWithNoTranslation()
284 {
285 $translator = new Translator('ru', new MessageSelector());
286 $translator->setFallbackLocales(array('en'));
287 $translator->addLoader('array', new ArrayLoader());
288
289 $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
290 }
291}
292
293class String
294{
295 protected $str;
296
297 public function __construct($str)
298 {
299 $this->str = $str;
300 }
301
302 public function __toString()
303 {
304 return $this->str;
305 }
306}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty-translation.po b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty-translation.po
new file mode 100644
index 00000000..ff6f22af
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty-translation.po
@@ -0,0 +1,3 @@
1msgid "foo"
2msgstr ""
3
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.csv b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.csv
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.csv
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.ini b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.ini
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.ini
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.mo b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.mo
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.mo
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.po b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.po
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.po
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.yml b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.yml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/empty.yml
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/encoding.xlf b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/encoding.xlf
new file mode 100644
index 00000000..6be901bd
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/encoding.xlf
@@ -0,0 +1,15 @@
1<?xml version="1.0" encoding="ISO-8859-1"?>
2<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="1" resname="foo">
6 <source>foo</source>
7 <target>bär</target>
8 </trans-unit>
9 <trans-unit id="2" resname="bar">
10 <source>bar</source>
11 <target>föö</target>
12 </trans-unit>
13 </body>
14 </file>
15</xliff>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/invalid-xml-resources.xlf b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/invalid-xml-resources.xlf
new file mode 100644
index 00000000..7bf6c98b
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/invalid-xml-resources.xlf
@@ -0,0 +1,23 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="1">
6 <source>foo</source>
7 <target>bar
8 </trans-unit>
9 <trans-unit id="2">
10 <source>extra</source>
11 </trans-unit>
12 <trans-unit id="3">
13 <source>key</source>
14 <target></target>
15 </trans-unit>
16 <trans-unit id="4">
17 <source>test</source>
18 <target>with</target>
19 <note>note</note>
20 </trans-unit>
21 </body>
22 </file>
23</xliff>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/non-valid.xlf b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/non-valid.xlf
new file mode 100644
index 00000000..734fc97e
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/non-valid.xlf
@@ -0,0 +1,11 @@
1<?xml version="1.0"?>
2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit>
6 <source>foo</source>
7 <target>bar</target>
8 </trans-unit>
9 </body>
10 </file>
11</xliff>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/non-valid.yml b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/non-valid.yml
new file mode 100644
index 00000000..257cc564
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/non-valid.yml
@@ -0,0 +1 @@
foo
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/plurals.mo b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/plurals.mo
new file mode 100644
index 00000000..6445e77b
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/plurals.mo
Binary files differ
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/plurals.po b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/plurals.po
new file mode 100644
index 00000000..439c41ad
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/plurals.po
@@ -0,0 +1,5 @@
1msgid "foo"
2msgid_plural "foos"
3msgstr[0] "bar"
4msgstr[1] "bars"
5
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resname.xlf b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resname.xlf
new file mode 100644
index 00000000..2df16af9
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resname.xlf
@@ -0,0 +1,19 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="1" resname="foo">
6 <source></source>
7 <target>bar</target>
8 </trans-unit>
9 <trans-unit id="2" resname="bar">
10 <source>bar source</source>
11 <target>baz</target>
12 </trans-unit>
13 <trans-unit id="3">
14 <source>baz</source>
15 <target>foo</target>
16 </trans-unit>
17 </body>
18 </file>
19</xliff>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/corrupted/resources.dat b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/corrupted/resources.dat
new file mode 100644
index 00000000..391250ca
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/corrupted/resources.dat
@@ -0,0 +1 @@
XXX \ No newline at end of file
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/en.res b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/en.res
new file mode 100644
index 00000000..1fc1436d
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/en.res
Binary files differ
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/en.txt b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/en.txt
new file mode 100644
index 00000000..c04a4e85
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/en.txt
@@ -0,0 +1,3 @@
1en{
2 symfony{"Symfony 2 is great"}
3} \ No newline at end of file
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/fr.res b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/fr.res
new file mode 100644
index 00000000..f5841609
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/fr.res
Binary files differ
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/fr.txt b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/fr.txt
new file mode 100644
index 00000000..7e84f67a
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/fr.txt
@@ -0,0 +1,3 @@
1fr{
2 symfony{"Symfony 2 est génial"}
3} \ No newline at end of file
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/packagelist.txt b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/packagelist.txt
new file mode 100644
index 00000000..c5783ed4
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/packagelist.txt
@@ -0,0 +1,2 @@
1en.res
2fr.res
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/resources.dat b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/resources.dat
new file mode 100644
index 00000000..563b0eae
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/dat/resources.dat
Binary files differ
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/res/en.res b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/res/en.res
new file mode 100644
index 00000000..ad894a92
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resourcebundle/res/en.res
Binary files differ
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources-clean.xlf b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources-clean.xlf
new file mode 100644
index 00000000..464b0792
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources-clean.xlf
@@ -0,0 +1,15 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="acbd18db4cc2f85cedef654fccc4a4d8" resname="foo">
6 <source>foo</source>
7 <target>bar</target>
8 </trans-unit>
9 <trans-unit id="3c6e0b8a9c15224a8228b9a98ca1531d" resname="key">
10 <source>key</source>
11 <target></target>
12 </trans-unit>
13 </body>
14 </file>
15</xliff>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.csv b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.csv
new file mode 100644
index 00000000..374b9eb5
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.csv
@@ -0,0 +1,4 @@
1"foo"; "bar"
2#"bar"; "foo"
3"incorrect"; "number"; "columns"; "will"; "be"; "ignored"
4"incorrect" \ No newline at end of file
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.ini b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.ini
new file mode 100644
index 00000000..4953062e
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.ini
@@ -0,0 +1 @@
foo="bar"
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.mo b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.mo
new file mode 100644
index 00000000..0a966025
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.mo
Binary files differ
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.php b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.php
new file mode 100644
index 00000000..c2913985
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.php
@@ -0,0 +1,5 @@
1<?php
2
3return array (
4 'foo' => 'bar',
5);
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.po b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.po
new file mode 100644
index 00000000..da0d5f46
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.po
@@ -0,0 +1,2 @@
1msgid "foo"
2msgstr "bar" \ No newline at end of file
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.ts b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.ts
new file mode 100644
index 00000000..40e18522
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.ts
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2<TS>
3 <context>
4 <name>resources</name>
5 <message>
6 <source>foo</source>
7 <translation>bar</translation>
8 </message>
9 </context>
10</TS>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.xlf b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.xlf
new file mode 100644
index 00000000..b0e59880
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.xlf
@@ -0,0 +1,23 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
3 <file source-language="en" datatype="plaintext" original="file.ext">
4 <body>
5 <trans-unit id="1">
6 <source>foo</source>
7 <target>bar</target>
8 </trans-unit>
9 <trans-unit id="2">
10 <source>extra</source>
11 </trans-unit>
12 <trans-unit id="3">
13 <source>key</source>
14 <target></target>
15 </trans-unit>
16 <trans-unit id="4">
17 <source>test</source>
18 <target>with</target>
19 <note>note</note>
20 </trans-unit>
21 </body>
22 </file>
23</xliff>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.yml b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.yml
new file mode 100644
index 00000000..20e9ff3f
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/resources.yml
@@ -0,0 +1 @@
foo: bar
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/valid.csv b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/valid.csv
new file mode 100644
index 00000000..59882e5d
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/valid.csv
@@ -0,0 +1,4 @@
1foo;bar
2bar;"foo
3foo"
4"foo;foo";bar
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/withdoctype.xlf b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/withdoctype.xlf
new file mode 100644
index 00000000..f83e834d
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Tests/fixtures/withdoctype.xlf
@@ -0,0 +1,12 @@
1<?xml version="1.0"?>
2<!DOCTYPE foo>
3<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
4 <file source-language="en" datatype="plaintext" original="file.ext">
5 <body>
6 <trans-unit id="1">
7 <source>foo</source>
8 <target>bar</target>
9 </trans-unit>
10 </body>
11 </file>
12</xliff>
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Translator.php b/vendor/symfony/translation/Symfony/Component/Translation/Translator.php
new file mode 100644
index 00000000..8e74b79f
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Translator.php
@@ -0,0 +1,282 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation;
13
14use Symfony\Component\Translation\Loader\LoaderInterface;
15use Symfony\Component\Translation\Exception\NotFoundResourceException;
16
17/**
18 * Translator.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 *
22 * @api
23 */
24class Translator implements TranslatorInterface
25{
26 /**
27 * @var MessageCatalogueInterface[]
28 */
29 protected $catalogues = array();
30
31 /**
32 * @var string
33 */
34 protected $locale;
35
36 /**
37 * @var array
38 */
39 private $fallbackLocales = array();
40
41 /**
42 * @var LoaderInterface[]
43 */
44 private $loaders = array();
45
46 /**
47 * @var array
48 */
49 private $resources = array();
50
51 /**
52 * @var MessageSelector
53 */
54 private $selector;
55
56 /**
57 * Constructor.
58 *
59 * @param string $locale The locale
60 * @param MessageSelector|null $selector The message selector for pluralization
61 *
62 * @api
63 */
64 public function __construct($locale, MessageSelector $selector = null)
65 {
66 $this->locale = $locale;
67 $this->selector = $selector ?: new MessageSelector();
68 }
69
70 /**
71 * Adds a Loader.
72 *
73 * @param string $format The name of the loader (@see addResource())
74 * @param LoaderInterface $loader A LoaderInterface instance
75 *
76 * @api
77 */
78 public function addLoader($format, LoaderInterface $loader)
79 {
80 $this->loaders[$format] = $loader;
81 }
82
83 /**
84 * Adds a Resource.
85 *
86 * @param string $format The name of the loader (@see addLoader())
87 * @param mixed $resource The resource name
88 * @param string $locale The locale
89 * @param string $domain The domain
90 *
91 * @api
92 */
93 public function addResource($format, $resource, $locale, $domain = null)
94 {
95 if (null === $domain) {
96 $domain = 'messages';
97 }
98
99 $this->resources[$locale][] = array($format, $resource, $domain);
100
101 if (in_array($locale, $this->fallbackLocales)) {
102 $this->catalogues = array();
103 } else {
104 unset($this->catalogues[$locale]);
105 }
106 }
107
108 /**
109 * {@inheritdoc}
110 *
111 * @api
112 */
113 public function setLocale($locale)
114 {
115 $this->locale = $locale;
116 }
117
118 /**
119 * {@inheritdoc}
120 *
121 * @api
122 */
123 public function getLocale()
124 {
125 return $this->locale;
126 }
127
128 /**
129 * Sets the fallback locale(s).
130 *
131 * @param string|array $locales The fallback locale(s)
132 *
133 * @deprecated since 2.3, to be removed in 3.0. Use setFallbackLocales() instead.
134 *
135 * @api
136 */
137 public function setFallbackLocale($locales)
138 {
139 $this->setFallbackLocales(is_array($locales) ? $locales : array($locales));
140 }
141
142 /**
143 * Sets the fallback locales.
144 *
145 * @param array $locales The fallback locales
146 *
147 * @api
148 */
149 public function setFallbackLocales(array $locales)
150 {
151 // needed as the fallback locales are linked to the already loaded catalogues
152 $this->catalogues = array();
153
154 $this->fallbackLocales = $locales;
155 }
156
157 /**
158 * Gets the fallback locales.
159 *
160 * @return array $locales The fallback locales
161 *
162 * @api
163 */
164 public function getFallbackLocales()
165 {
166 return $this->fallbackLocales;
167 }
168
169 /**
170 * {@inheritdoc}
171 *
172 * @api
173 */
174 public function trans($id, array $parameters = array(), $domain = null, $locale = null)
175 {
176 if (null === $locale) {
177 $locale = $this->getLocale();
178 }
179
180 if (null === $domain) {
181 $domain = 'messages';
182 }
183
184 if (!isset($this->catalogues[$locale])) {
185 $this->loadCatalogue($locale);
186 }
187
188 return strtr($this->catalogues[$locale]->get((string) $id, $domain), $parameters);
189 }
190
191 /**
192 * {@inheritdoc}
193 *
194 * @api
195 */
196 public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
197 {
198 if (null === $locale) {
199 $locale = $this->getLocale();
200 }
201
202 if (null === $domain) {
203 $domain = 'messages';
204 }
205
206 if (!isset($this->catalogues[$locale])) {
207 $this->loadCatalogue($locale);
208 }
209
210 $id = (string) $id;
211
212 $catalogue = $this->catalogues[$locale];
213 while (!$catalogue->defines($id, $domain)) {
214 if ($cat = $catalogue->getFallbackCatalogue()) {
215 $catalogue = $cat;
216 $locale = $catalogue->getLocale();
217 } else {
218 break;
219 }
220 }
221
222 return strtr($this->selector->choose($catalogue->get($id, $domain), (int) $number, $locale), $parameters);
223 }
224
225 protected function loadCatalogue($locale)
226 {
227 try {
228 $this->doLoadCatalogue($locale);
229 } catch (NotFoundResourceException $e) {
230 if (!$this->computeFallbackLocales($locale)) {
231 throw $e;
232 }
233 }
234 $this->loadFallbackCatalogues($locale);
235 }
236
237 private function doLoadCatalogue($locale)
238 {
239 $this->catalogues[$locale] = new MessageCatalogue($locale);
240
241 if (isset($this->resources[$locale])) {
242 foreach ($this->resources[$locale] as $resource) {
243 if (!isset($this->loaders[$resource[0]])) {
244 throw new \RuntimeException(sprintf('The "%s" translation loader is not registered.', $resource[0]));
245 }
246 $this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2]));
247 }
248 }
249 }
250
251 private function loadFallbackCatalogues($locale)
252 {
253 $current = $this->catalogues[$locale];
254
255 foreach ($this->computeFallbackLocales($locale) as $fallback) {
256 if (!isset($this->catalogues[$fallback])) {
257 $this->doLoadCatalogue($fallback);
258 }
259
260 $current->addFallbackCatalogue($this->catalogues[$fallback]);
261 $current = $this->catalogues[$fallback];
262 }
263 }
264
265 protected function computeFallbackLocales($locale)
266 {
267 $locales = array();
268 foreach ($this->fallbackLocales as $fallback) {
269 if ($fallback === $locale) {
270 continue;
271 }
272
273 $locales[] = $fallback;
274 }
275
276 if (strrchr($locale, '_') !== false) {
277 array_unshift($locales, substr($locale, 0, -strlen(strrchr($locale, '_'))));
278 }
279
280 return array_unique($locales);
281 }
282}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/TranslatorInterface.php b/vendor/symfony/translation/Symfony/Component/Translation/TranslatorInterface.php
new file mode 100644
index 00000000..3dcdd4fc
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/TranslatorInterface.php
@@ -0,0 +1,69 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation;
13
14/**
15 * TranslatorInterface.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 *
19 * @api
20 */
21interface TranslatorInterface
22{
23 /**
24 * Translates the given message.
25 *
26 * @param string $id The message id (may also be an object that can be cast to string)
27 * @param array $parameters An array of parameters for the message
28 * @param string $domain The domain for the message
29 * @param string $locale The locale
30 *
31 * @return string The translated string
32 *
33 * @api
34 */
35 public function trans($id, array $parameters = array(), $domain = null, $locale = null);
36
37 /**
38 * Translates the given choice message by choosing a translation according to a number.
39 *
40 * @param string $id The message id (may also be an object that can be cast to string)
41 * @param integer $number The number to use to find the indice of the message
42 * @param array $parameters An array of parameters for the message
43 * @param string $domain The domain for the message
44 * @param string $locale The locale
45 *
46 * @return string The translated string
47 *
48 * @api
49 */
50 public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null);
51
52 /**
53 * Sets the current locale.
54 *
55 * @param string $locale The locale
56 *
57 * @api
58 */
59 public function setLocale($locale);
60
61 /**
62 * Returns the current locale.
63 *
64 * @return string The locale
65 *
66 * @api
67 */
68 public function getLocale();
69}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Writer/TranslationWriter.php b/vendor/symfony/translation/Symfony/Component/Translation/Writer/TranslationWriter.php
new file mode 100644
index 00000000..9d70c12f
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/Writer/TranslationWriter.php
@@ -0,0 +1,73 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Writer;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Dumper\DumperInterface;
16
17/**
18 * TranslationWriter writes translation messages.
19 *
20 * @author Michel Salib <michelsalib@hotmail.com>
21 */
22class TranslationWriter
23{
24 /**
25 * Dumpers used for export.
26 *
27 * @var array
28 */
29 private $dumpers = array();
30
31 /**
32 * Adds a dumper to the writer.
33 *
34 * @param string $format The format of the dumper
35 * @param DumperInterface $dumper The dumper
36 */
37 public function addDumper($format, DumperInterface $dumper)
38 {
39 $this->dumpers[$format] = $dumper;
40 }
41
42 /**
43 * Obtains the list of supported formats.
44 *
45 * @return array
46 */
47 public function getFormats()
48 {
49 return array_keys($this->dumpers);
50 }
51
52 /**
53 * Writes translation from the catalogue according to the selected format.
54 *
55 * @param MessageCatalogue $catalogue The message catalogue to dump
56 * @param string $format The format to use to dump the messages
57 * @param array $options Options that are passed to the dumper
58 *
59 * @throws \InvalidArgumentException
60 */
61 public function writeTranslations(MessageCatalogue $catalogue, $format, $options = array())
62 {
63 if (!isset($this->dumpers[$format])) {
64 throw new \InvalidArgumentException(sprintf('There is no dumper associated with format "%s".', $format));
65 }
66
67 // get the right dumper
68 $dumper = $this->dumpers[$format];
69
70 // save
71 $dumper->dump($catalogue, $options);
72 }
73}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/composer.json b/vendor/symfony/translation/Symfony/Component/Translation/composer.json
new file mode 100644
index 00000000..96a8e662
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/composer.json
@@ -0,0 +1,39 @@
1{
2 "name": "symfony/translation",
3 "type": "library",
4 "description": "Symfony Translation Component",
5 "keywords": [],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3"
20 },
21 "require-dev": {
22 "symfony/config": "~2.0",
23 "symfony/yaml": "~2.2"
24 },
25 "suggest": {
26 "symfony/config": "",
27 "symfony/yaml": ""
28 },
29 "autoload": {
30 "psr-0": { "Symfony\\Component\\Translation\\": "" }
31 },
32 "target-dir": "Symfony/Component/Translation",
33 "minimum-stability": "dev",
34 "extra": {
35 "branch-alias": {
36 "dev-master": "2.3-dev"
37 }
38 }
39}
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/phpunit.xml.dist b/vendor/symfony/translation/Symfony/Component/Translation/phpunit.xml.dist
new file mode 100644
index 00000000..1b37f214
--- /dev/null
+++ b/vendor/symfony/translation/Symfony/Component/Translation/phpunit.xml.dist
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony Translation Component Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./vendor</directory>
25 <directory>./Tests</directory>
26 </exclude>
27 </whitelist>
28 </filter>
29</phpunit>
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/.gitignore b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/.gitignore
new file mode 100644
index 00000000..44de97a3
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/.gitignore
@@ -0,0 +1,4 @@
1vendor/
2composer.lock
3phpunit.xml
4
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/CHANGELOG.md b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/CHANGELOG.md
new file mode 100644
index 00000000..ad22216e
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/CHANGELOG.md
@@ -0,0 +1,29 @@
1CHANGELOG
2=========
3
42.3.0
5-----
6
7 * added helpers form(), form_start() and form_end()
8 * deprecated form_enctype() in favor of form_start()
9
102.2.0
11-----
12
13 * added a `controller` function to help generating controller references
14 * added a `render_esi` and a `render_hinclude` function
15 * [BC BREAK] restricted the `render` tag to only accept URIs or ControllerReference instances (the signature changed)
16 * added a `render` function to render a request
17 * The `app` global variable is now injected even when using the twig service directly.
18 * Added an optional parameter to the `path` and `url` function which allows to generate
19 relative paths (e.g. "../parent-file") and scheme-relative URLs (e.g. "//example.com/dir/file").
20
212.1.0
22-----
23
24 * added global variables access in a form theme
25 * added TwigEngine
26 * added TwigExtractor
27 * added a csrf_token function
28 * added a way to specify a default domain for a Twig template (via the
29 'trans_default_domain' tag)
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/CodeExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/CodeExtension.php
new file mode 100644
index 00000000..a6202b24
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/CodeExtension.php
@@ -0,0 +1,232 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Extension;
13
14if (!defined('ENT_SUBSTITUTE')) {
15 define('ENT_SUBSTITUTE', 8);
16}
17
18/**
19 * Twig extension relate to PHP code and used by the profiler and the default exception templates.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 */
23class CodeExtension extends \Twig_Extension
24{
25 private $fileLinkFormat;
26 private $rootDir;
27 private $charset;
28
29 /**
30 * Constructor.
31 *
32 * @param string $fileLinkFormat The format for links to source files
33 * @param string $rootDir The project root directory
34 * @param string $charset The charset
35 */
36 public function __construct($fileLinkFormat, $rootDir, $charset)
37 {
38 $this->fileLinkFormat = empty($fileLinkFormat) ? ini_get('xdebug.file_link_format') : $fileLinkFormat;
39 $this->rootDir = str_replace('\\', '/', $rootDir).'/';
40 $this->charset = $charset;
41 }
42
43 /**
44 * {@inheritdoc}
45 */
46 public function getFilters()
47 {
48 return array(
49 'abbr_class' => new \Twig_Filter_Method($this, 'abbrClass', array('is_safe' => array('html'))),
50 'abbr_method' => new \Twig_Filter_Method($this, 'abbrMethod', array('is_safe' => array('html'))),
51 'format_args' => new \Twig_Filter_Method($this, 'formatArgs', array('is_safe' => array('html'))),
52 'format_args_as_text' => new \Twig_Filter_Method($this, 'formatArgsAsText'),
53 'file_excerpt' => new \Twig_Filter_Method($this, 'fileExcerpt', array('is_safe' => array('html'))),
54 'format_file' => new \Twig_Filter_Method($this, 'formatFile', array('is_safe' => array('html'))),
55 'format_file_from_text' => new \Twig_Filter_Method($this, 'formatFileFromText', array('is_safe' => array('html'))),
56 'file_link' => new \Twig_Filter_Method($this, 'getFileLink', array('is_safe' => array('html'))),
57 );
58 }
59
60 public function abbrClass($class)
61 {
62 $parts = explode('\\', $class);
63 $short = array_pop($parts);
64
65 return sprintf("<abbr title=\"%s\">%s</abbr>", $class, $short);
66 }
67
68 public function abbrMethod($method)
69 {
70 if (false !== strpos($method, '::')) {
71 list($class, $method) = explode('::', $method, 2);
72 $result = sprintf("%s::%s()", $this->abbrClass($class), $method);
73 } elseif ('Closure' === $method) {
74 $result = sprintf("<abbr title=\"%s\">%s</abbr>", $method, $method);
75 } else {
76 $result = sprintf("<abbr title=\"%s\">%s</abbr>()", $method, $method);
77 }
78
79 return $result;
80 }
81
82 /**
83 * Formats an array as a string.
84 *
85 * @param array $args The argument array
86 *
87 * @return string
88 */
89 public function formatArgs($args)
90 {
91 $result = array();
92 foreach ($args as $key => $item) {
93 if ('object' === $item[0]) {
94 $parts = explode('\\', $item[1]);
95 $short = array_pop($parts);
96 $formattedValue = sprintf("<em>object</em>(<abbr title=\"%s\">%s</abbr>)", $item[1], $short);
97 } elseif ('array' === $item[0]) {
98 $formattedValue = sprintf("<em>array</em>(%s)", is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
99 } elseif ('string' === $item[0]) {
100 $formattedValue = sprintf("'%s'", htmlspecialchars($item[1], ENT_QUOTES, $this->charset));
101 } elseif ('null' === $item[0]) {
102 $formattedValue = '<em>null</em>';
103 } elseif ('boolean' === $item[0]) {
104 $formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
105 } elseif ('resource' === $item[0]) {
106 $formattedValue = '<em>resource</em>';
107 } else {
108 $formattedValue = str_replace("\n", '', var_export(htmlspecialchars((string) $item[1], ENT_QUOTES, $this->charset), true));
109 }
110
111 $result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
112 }
113
114 return implode(', ', $result);
115 }
116
117 /**
118 * Formats an array as a string.
119 *
120 * @param array $args The argument array
121 *
122 * @return string
123 */
124 public function formatArgsAsText($args)
125 {
126 return strip_tags($this->formatArgs($args));
127 }
128
129 /**
130 * Returns an excerpt of a code file around the given line number.
131 *
132 * @param string $file A file path
133 * @param int $line The selected line number
134 *
135 * @return string An HTML string
136 */
137 public function fileExcerpt($file, $line)
138 {
139 if (is_readable($file)) {
140 $code = highlight_file($file, true);
141 // remove main code/span tags
142 $code = preg_replace('#^<code.*?>\s*<span.*?>(.*)</span>\s*</code>#s', '\\1', $code);
143 $content = preg_split('#<br />#', $code);
144
145 $lines = array();
146 for ($i = max($line - 3, 1), $max = min($line + 3, count($content)); $i <= $max; $i++) {
147 $lines[] = '<li'.($i == $line ? ' class="selected"' : '').'><code>'.self::fixCodeMarkup($content[$i - 1]).'</code></li>';
148 }
149
150 return '<ol start="'.max($line - 3, 1).'">'.implode("\n", $lines).'</ol>';
151 }
152 }
153
154 /**
155 * Formats a file path.
156 *
157 * @param string $file An absolute file path
158 * @param integer $line The line number
159 * @param string $text Use this text for the link rather than the file path
160 *
161 * @return string
162 */
163 public function formatFile($file, $line, $text = null)
164 {
165 if (null === $text) {
166 $file = trim($file);
167 $text = $file;
168 if (0 === strpos($text, $this->rootDir)) {
169 $text = str_replace($this->rootDir, '', str_replace('\\', '/', $text));
170 $text = sprintf('<abbr title="%s">kernel.root_dir</abbr>/%s', $this->rootDir, $text);
171 }
172 }
173
174 $text = "$text at line $line";
175
176 if (false !== $link = $this->getFileLink($file, $line)) {
177 return sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', htmlspecialchars($link, ENT_QUOTES | ENT_SUBSTITUTE, $this->charset), $text);
178 }
179
180 return $text;
181 }
182
183 /**
184 * Returns the link for a given file/line pair.
185 *
186 * @param string $file An absolute file path
187 * @param integer $line The line number
188 *
189 * @return string A link of false
190 */
191 public function getFileLink($file, $line)
192 {
193 if ($this->fileLinkFormat && is_file($file)) {
194 return strtr($this->fileLinkFormat, array('%f' => $file, '%l' => $line));
195 }
196
197 return false;
198 }
199
200 public function formatFileFromText($text)
201 {
202 $that = $this;
203
204 return preg_replace_callback('/in ("|&quot;)?(.+?)\1(?: +(?:on|at))? +line (\d+)/s', function ($match) use ($that) {
205 return 'in '.$that->formatFile($match[2], $match[3]);
206 }, $text);
207 }
208
209 public function getName()
210 {
211 return 'code';
212 }
213
214 protected static function fixCodeMarkup($line)
215 {
216 // </span> ending tag from previous line
217 $opening = strpos($line, '<span');
218 $closing = strpos($line, '</span>');
219 if (false !== $closing && (false === $opening || $closing < $opening)) {
220 $line = substr_replace($line, '', $closing, 7);
221 }
222
223 // missing </span> tag at the end of line
224 $opening = strpos($line, '<span');
225 $closing = strpos($line, '</span>');
226 if (false !== $opening && (false === $closing || $closing > $opening)) {
227 $line .= '</span>';
228 }
229
230 return $line;
231 }
232}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/FormExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/FormExtension.php
new file mode 100644
index 00000000..fbfa5243
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/FormExtension.php
@@ -0,0 +1,136 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Extension;
13
14use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
15use Symfony\Bridge\Twig\Form\TwigRendererInterface;
16use Symfony\Component\Form\Extension\Core\View\ChoiceView;
17
18/**
19 * FormExtension extends Twig with form capabilities.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 * @author Bernhard Schussek <bschussek@gmail.com>
23 */
24class FormExtension extends \Twig_Extension
25{
26 /**
27 * This property is public so that it can be accessed directly from compiled
28 * templates without having to call a getter, which slightly decreases performance.
29 *
30 * @var TwigRendererInterface
31 */
32 public $renderer;
33
34 public function __construct(TwigRendererInterface $renderer)
35 {
36 $this->renderer = $renderer;
37 }
38
39 /**
40 * {@inheritdoc}
41 */
42 public function initRuntime(\Twig_Environment $environment)
43 {
44 $this->renderer->setEnvironment($environment);
45 }
46
47 /**
48 * {@inheritdoc}
49 */
50 public function getTokenParsers()
51 {
52 return array(
53 // {% form_theme form "SomeBundle::widgets.twig" %}
54 new FormThemeTokenParser(),
55 );
56 }
57
58 /**
59 * {@inheritdoc}
60 */
61 public function getFunctions()
62 {
63 return array(
64 'form_enctype' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\FormEnctypeNode', array('is_safe' => array('html'))),
65 'form_widget' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
66 'form_errors' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
67 'form_label' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
68 'form_row' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
69 'form_rest' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
70 'form' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
71 'form_start' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
72 'form_end' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
73 'csrf_token' => new \Twig_Function_Method($this, 'renderer->renderCsrfToken'),
74 );
75 }
76
77 /**
78 * {@inheritdoc}
79 */
80 public function getFilters()
81 {
82 return array(
83 'humanize' => new \Twig_Filter_Method($this, 'renderer->humanize'),
84 );
85 }
86
87 /**
88 * {@inheritdoc}
89 */
90 public function getTests()
91 {
92 return array(
93 'selectedchoice' => new \Twig_Test_Method($this, 'isSelectedChoice'),
94 );
95 }
96
97 /**
98 * Returns whether a choice is selected for a given form value.
99 *
100 * Unfortunately Twig does not support an efficient way to execute the
101 * "is_selected" closure passed to the template by ChoiceType. It is faster
102 * to implement the logic here (around 65ms for a specific form).
103 *
104 * Directly implementing the logic here is also faster than doing so in
105 * ChoiceView (around 30ms).
106 *
107 * The worst option tested so far is to implement the logic in ChoiceView
108 * and access the ChoiceView method directly in the template. Doing so is
109 * around 220ms slower than doing the method call here in the filter. Twig
110 * seems to be much more efficient at executing filters than at executing
111 * methods of an object.
112 *
113 * @param ChoiceView $choice The choice to check.
114 * @param string|array $selectedValue The selected value to compare.
115 *
116 * @return Boolean Whether the choice is selected.
117 *
118 * @see ChoiceView::isSelected()
119 */
120 public function isSelectedChoice(ChoiceView $choice, $selectedValue)
121 {
122 if (is_array($selectedValue)) {
123 return false !== array_search($choice->value, $selectedValue, true);
124 }
125
126 return $choice->value === $selectedValue;
127 }
128
129 /**
130 * {@inheritdoc}
131 */
132 public function getName()
133 {
134 return 'form';
135 }
136}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php
new file mode 100644
index 00000000..a8377234
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php
@@ -0,0 +1,88 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Extension;
13
14use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
15use Symfony\Component\HttpKernel\Controller\ControllerReference;
16
17/**
18 * Provides integration with the HttpKernel component.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 */
22class HttpKernelExtension extends \Twig_Extension
23{
24 private $handler;
25
26 /**
27 * Constructor.
28 *
29 * @param FragmentHandler $handler A FragmentHandler instance
30 */
31 public function __construct(FragmentHandler $handler)
32 {
33 $this->handler = $handler;
34 }
35
36 public function getFunctions()
37 {
38 return array(
39 'render' => new \Twig_Function_Method($this, 'renderFragment', array('is_safe' => array('html'))),
40 'render_*' => new \Twig_Function_Method($this, 'renderFragmentStrategy', array('is_safe' => array('html'))),
41 'controller' => new \Twig_Function_Method($this, 'controller'),
42 );
43 }
44
45 /**
46 * Renders a fragment.
47 *
48 * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
49 * @param array $options An array of options
50 *
51 * @return string The fragment content
52 *
53 * @see Symfony\Component\HttpKernel\Fragment\FragmentHandler::render()
54 */
55 public function renderFragment($uri, $options = array())
56 {
57 $strategy = isset($options['strategy']) ? $options['strategy'] : 'inline';
58 unset($options['strategy']);
59
60 return $this->handler->render($uri, $strategy, $options);
61 }
62
63 /**
64 * Renders a fragment.
65 *
66 * @param string $strategy A strategy name
67 * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
68 * @param array $options An array of options
69 *
70 * @return string The fragment content
71 *
72 * @see Symfony\Component\HttpKernel\Fragment\FragmentHandler::render()
73 */
74 public function renderFragmentStrategy($strategy, $uri, $options = array())
75 {
76 return $this->handler->render($uri, $strategy, $options);
77 }
78
79 public function controller($controller, $attributes = array(), $query = array())
80 {
81 return new ControllerReference($controller, $attributes, $query);
82 }
83
84 public function getName()
85 {
86 return 'http_kernel';
87 }
88}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/RoutingExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/RoutingExtension.php
new file mode 100644
index 00000000..8274abf3
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/RoutingExtension.php
@@ -0,0 +1,100 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Extension;
13
14use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15
16/**
17 * Provides integration of the Routing component with Twig.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class RoutingExtension extends \Twig_Extension
22{
23 private $generator;
24
25 public function __construct(UrlGeneratorInterface $generator)
26 {
27 $this->generator = $generator;
28 }
29
30 /**
31 * Returns a list of functions to add to the existing list.
32 *
33 * @return array An array of functions
34 */
35 public function getFunctions()
36 {
37 return array(
38 'url' => new \Twig_Function_Method($this, 'getUrl', array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
39 'path' => new \Twig_Function_Method($this, 'getPath', array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
40 );
41 }
42
43 public function getPath($name, $parameters = array(), $relative = false)
44 {
45 return $this->generator->generate($name, $parameters, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH);
46 }
47
48 public function getUrl($name, $parameters = array(), $schemeRelative = false)
49 {
50 return $this->generator->generate($name, $parameters, $schemeRelative ? UrlGeneratorInterface::NETWORK_PATH : UrlGeneratorInterface::ABSOLUTE_URL);
51 }
52
53 /**
54 * Determines at compile time whether the generated URL will be safe and thus
55 * saving the unneeded automatic escaping for performance reasons.
56 *
57 * The URL generation process percent encodes non-alphanumeric characters. So there is no risk
58 * that malicious/invalid characters are part of the URL. The only character within an URL that
59 * must be escaped in html is the ampersand ("&") which separates query params. So we cannot mark
60 * the URL generation as always safe, but only when we are sure there won't be multiple query
61 * params. This is the case when there are none or only one constant parameter given.
62 * E.g. we know beforehand this will be safe:
63 * - path('route')
64 * - path('route', {'param': 'value'})
65 * But the following may not:
66 * - path('route', var)
67 * - path('route', {'param': ['val1', 'val2'] }) // a sub-array
68 * - path('route', {'param1': 'value1', 'param2': 'value2'})
69 * If param1 and param2 reference placeholder in the route, it would still be safe. But we don't know.
70 *
71 * @param \Twig_Node $argsNode The arguments of the path/url function
72 *
73 * @return array An array with the contexts the URL is safe
74 */
75 public function isUrlGenerationSafe(\Twig_Node $argsNode)
76 {
77 // support named arguments
78 $paramsNode = $argsNode->hasNode('parameters') ? $argsNode->getNode('parameters') : (
79 $argsNode->hasNode(1) ? $argsNode->getNode(1) : null
80 );
81
82 if (null === $paramsNode || $paramsNode instanceof \Twig_Node_Expression_Array && count($paramsNode) <= 2 &&
83 (!$paramsNode->hasNode(1) || $paramsNode->getNode(1) instanceof \Twig_Node_Expression_Constant)
84 ) {
85 return array('html');
86 }
87
88 return array();
89 }
90
91 /**
92 * Returns the name of the extension.
93 *
94 * @return string The extension name
95 */
96 public function getName()
97 {
98 return 'routing';
99 }
100}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/SecurityExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/SecurityExtension.php
new file mode 100644
index 00000000..c9f4466c
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/SecurityExtension.php
@@ -0,0 +1,63 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Extension;
13
14use Symfony\Component\Security\Acl\Voter\FieldVote;
15use Symfony\Component\Security\Core\SecurityContextInterface;
16
17/**
18 * SecurityExtension exposes security context features.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 */
22class SecurityExtension extends \Twig_Extension
23{
24 private $context;
25
26 public function __construct(SecurityContextInterface $context = null)
27 {
28 $this->context = $context;
29 }
30
31 public function isGranted($role, $object = null, $field = null)
32 {
33 if (null === $this->context) {
34 return false;
35 }
36
37 if (null !== $field) {
38 $object = new FieldVote($object, $field);
39 }
40
41 return $this->context->isGranted($role, $object);
42 }
43
44 /**
45 * {@inheritdoc}
46 */
47 public function getFunctions()
48 {
49 return array(
50 'is_granted' => new \Twig_Function_Method($this, 'isGranted'),
51 );
52 }
53
54 /**
55 * Returns the name of the extension.
56 *
57 * @return string The extension name
58 */
59 public function getName()
60 {
61 return 'security';
62 }
63}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/TranslationExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/TranslationExtension.php
new file mode 100644
index 00000000..2ab3832d
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/TranslationExtension.php
@@ -0,0 +1,118 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Extension;
13
14use Symfony\Bridge\Twig\TokenParser\TransTokenParser;
15use Symfony\Bridge\Twig\TokenParser\TransChoiceTokenParser;
16use Symfony\Bridge\Twig\TokenParser\TransDefaultDomainTokenParser;
17use Symfony\Component\Translation\TranslatorInterface;
18use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
19use Symfony\Bridge\Twig\NodeVisitor\TranslationDefaultDomainNodeVisitor;
20
21/**
22 * Provides integration of the Translation component with Twig.
23 *
24 * @author Fabien Potencier <fabien@symfony.com>
25 */
26class TranslationExtension extends \Twig_Extension
27{
28 private $translator;
29 private $translationNodeVisitor;
30
31 public function __construct(TranslatorInterface $translator, \Twig_NodeVisitorInterface $translationNodeVisitor = null)
32 {
33 if (!$translationNodeVisitor) {
34 $translationNodeVisitor = new TranslationNodeVisitor();
35 }
36
37 $this->translator = $translator;
38 $this->translationNodeVisitor = $translationNodeVisitor;
39 }
40
41 public function getTranslator()
42 {
43 return $this->translator;
44 }
45
46 /**
47 * {@inheritdoc}
48 */
49 public function getFilters()
50 {
51 return array(
52 'trans' => new \Twig_Filter_Method($this, 'trans'),
53 'transchoice' => new \Twig_Filter_Method($this, 'transchoice'),
54 );
55 }
56
57 /**
58 * Returns the token parser instance to add to the existing list.
59 *
60 * @return array An array of Twig_TokenParser instances
61 */
62 public function getTokenParsers()
63 {
64 return array(
65 // {% trans %}Symfony is great!{% endtrans %}
66 new TransTokenParser(),
67
68 // {% transchoice count %}
69 // {0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples
70 // {% endtranschoice %}
71 new TransChoiceTokenParser(),
72
73 // {% trans_default_domain "foobar" %}
74 new TransDefaultDomainTokenParser(),
75 );
76 }
77
78 /**
79 * {@inheritdoc}
80 */
81 public function getNodeVisitors()
82 {
83 return array($this->translationNodeVisitor, new TranslationDefaultDomainNodeVisitor());
84 }
85
86 public function getTranslationNodeVisitor()
87 {
88 return $this->translationNodeVisitor;
89 }
90
91 public function trans($message, array $arguments = array(), $domain = null, $locale = null)
92 {
93 if (null === $domain) {
94 $domain = 'messages';
95 }
96
97 return $this->translator->trans($message, $arguments, $domain, $locale);
98 }
99
100 public function transchoice($message, $count, array $arguments = array(), $domain = null, $locale = null)
101 {
102 if (null === $domain) {
103 $domain = 'messages';
104 }
105
106 return $this->translator->transChoice($message, $count, array_merge(array('%count%' => $count), $arguments), $domain, $locale);
107 }
108
109 /**
110 * Returns the name of the extension.
111 *
112 * @return string The extension name
113 */
114 public function getName()
115 {
116 return 'translator';
117 }
118}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/YamlExtension.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/YamlExtension.php
new file mode 100644
index 00000000..f88829ee
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Extension/YamlExtension.php
@@ -0,0 +1,67 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Extension;
13
14use Symfony\Component\Yaml\Dumper as YamlDumper;
15
16/**
17 * Provides integration of the Yaml component with Twig.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class YamlExtension extends \Twig_Extension
22{
23 /**
24 * {@inheritdoc}
25 */
26 public function getFilters()
27 {
28 return array(
29 'yaml_encode' => new \Twig_Filter_Method($this, 'encode'),
30 'yaml_dump' => new \Twig_Filter_Method($this, 'dump'),
31 );
32 }
33
34 public function encode($input, $inline = 0, $dumpObjects = false)
35 {
36 static $dumper;
37
38 if (null === $dumper) {
39 $dumper = new YamlDumper();
40 }
41
42 return $dumper->dump($input, $inline, false, $dumpObjects);
43 }
44
45 public function dump($value, $inline = 0, $dumpObjects = false)
46 {
47 if (is_resource($value)) {
48 return '%Resource%';
49 }
50
51 if (is_array($value) || is_object($value)) {
52 return '%'.gettype($value).'% '.$this->encode($value, $inline, $dumpObjects);
53 }
54
55 return $this->encode($value, $inline, $dumpObjects);
56 }
57
58 /**
59 * Returns the name of the extension.
60 *
61 * @return string The extension name
62 */
63 public function getName()
64 {
65 return 'yaml';
66 }
67}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRenderer.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRenderer.php
new file mode 100644
index 00000000..72798d10
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRenderer.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Form;
13
14use Symfony\Component\Form\FormRenderer;
15use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class TwigRenderer extends FormRenderer implements TwigRendererInterface
21{
22 /**
23 * @var TwigRendererEngineInterface
24 */
25 private $engine;
26
27 public function __construct(TwigRendererEngineInterface $engine, CsrfProviderInterface $csrfProvider = null)
28 {
29 parent::__construct($engine, $csrfProvider);
30
31 $this->engine = $engine;
32 }
33
34 /**
35 * {@inheritdoc}
36 */
37 public function setEnvironment(\Twig_Environment $environment)
38 {
39 $this->engine->setEnvironment($environment);
40 }
41}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngine.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngine.php
new file mode 100644
index 00000000..05beb315
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngine.php
@@ -0,0 +1,183 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Form;
13
14use Symfony\Component\Form\AbstractRendererEngine;
15use Symfony\Component\Form\FormView;
16
17/**
18 * @author Bernhard Schussek <bschussek@gmail.com>
19 */
20class TwigRendererEngine extends AbstractRendererEngine implements TwigRendererEngineInterface
21{
22 /**
23 * @var \Twig_Environment
24 */
25 private $environment;
26
27 /**
28 * @var \Twig_Template
29 */
30 private $template;
31
32 /**
33 * {@inheritdoc}
34 */
35 public function setEnvironment(\Twig_Environment $environment)
36 {
37 $this->environment = $environment;
38 }
39
40 /**
41 * {@inheritdoc}
42 */
43 public function renderBlock(FormView $view, $resource, $blockName, array $variables = array())
44 {
45 $cacheKey = $view->vars[self::CACHE_KEY_VAR];
46
47 $context = $this->environment->mergeGlobals($variables);
48
49 ob_start();
50
51 // By contract,This method can only be called after getting the resource
52 // (which is passed to the method). Getting a resource for the first time
53 // (with an empty cache) is guaranteed to invoke loadResourcesFromTheme(),
54 // where the property $template is initialized.
55
56 // We do not call renderBlock here to avoid too many nested level calls
57 // (XDebug limits the level to 100 by default)
58 $this->template->displayBlock($blockName, $context, $this->resources[$cacheKey]);
59
60 return ob_get_clean();
61 }
62
63 /**
64 * Loads the cache with the resource for a given block name.
65 *
66 * This implementation eagerly loads all blocks of the themes assigned to the given view
67 * and all of its ancestors views. This is necessary, because Twig receives the
68 * list of blocks later. At that point, all blocks must already be loaded, for the
69 * case that the function "block()" is used in the Twig template.
70 *
71 * @see getResourceForBlock()
72 *
73 * @param string $cacheKey The cache key of the form view.
74 * @param FormView $view The form view for finding the applying themes.
75 * @param string $blockName The name of the block to load.
76 *
77 * @return Boolean True if the resource could be loaded, false otherwise.
78 */
79 protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName)
80 {
81 // The caller guarantees that $this->resources[$cacheKey][$block] is
82 // not set, but it doesn't have to check whether $this->resources[$cacheKey]
83 // is set. If $this->resources[$cacheKey] is set, all themes for this
84 // $cacheKey are already loaded (due to the eager population, see doc comment).
85 if (isset($this->resources[$cacheKey])) {
86 // As said in the previous, the caller guarantees that
87 // $this->resources[$cacheKey][$block] is not set. Since the themes are
88 // already loaded, it can only be a non-existing block.
89 $this->resources[$cacheKey][$blockName] = false;
90
91 return false;
92 }
93
94 // Recursively try to find the block in the themes assigned to $view,
95 // then of its parent view, then of the parent view of the parent and so on.
96 // When the root view is reached in this recursion, also the default
97 // themes are taken into account.
98
99 // Check each theme whether it contains the searched block
100 if (isset($this->themes[$cacheKey])) {
101 for ($i = count($this->themes[$cacheKey]) - 1; $i >= 0; --$i) {
102 $this->loadResourcesFromTheme($cacheKey, $this->themes[$cacheKey][$i]);
103 // CONTINUE LOADING (see doc comment)
104 }
105 }
106
107 // Check the default themes once we reach the root view without success
108 if (!$view->parent) {
109 for ($i = count($this->defaultThemes) - 1; $i >= 0; --$i) {
110 $this->loadResourcesFromTheme($cacheKey, $this->defaultThemes[$i]);
111 // CONTINUE LOADING (see doc comment)
112 }
113 }
114
115 // Proceed with the themes of the parent view
116 if ($view->parent) {
117 $parentCacheKey = $view->parent->vars[self::CACHE_KEY_VAR];
118
119 if (!isset($this->resources[$parentCacheKey])) {
120 $this->loadResourceForBlockName($parentCacheKey, $view->parent, $blockName);
121 }
122
123 // EAGER CACHE POPULATION (see doc comment)
124 foreach ($this->resources[$parentCacheKey] as $nestedBlockName => $resource) {
125 if (!isset($this->resources[$cacheKey][$nestedBlockName])) {
126 $this->resources[$cacheKey][$nestedBlockName] = $resource;
127 }
128 }
129 }
130
131 // Even though we loaded the themes, it can happen that none of them
132 // contains the searched block
133 if (!isset($this->resources[$cacheKey][$blockName])) {
134 // Cache that we didn't find anything to speed up further accesses
135 $this->resources[$cacheKey][$blockName] = false;
136 }
137
138 return false !== $this->resources[$cacheKey][$blockName];
139 }
140
141 /**
142 * Loads the resources for all blocks in a theme.
143 *
144 * @param string $cacheKey The cache key for storing the resource.
145 * @param mixed $theme The theme to load the block from. This parameter
146 * is passed by reference, because it might be necessary
147 * to initialize the theme first. Any changes made to
148 * this variable will be kept and be available upon
149 * further calls to this method using the same theme.
150 */
151 protected function loadResourcesFromTheme($cacheKey, &$theme)
152 {
153 if (!$theme instanceof \Twig_Template) {
154 /* @var \Twig_Template $theme */
155 $theme = $this->environment->loadTemplate($theme);
156 }
157
158 if (null === $this->template) {
159 // Store the first \Twig_Template instance that we find so that
160 // we can call displayBlock() later on. It doesn't matter *which*
161 // template we use for that, since we pass the used blocks manually
162 // anyway.
163 $this->template = $theme;
164 }
165
166 // Use a separate variable for the inheritance traversal, because
167 // theme is a reference and we don't want to change it.
168 $currentTheme = $theme;
169
170 // The do loop takes care of template inheritance.
171 // Add blocks from all templates in the inheritance tree, but avoid
172 // overriding blocks already set.
173 do {
174 foreach ($currentTheme->getBlocks() as $block => $blockData) {
175 if (!isset($this->resources[$cacheKey][$block])) {
176 // The resource given back is the key to the bucket that
177 // contains this block.
178 $this->resources[$cacheKey][$block] = $blockData;
179 }
180 }
181 } while (false !== $currentTheme = $currentTheme->getParent(array()));
182 }
183}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngineInterface.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngineInterface.php
new file mode 100644
index 00000000..ef764a24
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererEngineInterface.php
@@ -0,0 +1,27 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Form;
13
14use Symfony\Component\Form\FormRendererEngineInterface;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface TwigRendererEngineInterface extends FormRendererEngineInterface
20{
21 /**
22 * Sets Twig's environment.
23 *
24 * @param \Twig_Environment $environment
25 */
26 public function setEnvironment(\Twig_Environment $environment);
27}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererInterface.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererInterface.php
new file mode 100644
index 00000000..4682f520
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Form/TwigRendererInterface.php
@@ -0,0 +1,27 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Form;
13
14use Symfony\Component\Form\FormRendererInterface;
15
16/**
17 * @author Bernhard Schussek <bschussek@gmail.com>
18 */
19interface TwigRendererInterface extends FormRendererInterface
20{
21 /**
22 * Sets Twig's environment.
23 *
24 * @param \Twig_Environment $environment
25 */
26 public function setEnvironment(\Twig_Environment $environment);
27}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/LICENSE b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormEnctypeNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormEnctypeNode.php
new file mode 100644
index 00000000..93bce1b9
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormEnctypeNode.php
@@ -0,0 +1,31 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Node;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 *
17 * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
18 * the helper "form_start()" instead.
19 */
20class FormEnctypeNode extends SearchAndRenderBlockNode
21{
22 public function compile(\Twig_Compiler $compiler)
23 {
24 parent::compile($compiler);
25
26 $compiler->raw(";\n");
27
28 // Uncomment this as soon as the deprecation note should be shown
29 // $compiler->write('trigger_error(\'The helper form_enctype(form) is deprecated since version 2.3 and will be removed in 3.0. Use form_start(form) instead.\', E_USER_DEPRECATED)');
30 }
31}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormThemeNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormThemeNode.php
new file mode 100644
index 00000000..329ab86f
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/FormThemeNode.php
@@ -0,0 +1,40 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Node;
13
14/**
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class FormThemeNode extends \Twig_Node
18{
19 public function __construct(\Twig_NodeInterface $form, \Twig_NodeInterface $resources, $lineno, $tag = null)
20 {
21 parent::__construct(array('form' => $form, 'resources' => $resources), array(), $lineno, $tag);
22 }
23
24 /**
25 * Compiles the node to PHP.
26 *
27 * @param \Twig_Compiler $compiler A Twig_Compiler instance
28 */
29 public function compile(\Twig_Compiler $compiler)
30 {
31 $compiler
32 ->addDebugInfo($this)
33 ->write('$this->env->getExtension(\'form\')->renderer->setTheme(')
34 ->subcompile($this->getNode('form'))
35 ->raw(', ')
36 ->subcompile($this->getNode('resources'))
37 ->raw(");\n");
38 ;
39 }
40}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/RenderBlockNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/RenderBlockNode.php
new file mode 100644
index 00000000..822a2727
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/RenderBlockNode.php
@@ -0,0 +1,42 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Node;
13
14/**
15 * Compiles a call to {@link FormRendererInterface::renderBlock()}.
16 *
17 * The function name is used as block name. For example, if the function name
18 * is "foo", the block "foo" will be rendered.
19 *
20 * @author Bernhard Schussek <bschussek@gmail.com>
21 */
22class RenderBlockNode extends \Twig_Node_Expression_Function
23{
24 public function compile(\Twig_Compiler $compiler)
25 {
26 $compiler->addDebugInfo($this);
27 $arguments = iterator_to_array($this->getNode('arguments'));
28 $compiler->write('$this->env->getExtension(\'form\')->renderer->renderBlock(');
29
30 if (isset($arguments[0])) {
31 $compiler->subcompile($arguments[0]);
32 $compiler->raw(', \'' . $this->getAttribute('name') . '\'');
33
34 if (isset($arguments[1])) {
35 $compiler->raw(', ');
36 $compiler->subcompile($arguments[1]);
37 }
38 }
39
40 $compiler->raw(')');
41 }
42}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php
new file mode 100644
index 00000000..630e2638
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php
@@ -0,0 +1,106 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Node;
13
14/**
15 * @author Bernhard Schussek <bschussek@gmail.com>
16 */
17class SearchAndRenderBlockNode extends \Twig_Node_Expression_Function
18{
19 public function compile(\Twig_Compiler $compiler)
20 {
21 $compiler->addDebugInfo($this);
22 $compiler->raw('$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(');
23
24 preg_match('/_([^_]+)$/', $this->getAttribute('name'), $matches);
25
26 $label = null;
27 $arguments = iterator_to_array($this->getNode('arguments'));
28 $blockNameSuffix = $matches[1];
29
30 if (isset($arguments[0])) {
31 $compiler->subcompile($arguments[0]);
32 $compiler->raw(', \''.$blockNameSuffix.'\'');
33
34 if (isset($arguments[1])) {
35 if ('label' === $blockNameSuffix) {
36 // The "label" function expects the label in the second and
37 // the variables in the third argument
38 $label = $arguments[1];
39 $variables = isset($arguments[2]) ? $arguments[2] : null;
40 $lineno = $label->getLine();
41
42 if ($label instanceof \Twig_Node_Expression_Constant) {
43 // If the label argument is given as a constant, we can either
44 // strip it away if it is empty, or integrate it into the array
45 // of variables at compile time.
46 $labelIsExpression = false;
47
48 // Only insert the label into the array if it is not empty
49 if (!twig_test_empty($label->getAttribute('value'))) {
50 $originalVariables = $variables;
51 $variables = new \Twig_Node_Expression_Array(array(), $lineno);
52 $labelKey = new \Twig_Node_Expression_Constant('label', $lineno);
53
54 if (null !== $originalVariables) {
55 foreach ($originalVariables->getKeyValuePairs() as $pair) {
56 // Don't copy the original label attribute over if it exists
57 if ((string) $labelKey !== (string) $pair['key']) {
58 $variables->addElement($pair['value'], $pair['key']);
59 }
60 }
61 }
62
63 // Insert the label argument into the array
64 $variables->addElement($label, $labelKey);
65 }
66 } else {
67 // The label argument is not a constant, but some kind of
68 // expression. This expression needs to be evaluated at runtime.
69 // Depending on the result (whether it is null or not), the
70 // label in the arguments should take precedence over the label
71 // in the attributes or not.
72 $labelIsExpression = true;
73 }
74 } else {
75 // All other functions than "label" expect the variables
76 // in the second argument
77 $label = null;
78 $variables = $arguments[1];
79 $labelIsExpression = false;
80 }
81
82 if (null !== $variables || $labelIsExpression) {
83 $compiler->raw(', ');
84
85 if (null !== $variables) {
86 $compiler->subcompile($variables);
87 }
88
89 if ($labelIsExpression) {
90 if (null !== $variables) {
91 $compiler->raw(' + ');
92 }
93
94 // Check at runtime whether the label is empty.
95 // If not, add it to the array at runtime.
96 $compiler->raw('(twig_test_empty($_label_ = ');
97 $compiler->subcompile($label);
98 $compiler->raw(') ? array() : array("label" => $_label_))');
99 }
100 }
101 }
102 }
103
104 $compiler->raw(")");
105 }
106}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php
new file mode 100644
index 00000000..adee71ff
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Node;
13
14/**
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class TransDefaultDomainNode extends \Twig_Node
18{
19 public function __construct(\Twig_Node_Expression $expr, $lineno = 0, $tag = null)
20 {
21 parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
22 }
23
24 /**
25 * Compiles the node to PHP.
26 *
27 * @param \Twig_Compiler $compiler A Twig_Compiler instance
28 */
29 public function compile(\Twig_Compiler $compiler)
30 {
31 // noop as this node is just a marker for TranslationDefaultDomainNodeVisitor
32 }
33}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransNode.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransNode.php
new file mode 100644
index 00000000..a68c101a
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Node/TransNode.php
@@ -0,0 +1,119 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Node;
13
14/**
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class TransNode extends \Twig_Node
18{
19 public function __construct(\Twig_NodeInterface $body, \Twig_NodeInterface $domain = null, \Twig_Node_Expression $count = null, \Twig_Node_Expression $vars = null, \Twig_Node_Expression $locale = null, $lineno = 0, $tag = null)
20 {
21 parent::__construct(array('count' => $count, 'body' => $body, 'domain' => $domain, 'vars' => $vars, 'locale' => $locale), array(), $lineno, $tag);
22 }
23
24 /**
25 * Compiles the node to PHP.
26 *
27 * @param \Twig_Compiler $compiler A Twig_Compiler instance
28 */
29 public function compile(\Twig_Compiler $compiler)
30 {
31 $compiler->addDebugInfo($this);
32
33 $vars = $this->getNode('vars');
34 $defaults = new \Twig_Node_Expression_Array(array(), -1);
35 if ($vars instanceof \Twig_Node_Expression_Array) {
36 $defaults = $this->getNode('vars');
37 $vars = null;
38 }
39 list($msg, $defaults) = $this->compileString($this->getNode('body'), $defaults);
40
41 $method = null === $this->getNode('count') ? 'trans' : 'transChoice';
42
43 $compiler
44 ->write('echo $this->env->getExtension(\'translator\')->getTranslator()->'.$method.'(')
45 ->subcompile($msg)
46 ;
47
48 $compiler->raw(', ');
49
50 if (null !== $this->getNode('count')) {
51 $compiler
52 ->subcompile($this->getNode('count'))
53 ->raw(', ')
54 ;
55 }
56
57 if (null !== $vars) {
58 $compiler
59 ->raw('array_merge(')
60 ->subcompile($defaults)
61 ->raw(', ')
62 ->subcompile($this->getNode('vars'))
63 ->raw(')')
64 ;
65 } else {
66 $compiler->subcompile($defaults);
67 }
68
69 $compiler->raw(', ');
70
71 if (null === $this->getNode('domain')) {
72 $compiler->repr('messages');
73 } else {
74 $compiler->subcompile($this->getNode('domain'));
75 }
76
77 if (null !== $this->getNode('locale')) {
78 $compiler
79 ->raw(', ')
80 ->subcompile($this->getNode('locale'))
81 ;
82 }
83 $compiler->raw(");\n");
84 }
85
86 protected function compileString(\Twig_NodeInterface $body, \Twig_Node_Expression_Array $vars)
87 {
88 if ($body instanceof \Twig_Node_Expression_Constant) {
89 $msg = $body->getAttribute('value');
90 } elseif ($body instanceof \Twig_Node_Text) {
91 $msg = $body->getAttribute('data');
92 } else {
93 return array($body, $vars);
94 }
95
96 preg_match_all('/(?<!%)%([^%]+)%/', $msg, $matches);
97
98 if (version_compare(\Twig_Environment::VERSION, '1.5', '>=')) {
99 foreach ($matches[1] as $var) {
100 $key = new \Twig_Node_Expression_Constant('%'.$var.'%', $body->getLine());
101 if (!$vars->hasElement($key)) {
102 $vars->addElement(new \Twig_Node_Expression_Name($var, $body->getLine()), $key);
103 }
104 }
105 } else {
106 $current = array();
107 foreach ($vars as $name => $var) {
108 $current[$name] = true;
109 }
110 foreach ($matches[1] as $var) {
111 if (!isset($current['%'.$var.'%'])) {
112 $vars->setNode('%'.$var.'%', new \Twig_Node_Expression_Name($var, $body->getLine()));
113 }
114 }
115 }
116
117 return array(new \Twig_Node_Expression_Constant(str_replace('%%', '%', trim($msg)), $body->getLine()), $vars);
118 }
119}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/Scope.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/Scope.php
new file mode 100644
index 00000000..ce27b6a6
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/Scope.php
@@ -0,0 +1,135 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\NodeVisitor;
13
14/**
15 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
16 */
17class Scope
18{
19 /**
20 * @var Scope|null
21 */
22 private $parent;
23
24 /**
25 * @var Scope[]
26 */
27 private $children;
28
29 /**
30 * @var array
31 */
32 private $data;
33
34 /**
35 * @var boolean
36 */
37 private $left;
38
39 /**
40 * @param Scope $parent
41 */
42 public function __construct(Scope $parent = null)
43 {
44 $this->parent = $parent;
45 $this->left = false;
46 $this->data = array();
47 }
48
49 /**
50 * Opens a new child scope.
51 *
52 * @return Scope
53 */
54 public function enter()
55 {
56 $child = new self($this);
57 $this->children[] = $child;
58
59 return $child;
60 }
61
62 /**
63 * Closes current scope and returns parent one.
64 *
65 * @return Scope|null
66 */
67 public function leave()
68 {
69 $this->left = true;
70
71 return $this->parent;
72 }
73
74 /**
75 * Stores data into current scope.
76 *
77 * @param string $key
78 * @param mixed $value
79 *
80 * @throws \LogicException
81 *
82 * @return Scope Current scope
83 */
84 public function set($key, $value)
85 {
86 if ($this->left) {
87 throw new \LogicException('Left scope is not mutable.');
88 }
89
90 $this->data[$key] = $value;
91
92 return $this;
93 }
94
95 /**
96 * Tests if a data is visible from current scope.
97 *
98 * @param string $key
99 *
100 * @return boolean
101 */
102 public function has($key)
103 {
104 if (array_key_exists($key, $this->data)) {
105 return true;
106 }
107
108 if (null === $this->parent) {
109 return false;
110 }
111
112 return $this->parent->has($key);
113 }
114
115 /**
116 * Returns data visible from current scope.
117 *
118 * @param string $key
119 * @param mixed $default
120 *
121 * @return mixed
122 */
123 public function get($key, $default = null)
124 {
125 if (array_key_exists($key, $this->data)) {
126 return $this->data[$key];
127 }
128
129 if (null === $this->parent) {
130 return $default;
131 }
132
133 return $this->parent->get($key, $default);
134 }
135}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php
new file mode 100644
index 00000000..8e7e7f48
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php
@@ -0,0 +1,106 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\NodeVisitor;
13
14use Symfony\Bridge\Twig\Node\TransNode;
15use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
16
17/**
18 * TranslationDefaultDomainNodeVisitor.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 */
22class TranslationDefaultDomainNodeVisitor implements \Twig_NodeVisitorInterface
23{
24 /**
25 * @var Scope
26 */
27 private $scope;
28
29 /**
30 * Constructor.
31 */
32 public function __construct()
33 {
34 $this->scope = new Scope();
35 }
36
37 /**
38 * {@inheritdoc}
39 */
40 public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env)
41 {
42 if ($node instanceof \Twig_Node_Block || $node instanceof \Twig_Node_Module) {
43 $this->scope = $this->scope->enter();
44 }
45
46 if ($node instanceof TransDefaultDomainNode) {
47 if ($node->getNode('expr') instanceof \Twig_Node_Expression_Constant) {
48 $this->scope->set('domain', $node->getNode('expr'));
49
50 return $node;
51 } else {
52 $var = $env->getParser()->getVarName();
53 $name = new \Twig_Node_Expression_AssignName($var, $node->getLine());
54 $this->scope->set('domain', new \Twig_Node_Expression_Name($var, $node->getLine()));
55
56 return new \Twig_Node_Set(false, new \Twig_Node(array($name)), new \Twig_Node(array($node->getNode('expr'))), $node->getLine());
57 }
58 }
59
60 if (!$this->scope->has('domain')) {
61 return $node;
62 }
63
64 if ($node instanceof \Twig_Node_Expression_Filter && in_array($node->getNode('filter')->getAttribute('value'), array('trans', 'transchoice'))) {
65 $ind = 'trans' === $node->getNode('filter')->getAttribute('value') ? 1 : 2;
66 $arguments = $node->getNode('arguments');
67 if (!$arguments->hasNode($ind)) {
68 if (!$arguments->hasNode($ind - 1)) {
69 $arguments->setNode($ind - 1, new \Twig_Node_Expression_Array(array(), $node->getLine()));
70 }
71
72 $arguments->setNode($ind, $this->scope->get('domain'));
73 }
74 } elseif ($node instanceof TransNode) {
75 if (null === $node->getNode('domain')) {
76 $node->setNode('domain', $this->scope->get('domain'));
77 }
78 }
79
80 return $node;
81 }
82
83 /**
84 * {@inheritdoc}
85 */
86 public function leaveNode(\Twig_NodeInterface $node, \Twig_Environment $env)
87 {
88 if ($node instanceof TransDefaultDomainNode) {
89 return false;
90 }
91
92 if ($node instanceof \Twig_Node_Block || $node instanceof \Twig_Node_Module) {
93 $this->scope = $this->scope->leave();
94 }
95
96 return $node;
97 }
98
99 /**
100 * {@inheritdoc}
101 */
102 public function getPriority()
103 {
104 return -10;
105 }
106}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php
new file mode 100644
index 00000000..592c2506
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php
@@ -0,0 +1,137 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\NodeVisitor;
13
14use Symfony\Bridge\Twig\Node\TransNode;
15
16/**
17 * TranslationNodeVisitor extracts translation messages.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class TranslationNodeVisitor implements \Twig_NodeVisitorInterface
22{
23 const UNDEFINED_DOMAIN = '_undefined';
24
25 private $enabled = false;
26 private $messages = array();
27
28 public function enable()
29 {
30 $this->enabled = true;
31 $this->messages = array();
32 }
33
34 public function disable()
35 {
36 $this->enabled = false;
37 $this->messages = array();
38 }
39
40 public function getMessages()
41 {
42 return $this->messages;
43 }
44
45 /**
46 * {@inheritdoc}
47 */
48 public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env)
49 {
50 if (!$this->enabled) {
51 return $node;
52 }
53
54 if (
55 $node instanceof \Twig_Node_Expression_Filter &&
56 'trans' === $node->getNode('filter')->getAttribute('value') &&
57 $node->getNode('node') instanceof \Twig_Node_Expression_Constant
58 ) {
59 // extract constant nodes with a trans filter
60 $this->messages[] = array(
61 $node->getNode('node')->getAttribute('value'),
62 $this->getReadDomainFromArguments($node->getNode('arguments'), 1),
63 );
64 } elseif (
65 $node instanceof \Twig_Node_Expression_Filter &&
66 'transchoice' === $node->getNode('filter')->getAttribute('value') &&
67 $node->getNode('node') instanceof \Twig_Node_Expression_Constant
68 ) {
69 // extract constant nodes with a trans filter
70 $this->messages[] = array(
71 $node->getNode('node')->getAttribute('value'),
72 $this->getReadDomainFromArguments($node->getNode('arguments'), 2),
73 );
74 } elseif ($node instanceof TransNode) {
75 // extract trans nodes
76 $this->messages[] = array(
77 $node->getNode('body')->getAttribute('data'),
78 $this->getReadDomainFromNode($node->getNode('domain')),
79 );
80 }
81
82 return $node;
83 }
84
85 /**
86 * {@inheritdoc}
87 */
88 public function leaveNode(\Twig_NodeInterface $node, \Twig_Environment $env)
89 {
90 return $node;
91 }
92
93 /**
94 * {@inheritdoc}
95 */
96 public function getPriority()
97 {
98 return 0;
99 }
100
101 /**
102 * @param \Twig_Node $arguments
103 * @param int $index
104 *
105 * @return string|null
106 */
107 private function getReadDomainFromArguments(\Twig_Node $arguments, $index)
108 {
109 if ($arguments->hasNode('domain')) {
110 $argument = $arguments->getNode('domain');
111 } elseif ($arguments->hasNode($index)) {
112 $argument = $arguments->getNode($index);
113 } else {
114 return null;
115 }
116
117 return $this->getReadDomainFromNode($argument);
118 }
119
120 /**
121 * @param \Twig_Node $node
122 *
123 * @return string|null
124 */
125 private function getReadDomainFromNode(\Twig_Node $node = null)
126 {
127 if (null === $node) {
128 return null;
129 }
130
131 if ($node instanceof \Twig_Node_Expression_Constant) {
132 return $node->getAttribute('value');
133 }
134
135 return self::UNDEFINED_DOMAIN;
136 }
137}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/README.md b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/README.md
new file mode 100644
index 00000000..e5663236
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/README.md
@@ -0,0 +1,15 @@
1Twig Bridge
2===========
3
4Provides integration for [Twig](http://twig.sensiolabs.org/) with various
5Symfony2 components.
6
7Resources
8---------
9
10If you want to run the unit tests, install dev dependencies before
11running PHPUnit:
12
13 $ cd path/to/Symfony/Bridge/Twig/
14 $ composer.phar install --dev
15 $ phpunit
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
new file mode 100644
index 00000000..453c29c6
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
@@ -0,0 +1,390 @@
1{# Widgets #}
2
3{% block form_widget %}
4{% spaceless %}
5 {% if compound %}
6 {{ block('form_widget_compound') }}
7 {% else %}
8 {{ block('form_widget_simple') }}
9 {% endif %}
10{% endspaceless %}
11{% endblock form_widget %}
12
13{% block form_widget_simple %}
14{% spaceless %}
15 {% set type = type|default('text') %}
16 <input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
17{% endspaceless %}
18{% endblock form_widget_simple %}
19
20{% block form_widget_compound %}
21{% spaceless %}
22 <div {{ block('widget_container_attributes') }}>
23 {% if form.parent is empty %}
24 {{ form_errors(form) }}
25 {% endif %}
26 {{ block('form_rows') }}
27 {{ form_rest(form) }}
28 </div>
29{% endspaceless %}
30{% endblock form_widget_compound %}
31
32{% block collection_widget %}
33{% spaceless %}
34 {% if prototype is defined %}
35 {% set attr = attr|merge({'data-prototype': form_row(prototype) }) %}
36 {% endif %}
37 {{ block('form_widget') }}
38{% endspaceless %}
39{% endblock collection_widget %}
40
41{% block textarea_widget %}
42{% spaceless %}
43 <textarea {{ block('widget_attributes') }}>{{ value }}</textarea>
44{% endspaceless %}
45{% endblock textarea_widget %}
46
47{% block choice_widget %}
48{% spaceless %}
49 {% if expanded %}
50 {{ block('choice_widget_expanded') }}
51 {% else %}
52 {{ block('choice_widget_collapsed') }}
53 {% endif %}
54{% endspaceless %}
55{% endblock choice_widget %}
56
57{% block choice_widget_expanded %}
58{% spaceless %}
59 <div {{ block('widget_container_attributes') }}>
60 {% for child in form %}
61 {{ form_widget(child) }}
62 {{ form_label(child) }}
63 {% endfor %}
64 </div>
65{% endspaceless %}
66{% endblock choice_widget_expanded %}
67
68{% block choice_widget_collapsed %}
69{% spaceless %}
70 <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
71 {% if empty_value is not none %}
72 <option {% if required %} disabled="disabled"{% if value is empty %} selected="selected"{% endif %}{% else %} value=""{% endif %}>{{ empty_value|trans({}, translation_domain) }}</option>
73 {% endif %}
74 {% if preferred_choices|length > 0 %}
75 {% set options = preferred_choices %}
76 {{ block('choice_widget_options') }}
77 {% if choices|length > 0 and separator is not none %}
78 <option disabled="disabled">{{ separator }}</option>
79 {% endif %}
80 {% endif %}
81 {% set options = choices %}
82 {{ block('choice_widget_options') }}
83 </select>
84{% endspaceless %}
85{% endblock choice_widget_collapsed %}
86
87{% block choice_widget_options %}
88{% spaceless %}
89 {% for group_label, choice in options %}
90 {% if choice is iterable %}
91 <optgroup label="{{ group_label|trans({}, translation_domain) }}">
92 {% set options = choice %}
93 {{ block('choice_widget_options') }}
94 </optgroup>
95 {% else %}
96 <option value="{{ choice.value }}"{% if choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice.label|trans({}, translation_domain) }}</option>
97 {% endif %}
98 {% endfor %}
99{% endspaceless %}
100{% endblock choice_widget_options %}
101
102{% block checkbox_widget %}
103{% spaceless %}
104 <input type="checkbox" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
105{% endspaceless %}
106{% endblock checkbox_widget %}
107
108{% block radio_widget %}
109{% spaceless %}
110 <input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
111{% endspaceless %}
112{% endblock radio_widget %}
113
114{% block datetime_widget %}
115{% spaceless %}
116 {% if widget == 'single_text' %}
117 {{ block('form_widget_simple') }}
118 {% else %}
119 <div {{ block('widget_container_attributes') }}>
120 {{ form_errors(form.date) }}
121 {{ form_errors(form.time) }}
122 {{ form_widget(form.date) }}
123 {{ form_widget(form.time) }}
124 </div>
125 {% endif %}
126{% endspaceless %}
127{% endblock datetime_widget %}
128
129{% block date_widget %}
130{% spaceless %}
131 {% if widget == 'single_text' %}
132 {{ block('form_widget_simple') }}
133 {% else %}
134 <div {{ block('widget_container_attributes') }}>
135 {{ date_pattern|replace({
136 '{{ year }}': form_widget(form.year),
137 '{{ month }}': form_widget(form.month),
138 '{{ day }}': form_widget(form.day),
139 })|raw }}
140 </div>
141 {% endif %}
142{% endspaceless %}
143{% endblock date_widget %}
144
145{% block time_widget %}
146{% spaceless %}
147 {% if widget == 'single_text' %}
148 {{ block('form_widget_simple') }}
149 {% else %}
150 {% set vars = widget == 'text' ? { 'attr': { 'size': 1 }} : {} %}
151 <div {{ block('widget_container_attributes') }}>
152 {{ form_widget(form.hour, vars) }}{% if with_minutes %}:{{ form_widget(form.minute, vars) }}{% endif %}{% if with_seconds %}:{{ form_widget(form.second, vars) }}{% endif %}
153 </div>
154 {% endif %}
155{% endspaceless %}
156{% endblock time_widget %}
157
158{% block number_widget %}
159{% spaceless %}
160 {# type="number" doesn't work with floats #}
161 {% set type = type|default('text') %}
162 {{ block('form_widget_simple') }}
163{% endspaceless %}
164{% endblock number_widget %}
165
166{% block integer_widget %}
167{% spaceless %}
168 {% set type = type|default('number') %}
169 {{ block('form_widget_simple') }}
170{% endspaceless %}
171{% endblock integer_widget %}
172
173{% block money_widget %}
174{% spaceless %}
175 {{ money_pattern|replace({ '{{ widget }}': block('form_widget_simple') })|raw }}
176{% endspaceless %}
177{% endblock money_widget %}
178
179{% block url_widget %}
180{% spaceless %}
181 {% set type = type|default('url') %}
182 {{ block('form_widget_simple') }}
183{% endspaceless %}
184{% endblock url_widget %}
185
186{% block search_widget %}
187{% spaceless %}
188 {% set type = type|default('search') %}
189 {{ block('form_widget_simple') }}
190{% endspaceless %}
191{% endblock search_widget %}
192
193{% block percent_widget %}
194{% spaceless %}
195 {% set type = type|default('text') %}
196 {{ block('form_widget_simple') }} %
197{% endspaceless %}
198{% endblock percent_widget %}
199
200{% block password_widget %}
201{% spaceless %}
202 {% set type = type|default('password') %}
203 {{ block('form_widget_simple') }}
204{% endspaceless %}
205{% endblock password_widget %}
206
207{% block hidden_widget %}
208{% spaceless %}
209 {% set type = type|default('hidden') %}
210 {{ block('form_widget_simple') }}
211{% endspaceless %}
212{% endblock hidden_widget %}
213
214{% block email_widget %}
215{% spaceless %}
216 {% set type = type|default('email') %}
217 {{ block('form_widget_simple') }}
218{% endspaceless %}
219{% endblock email_widget %}
220
221{% block button_widget %}
222{% spaceless %}
223 {% if label is empty %}
224 {% set label = name|humanize %}
225 {% endif %}
226 <button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ label|trans({}, translation_domain) }}</button>
227{% endspaceless %}
228{% endblock button_widget %}
229
230{% block submit_widget %}
231{% spaceless %}
232 {% set type = type|default('submit') %}
233 {{ block('button_widget') }}
234{% endspaceless %}
235{% endblock submit_widget %}
236
237{% block reset_widget %}
238{% spaceless %}
239 {% set type = type|default('reset') %}
240 {{ block('button_widget') }}
241{% endspaceless %}
242{% endblock reset_widget %}
243
244{# Labels #}
245
246{% block form_label %}
247{% spaceless %}
248 {% if label is not sameas(false) %}
249 {% if not compound %}
250 {% set label_attr = label_attr|merge({'for': id}) %}
251 {% endif %}
252 {% if required %}
253 {% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
254 {% endif %}
255 {% if label is empty %}
256 {% set label = name|humanize %}
257 {% endif %}
258 <label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label>
259 {% endif %}
260{% endspaceless %}
261{% endblock form_label %}
262
263{% block button_label %}{% endblock %}
264
265{# Rows #}
266
267{% block repeated_row %}
268{% spaceless %}
269 {#
270 No need to render the errors here, as all errors are mapped
271 to the first child (see RepeatedTypeValidatorExtension).
272 #}
273 {{ block('form_rows') }}
274{% endspaceless %}
275{% endblock repeated_row %}
276
277{% block form_row %}
278{% spaceless %}
279 <div>
280 {{ form_label(form) }}
281 {{ form_errors(form) }}
282 {{ form_widget(form) }}
283 </div>
284{% endspaceless %}
285{% endblock form_row %}
286
287{% block button_row %}
288{% spaceless %}
289 <div>
290 {{ form_widget(form) }}
291 </div>
292{% endspaceless %}
293{% endblock button_row %}
294
295{% block hidden_row %}
296 {{ form_widget(form) }}
297{% endblock hidden_row %}
298
299{# Misc #}
300
301{% block form %}
302{% spaceless %}
303 {{ form_start(form) }}
304 {{ form_widget(form) }}
305 {{ form_end(form) }}
306{% endspaceless %}
307{% endblock form %}
308
309{% block form_start %}
310{% spaceless %}
311 {% set method = method|upper %}
312 {% if method in ["GET", "POST"] %}
313 {% set form_method = method %}
314 {% else %}
315 {% set form_method = "POST" %}
316 {% endif %}
317 <form method="{{ form_method|lower }}" action="{{ action }}"{% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}{% if multipart %} enctype="multipart/form-data"{% endif %}>
318 {% if form_method != method %}
319 <input type="hidden" name="_method" value="{{ method }}" />
320 {% endif %}
321{% endspaceless %}
322{% endblock form_start %}
323
324{% block form_end %}
325{% spaceless %}
326 {% if not render_rest is defined or render_rest %}
327 {{ form_rest(form) }}
328 {% endif %}
329 </form>
330{% endspaceless %}
331{% endblock form_end %}
332
333{% block form_enctype %}
334{% spaceless %}
335 {% if multipart %}enctype="multipart/form-data"{% endif %}
336{% endspaceless %}
337{% endblock form_enctype %}
338
339{% block form_errors %}
340{% spaceless %}
341 {% if errors|length > 0 %}
342 <ul>
343 {% for error in errors %}
344 <li>{{ error.message }}</li>
345 {% endfor %}
346 </ul>
347 {% endif %}
348{% endspaceless %}
349{% endblock form_errors %}
350
351{% block form_rest %}
352{% spaceless %}
353 {% for child in form %}
354 {% if not child.rendered %}
355 {{ form_row(child) }}
356 {% endif %}
357 {% endfor %}
358{% endspaceless %}
359{% endblock form_rest %}
360
361{# Support #}
362
363{% block form_rows %}
364{% spaceless %}
365 {% for child in form %}
366 {{ form_row(child) }}
367 {% endfor %}
368{% endspaceless %}
369{% endblock form_rows %}
370
371{% block widget_attributes %}
372{% spaceless %}
373 id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
374 {% for attrname, attrvalue in attr %}{% if attrname in ['placeholder', 'title'] %}{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}" {% else %}{{ attrname }}="{{ attrvalue }}" {% endif %}{% endfor %}
375{% endspaceless %}
376{% endblock widget_attributes %}
377
378{% block widget_container_attributes %}
379{% spaceless %}
380 {% if id is not empty %}id="{{ id }}" {% endif %}
381 {% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
382{% endspaceless %}
383{% endblock widget_container_attributes %}
384
385{% block button_attributes %}
386{% spaceless %}
387 id="{{ id }}" name="{{ full_name }}"{% if disabled %} disabled="disabled"{% endif %}
388 {% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
389{% endspaceless %}
390{% endblock button_attributes %}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig
new file mode 100644
index 00000000..aed4f8d7
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig
@@ -0,0 +1,52 @@
1{% use "form_div_layout.html.twig" %}
2
3{% block form_row %}
4{% spaceless %}
5 <tr>
6 <td>
7 {{ form_label(form) }}
8 </td>
9 <td>
10 {{ form_errors(form) }}
11 {{ form_widget(form) }}
12 </td>
13 </tr>
14{% endspaceless %}
15{% endblock form_row %}
16
17{% block button_row %}
18{% spaceless %}
19 <tr>
20 <td></td>
21 <td>
22 {{ form_widget(form) }}
23 </td>
24 </tr>
25{% endspaceless %}
26{% endblock button_row %}
27
28{% block hidden_row %}
29{% spaceless %}
30 <tr style="display: none">
31 <td colspan="2">
32 {{ form_widget(form) }}
33 </td>
34 </tr>
35{% endspaceless %}
36{% endblock hidden_row %}
37
38{% block form_widget_compound %}
39{% spaceless %}
40 <table {{ block('widget_container_attributes') }}>
41 {% if form.parent is empty and errors|length > 0 %}
42 <tr>
43 <td colspan="2">
44 {{ form_errors(form) }}
45 </td>
46 </tr>
47 {% endif %}
48 {{ block('form_rows') }}
49 {{ form_rest(form) }}
50 </table>
51{% endspaceless %}
52{% endblock form_widget_compound %}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php
new file mode 100644
index 00000000..d9356514
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php
@@ -0,0 +1,69 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Extension;
13
14use Symfony\Bridge\Twig\Extension\CodeExtension;
15
16class CodeExtensionTest extends \PHPUnit_Framework_TestCase
17{
18 protected $helper;
19
20 public function testFormatFile()
21 {
22 $expected = sprintf('<a href="txmt://open?url=file://%s&amp;line=25" title="Click to open this file" class="file_link">%s at line 25</a>', __FILE__, __FILE__);
23 $this->assertEquals($expected, $this->getExtension()->formatFile(__FILE__, 25));
24 }
25
26 /**
27 * @dataProvider getClassNameProvider
28 */
29 public function testGettingClassAbbreviation($class, $abbr)
30 {
31 $this->assertEquals($this->getExtension()->abbrClass($class), $abbr);
32 }
33
34 /**
35 * @dataProvider getMethodNameProvider
36 */
37 public function testGettingMethodAbbreviation($method, $abbr)
38 {
39 $this->assertEquals($this->getExtension()->abbrMethod($method), $abbr);
40 }
41
42 public function getClassNameProvider()
43 {
44 return array(
45 array('F\Q\N\Foo', '<abbr title="F\Q\N\Foo">Foo</abbr>'),
46 array('Bare', '<abbr title="Bare">Bare</abbr>'),
47 );
48 }
49
50 public function getMethodNameProvider()
51 {
52 return array(
53 array('F\Q\N\Foo::Method', '<abbr title="F\Q\N\Foo">Foo</abbr>::Method()'),
54 array('Bare::Method', '<abbr title="Bare">Bare</abbr>::Method()'),
55 array('Closure', '<abbr title="Closure">Closure</abbr>'),
56 array('Method', '<abbr title="Method">Method</abbr>()')
57 );
58 }
59
60 public function testGetName()
61 {
62 $this->assertEquals('code', $this->getExtension()->getName());
63 }
64
65 protected function getExtension()
66 {
67 return new CodeExtension('txmt://open?url=file://%f&line=%l', '/root', 'UTF-8');
68 }
69}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubFilesystemLoader.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubFilesystemLoader.php
new file mode 100644
index 00000000..36c61cd6
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubFilesystemLoader.php
@@ -0,0 +1,30 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Extension\Fixtures;
13
14// Preventing autoloader throwing E_FATAL when Twig is now available
15if (!class_exists('Twig_Environment')) {
16 class StubFilesystemLoader
17 {
18 }
19} else {
20 class StubFilesystemLoader extends \Twig_Loader_Filesystem
21 {
22 protected function findTemplate($name)
23 {
24 // strip away bundle name
25 $parts = explode(':', $name);
26
27 return parent::findTemplate(end($parts));
28 }
29 }
30}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php
new file mode 100644
index 00000000..b7d011b5
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php
@@ -0,0 +1,35 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Extension\Fixtures;
13
14use Symfony\Component\Translation\TranslatorInterface;
15
16class StubTranslator implements TranslatorInterface
17{
18 public function trans($id, array $parameters = array(), $domain = null, $locale = null)
19 {
20 return '[trans]'.$id.'[/trans]';
21 }
22
23 public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
24 {
25 return '[trans]'.$id.'[/trans]';
26 }
27
28 public function setLocale($locale)
29 {
30 }
31
32 public function getLocale()
33 {
34 }
35}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php
new file mode 100644
index 00000000..c5c134bc
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php
@@ -0,0 +1,209 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Extension;
13
14use Symfony\Bridge\Twig\Extension\FormExtension;
15use Symfony\Bridge\Twig\Form\TwigRenderer;
16use Symfony\Bridge\Twig\Form\TwigRendererEngine;
17use Symfony\Bridge\Twig\Extension\TranslationExtension;
18use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
19use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
20use Symfony\Component\Form\FormView;
21use Symfony\Component\Form\Extension\Core\View\ChoiceView;
22use Symfony\Component\Form\Tests\AbstractDivLayoutTest;
23
24class FormExtensionDivLayoutTest extends AbstractDivLayoutTest
25{
26 /**
27 * @var FormExtension
28 */
29 protected $extension;
30
31 protected function setUp()
32 {
33 if (!class_exists('Symfony\Component\Locale\Locale')) {
34 $this->markTestSkipped('The "Locale" component is not available');
35 }
36
37 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
38 $this->markTestSkipped('The "EventDispatcher" component is not available');
39 }
40
41 if (!class_exists('Symfony\Component\Form\Form')) {
42 $this->markTestSkipped('The "Form" component is not available');
43 }
44
45 if (!class_exists('Twig_Environment')) {
46 $this->markTestSkipped('Twig is not available.');
47 }
48
49 parent::setUp();
50
51 $rendererEngine = new TwigRendererEngine(array(
52 'form_div_layout.html.twig',
53 'custom_widgets.html.twig',
54 ));
55 $renderer = new TwigRenderer($rendererEngine, $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'));
56
57 $this->extension = new FormExtension($renderer);
58
59 $loader = new StubFilesystemLoader(array(
60 __DIR__.'/../../Resources/views/Form',
61 __DIR__,
62 ));
63
64 $environment = new \Twig_Environment($loader, array('strict_variables' => true));
65 $environment->addExtension(new TranslationExtension(new StubTranslator()));
66 $environment->addGlobal('global', '');
67 $environment->addExtension($this->extension);
68
69 $this->extension->initRuntime($environment);
70 }
71
72 protected function tearDown()
73 {
74 parent::tearDown();
75
76 $this->extension = null;
77 }
78
79 public function testThemeBlockInheritanceUsingUse()
80 {
81 $view = $this->factory
82 ->createNamed('name', 'email')
83 ->createView()
84 ;
85
86 $this->setTheme($view, array('theme_use.html.twig'));
87
88 $this->assertMatchesXpath(
89 $this->renderWidget($view),
90 '/input[@type="email"][@rel="theme"]'
91 );
92 }
93
94 public function testThemeBlockInheritanceUsingExtend()
95 {
96 $view = $this->factory
97 ->createNamed('name', 'email')
98 ->createView()
99 ;
100
101 $this->setTheme($view, array('theme_extends.html.twig'));
102
103 $this->assertMatchesXpath(
104 $this->renderWidget($view),
105 '/input[@type="email"][@rel="theme"]'
106 );
107 }
108
109 public function isSelectedChoiceProvider()
110 {
111 // The commented cases should not be necessary anymore, because the
112 // choice lists should assure that both values passed here are always
113 // strings
114 return array(
115// array(true, 0, 0),
116 array(true, '0', '0'),
117 array(true, '1', '1'),
118// array(true, false, 0),
119// array(true, true, 1),
120 array(true, '', ''),
121// array(true, null, ''),
122 array(true, '1.23', '1.23'),
123 array(true, 'foo', 'foo'),
124 array(true, 'foo10', 'foo10'),
125 array(true, 'foo', array(1, 'foo', 'foo10')),
126
127 array(false, 10, array(1, 'foo', 'foo10')),
128 array(false, 0, array(1, 'foo', 'foo10')),
129 );
130 }
131
132 /**
133 * @dataProvider isSelectedChoiceProvider
134 */
135 public function testIsChoiceSelected($expected, $choice, $value)
136 {
137 $choice = new ChoiceView($choice, $choice, $choice.' label');
138
139 $this->assertSame($expected, $this->extension->isSelectedChoice($choice, $value));
140 }
141
142 protected function renderForm(FormView $view, array $vars = array())
143 {
144 return (string) $this->extension->renderer->renderBlock($view, 'form', $vars);
145 }
146
147 protected function renderEnctype(FormView $view)
148 {
149 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
150 }
151
152 protected function renderLabel(FormView $view, $label = null, array $vars = array())
153 {
154 if ($label !== null) {
155 $vars += array('label' => $label);
156 }
157
158 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'label', $vars);
159 }
160
161 protected function renderErrors(FormView $view)
162 {
163 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'errors');
164 }
165
166 protected function renderWidget(FormView $view, array $vars = array())
167 {
168 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'widget', $vars);
169 }
170
171 protected function renderRow(FormView $view, array $vars = array())
172 {
173 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'row', $vars);
174 }
175
176 protected function renderRest(FormView $view, array $vars = array())
177 {
178 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
179 }
180
181 protected function renderStart(FormView $view, array $vars = array())
182 {
183 return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars);
184 }
185
186 protected function renderEnd(FormView $view, array $vars = array())
187 {
188 return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars);
189 }
190
191 protected function setTheme(FormView $view, array $themes)
192 {
193 $this->extension->renderer->setTheme($view, $themes);
194 }
195
196 public static function themeBlockInheritanceProvider()
197 {
198 return array(
199 array(array('theme.html.twig'))
200 );
201 }
202
203 public static function themeInheritanceProvider()
204 {
205 return array(
206 array(array('parent_label.html.twig'), array('child_label.html.twig'))
207 );
208 }
209}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php
new file mode 100644
index 00000000..99a78217
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php
@@ -0,0 +1,131 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Extension;
13
14use Symfony\Component\Form\FormView;
15use Symfony\Bridge\Twig\Form\TwigRenderer;
16use Symfony\Bridge\Twig\Form\TwigRendererEngine;
17use Symfony\Bridge\Twig\Extension\FormExtension;
18use Symfony\Bridge\Twig\Extension\TranslationExtension;
19use Symfony\Component\Form\Tests\AbstractTableLayoutTest;
20use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
21use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
22
23class FormExtensionTableLayoutTest extends AbstractTableLayoutTest
24{
25 /**
26 * @var FormExtension
27 */
28 protected $extension;
29
30 protected function setUp()
31 {
32 if (!class_exists('Symfony\Component\Locale\Locale')) {
33 $this->markTestSkipped('The "Locale" component is not available');
34 }
35
36 if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
37 $this->markTestSkipped('The "EventDispatcher" component is not available');
38 }
39
40 if (!class_exists('Symfony\Component\Form\Form')) {
41 $this->markTestSkipped('The "Form" component is not available');
42 }
43
44 if (!class_exists('Twig_Environment')) {
45 $this->markTestSkipped('Twig is not available.');
46 }
47
48 parent::setUp();
49
50 $rendererEngine = new TwigRendererEngine(array(
51 'form_table_layout.html.twig',
52 'custom_widgets.html.twig',
53 ));
54 $renderer = new TwigRenderer($rendererEngine, $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'));
55
56 $this->extension = new FormExtension($renderer);
57
58 $loader = new StubFilesystemLoader(array(
59 __DIR__.'/../../Resources/views/Form',
60 __DIR__,
61 ));
62
63 $environment = new \Twig_Environment($loader, array('strict_variables' => true));
64 $environment->addExtension(new TranslationExtension(new StubTranslator()));
65 $environment->addGlobal('global', '');
66 $environment->addExtension($this->extension);
67
68 $this->extension->initRuntime($environment);
69 }
70
71 protected function tearDown()
72 {
73 parent::tearDown();
74
75 $this->extension = null;
76 }
77
78 protected function renderForm(FormView $view, array $vars = array())
79 {
80 return (string) $this->extension->renderer->renderBlock($view, 'form', $vars);
81 }
82
83 protected function renderEnctype(FormView $view)
84 {
85 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
86 }
87
88 protected function renderLabel(FormView $view, $label = null, array $vars = array())
89 {
90 if ($label !== null) {
91 $vars += array('label' => $label);
92 }
93
94 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'label', $vars);
95 }
96
97 protected function renderErrors(FormView $view)
98 {
99 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'errors');
100 }
101
102 protected function renderWidget(FormView $view, array $vars = array())
103 {
104 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'widget', $vars);
105 }
106
107 protected function renderRow(FormView $view, array $vars = array())
108 {
109 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'row', $vars);
110 }
111
112 protected function renderRest(FormView $view, array $vars = array())
113 {
114 return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
115 }
116
117 protected function renderStart(FormView $view, array $vars = array())
118 {
119 return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars);
120 }
121
122 protected function renderEnd(FormView $view, array $vars = array())
123 {
124 return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars);
125 }
126
127 protected function setTheme(FormView $view, array $themes)
128 {
129 $this->extension->renderer->setTheme($view, $themes);
130 }
131}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php
new file mode 100644
index 00000000..077927cd
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php
@@ -0,0 +1,68 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Extension;
13
14use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
15use Symfony\Bridge\Twig\Tests\TestCase;
16use Symfony\Component\HttpFoundation\Request;
17use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
18
19class HttpKernelExtensionTest extends TestCase
20{
21 protected function setUp()
22 {
23 parent::setUp();
24
25 if (!class_exists('Symfony\Component\HttpKernel\HttpKernel')) {
26 $this->markTestSkipped('The "HttpKernel" component is not available');
27 }
28
29 if (!class_exists('Twig_Environment')) {
30 $this->markTestSkipped('Twig is not available.');
31 }
32 }
33
34 /**
35 * @expectedException \Twig_Error_Runtime
36 */
37 public function testFragmentWithError()
38 {
39 $kernel = $this->getFragmentHandler($this->throwException(new \Exception('foo')));
40
41 $loader = new \Twig_Loader_Array(array('index' => '{{ fragment("foo") }}'));
42 $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
43 $twig->addExtension(new HttpKernelExtension($kernel));
44
45 $this->renderTemplate($kernel);
46 }
47
48 protected function getFragmentHandler($return)
49 {
50 $strategy = $this->getMock('Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface');
51 $strategy->expects($this->once())->method('getName')->will($this->returnValue('inline'));
52 $strategy->expects($this->once())->method('render')->will($return);
53
54 $renderer = new FragmentHandler(array($strategy));
55 $renderer->setRequest(Request::create('/'));
56
57 return $renderer;
58 }
59
60 protected function renderTemplate(FragmentHandler $renderer, $template = '{{ render("foo") }}')
61 {
62 $loader = new \Twig_Loader_Array(array('index' => $template));
63 $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
64 $twig->addExtension(new HttpKernelExtension($renderer));
65
66 return $twig->render('index');
67 }
68}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/RoutingExtensionTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/RoutingExtensionTest.php
new file mode 100644
index 00000000..3c5d762c
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/RoutingExtensionTest.php
@@ -0,0 +1,60 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Extension;
13
14use Symfony\Bridge\Twig\Extension\RoutingExtension;
15use Symfony\Bridge\Twig\Tests\TestCase;
16
17class RoutingExtensionTest extends TestCase
18{
19 protected function setUp()
20 {
21 parent::setUp();
22
23 if (!class_exists('Symfony\Component\Routing\Route')) {
24 $this->markTestSkipped('The "Routing" component is not available');
25 }
26 }
27
28 /**
29 * @dataProvider getEscapingTemplates
30 */
31 public function testEscaping($template, $mustBeEscaped)
32 {
33 $twig = new \Twig_Environment(null, array('debug' => true, 'cache' => false, 'autoescape' => true, 'optimizations' => 0));
34 $twig->addExtension(new RoutingExtension($this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface')));
35
36 $nodes = $twig->parse($twig->tokenize($template));
37
38 $this->assertSame($mustBeEscaped, $nodes->getNode('body')->getNode(0)->getNode('expr') instanceof \Twig_Node_Expression_Filter);
39 }
40
41 public function getEscapingTemplates()
42 {
43 return array(
44 array('{{ path("foo") }}', false),
45 array('{{ path("foo", {}) }}', false),
46 array('{{ path("foo", { foo: "foo" }) }}', false),
47 array('{{ path("foo", foo) }}', true),
48 array('{{ path("foo", { foo: foo }) }}', true),
49 array('{{ path("foo", { foo: ["foo", "bar"] }) }}', true),
50 array('{{ path("foo", { foo: "foo", bar: "bar" }) }}', true),
51
52 array('{{ path(name = "foo", parameters = {}) }}', false),
53 array('{{ path(name = "foo", parameters = { foo: "foo" }) }}', false),
54 array('{{ path(name = "foo", parameters = foo) }}', true),
55 array('{{ path(name = "foo", parameters = { foo: ["foo", "bar"] }) }}', true),
56 array('{{ path(name = "foo", parameters = { foo: foo }) }}', true),
57 array('{{ path(name = "foo", parameters = { foo: "foo", bar: "bar" }) }}', true),
58 );
59 }
60}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php
new file mode 100644
index 00000000..2b9c5533
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php
@@ -0,0 +1,151 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Extension;
13
14use Symfony\Bridge\Twig\Extension\TranslationExtension;
15use Symfony\Component\Translation\Translator;
16use Symfony\Component\Translation\MessageSelector;
17use Symfony\Component\Translation\Loader\ArrayLoader;
18use Symfony\Bridge\Twig\Tests\TestCase;
19
20class TranslationExtensionTest extends TestCase
21{
22 protected function setUp()
23 {
24 parent::setUp();
25
26 if (!class_exists('Symfony\Component\Translation\Translator')) {
27 $this->markTestSkipped('The "Translation" component is not available');
28 }
29
30 if (!class_exists('Twig_Environment')) {
31 $this->markTestSkipped('Twig is not available.');
32 }
33 }
34
35 public function testEscaping()
36 {
37 $output = $this->getTemplate('{% trans %}Percent: %value%%% (%msg%){% endtrans %}')->render(array('value' => 12, 'msg' => 'approx.'));
38
39 $this->assertEquals('Percent: 12% (approx.)', $output);
40 }
41
42 /**
43 * @dataProvider getTransTests
44 */
45 public function testTrans($template, $expected, array $variables = array())
46 {
47 if ($expected != $this->getTemplate($template)->render($variables)) {
48 print $template."\n";
49 $loader = new \Twig_Loader_Array(array('index' => $template));
50 $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
51 $twig->addExtension(new TranslationExtension(new Translator('en', new MessageSelector())));
52
53 echo $twig->compile($twig->parse($twig->tokenize($twig->getLoader()->getSource('index'), 'index')))."\n\n";
54 $this->assertEquals($expected, $this->getTemplate($template)->render($variables));
55 }
56
57 $this->assertEquals($expected, $this->getTemplate($template)->render($variables));
58 }
59
60 public function getTransTests()
61 {
62 return array(
63 // trans tag
64 array('{% trans %}Hello{% endtrans %}', 'Hello'),
65 array('{% trans %}%name%{% endtrans %}', 'Symfony2', array('name' => 'Symfony2')),
66
67 array('{% trans from elsewhere %}Hello{% endtrans %}', 'Hello'),
68
69 array('{% trans %}Hello %name%{% endtrans %}', 'Hello Symfony2', array('name' => 'Symfony2')),
70 array('{% trans with { \'%name%\': \'Symfony2\' } %}Hello %name%{% endtrans %}', 'Hello Symfony2'),
71 array('{% set vars = { \'%name%\': \'Symfony2\' } %}{% trans with vars %}Hello %name%{% endtrans %}', 'Hello Symfony2'),
72
73 array('{% trans into "fr"%}Hello{% endtrans %}', 'Hello'),
74
75 // transchoice
76 array('{% transchoice count from "messages" %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
77 'There is no apples', array('count' => 0)),
78 array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
79 'There is 5 apples', array('count' => 5)),
80 array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
81 'There is 5 apples (Symfony2)', array('count' => 5, 'name' => 'Symfony2')),
82 array('{% transchoice count with { \'%name%\': \'Symfony2\' } %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
83 'There is 5 apples (Symfony2)', array('count' => 5)),
84 array('{% transchoice count into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
85 'There is no apples', array('count' => 0)),
86
87 // trans filter
88 array('{{ "Hello"|trans }}', 'Hello'),
89 array('{{ name|trans }}', 'Symfony2', array('name' => 'Symfony2')),
90 array('{{ hello|trans({ \'%name%\': \'Symfony2\' }) }}', 'Hello Symfony2', array('hello' => 'Hello %name%')),
91 array('{% set vars = { \'%name%\': \'Symfony2\' } %}{{ hello|trans(vars) }}', 'Hello Symfony2', array('hello' => 'Hello %name%')),
92 array('{{ "Hello"|trans({}, "messages", "fr") }}', 'Hello'),
93
94 // transchoice filter
95 array('{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count) }}', 'There is 5 apples', array('count' => 5)),
96 array('{{ text|transchoice(5, {\'%name%\': \'Symfony2\'}) }}', 'There is 5 apples (Symfony2)', array('text' => '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%)')),
97 array('{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count, {}, "messages", "fr") }}', 'There is 5 apples', array('count' => 5)),
98 );
99 }
100
101 public function testDefaultTranslationDomain()
102 {
103 $templates = array(
104 'index' => '
105 {%- extends "base" %}
106
107 {%- trans_default_domain "foo" %}
108
109 {%- block content %}
110 {%- trans %}foo{% endtrans %}
111 {%- trans from "custom" %}foo{% endtrans %}
112 {{- "foo"|trans }}
113 {{- "foo"|trans({}, "custom") }}
114 {{- "foo"|transchoice(1) }}
115 {{- "foo"|transchoice(1, {}, "custom") }}
116 {% endblock %}
117 ',
118
119 'base' => '
120 {%- block content "" %}
121 ',
122 );
123
124 $translator = new Translator('en', new MessageSelector());
125 $translator->addLoader('array', new ArrayLoader());
126 $translator->addResource('array', array('foo' => 'foo (messages)'), 'en');
127 $translator->addResource('array', array('foo' => 'foo (custom)'), 'en', 'custom');
128 $translator->addResource('array', array('foo' => 'foo (foo)'), 'en', 'foo');
129
130 $template = $this->getTemplate($templates, $translator);
131
132 $this->assertEquals('foo (foo)foo (custom)foo (foo)foo (custom)foo (foo)foo (custom)', trim($template->render(array())));
133 }
134
135 protected function getTemplate($template, $translator = null)
136 {
137 if (null === $translator) {
138 $translator = new Translator('en', new MessageSelector());
139 }
140
141 if (is_array($template)) {
142 $loader = new \Twig_Loader_Array($template);
143 } else {
144 $loader = new \Twig_Loader_Array(array('index' => $template));
145 }
146 $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
147 $twig->addExtension(new TranslationExtension($translator));
148
149 return $twig->loadTemplate('index');
150 }
151}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/child_label.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/child_label.html.twig
new file mode 100644
index 00000000..8c7c2489
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/child_label.html.twig
@@ -0,0 +1,3 @@
1{% block form_label %}
2 <label>{{ global }}child</label>
3{% endblock form_label %}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/custom_widgets.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/custom_widgets.html.twig
new file mode 100644
index 00000000..12fd7c66
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/custom_widgets.html.twig
@@ -0,0 +1,16 @@
1{% block _text_id_widget %}
2{% spaceless %}
3 <div id="container">
4 {{ form_widget(form) }}
5 </div>
6{% endspaceless %}
7{% endblock _text_id_widget %}
8
9{% block _name_entry_label %}
10{% spaceless %}
11 {% if label is empty %}
12 {% set label = name|humanize %}
13 {% endif %}
14 <label>Custom label: {{ label|trans({}, translation_domain) }}</label>
15{% endspaceless %}
16{% endblock _name_entry_label %}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/parent_label.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/parent_label.html.twig
new file mode 100644
index 00000000..e96278b8
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/parent_label.html.twig
@@ -0,0 +1,3 @@
1{% block form_label %}
2 <label>parent</label>
3{% endblock form_label %}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme.html.twig
new file mode 100644
index 00000000..da1c1b64
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme.html.twig
@@ -0,0 +1,6 @@
1{% block form_widget_simple %}
2{% spaceless %}
3 {% set type = type|default('text') %}
4 <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
5{% endspaceless %}
6{% endblock form_widget_simple %}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_extends.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_extends.html.twig
new file mode 100644
index 00000000..8c719867
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_extends.html.twig
@@ -0,0 +1,8 @@
1{% extends 'form_div_layout.html.twig' %}
2
3{% block form_widget_simple %}
4{% spaceless %}
5 {% set type = type|default('text') %}
6 <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
7{% endspaceless %}
8{% endblock form_widget_simple %}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_use.html.twig b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_use.html.twig
new file mode 100644
index 00000000..d485b8d0
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Extension/theme_use.html.twig
@@ -0,0 +1,8 @@
1{% use 'form_div_layout.html.twig' %}
2
3{% block form_widget_simple %}
4{% spaceless %}
5 {% set type = type|default('text') %}
6 <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
7{% endspaceless %}
8{% endblock form_widget_simple %}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/FormThemeTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/FormThemeTest.php
new file mode 100644
index 00000000..90afef12
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/FormThemeTest.php
@@ -0,0 +1,85 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Node;
13
14use Symfony\Bridge\Twig\Tests\TestCase;
15use Symfony\Bridge\Twig\Node\FormThemeNode;
16
17class FormThemeTest extends TestCase
18{
19 protected function setUp()
20 {
21 parent::setUp();
22
23 if (version_compare(\Twig_Environment::VERSION, '1.5.0', '<')) {
24 $this->markTestSkipped('Requires Twig version to be at least 1.5.0.');
25 }
26 }
27
28 public function testConstructor()
29 {
30 $form = new \Twig_Node_Expression_Name('form', 0);
31 $resources = new \Twig_Node(array(
32 new \Twig_Node_Expression_Constant('tpl1', 0),
33 new \Twig_Node_Expression_Constant('tpl2', 0)
34 ));
35
36 $node = new FormThemeNode($form, $resources, 0);
37
38 $this->assertEquals($form, $node->getNode('form'));
39 $this->assertEquals($resources, $node->getNode('resources'));
40 }
41
42 public function testCompile()
43 {
44 $form = new \Twig_Node_Expression_Name('form', 0);
45 $resources = new \Twig_Node_Expression_Array(array(
46 new \Twig_Node_Expression_Constant(0, 0),
47 new \Twig_Node_Expression_Constant('tpl1', 0),
48 new \Twig_Node_Expression_Constant(1, 0),
49 new \Twig_Node_Expression_Constant('tpl2', 0)
50 ), 0);
51
52 $node = new FormThemeNode($form, $resources, 0);
53
54 $compiler = new \Twig_Compiler(new \Twig_Environment());
55
56 $this->assertEquals(
57 sprintf(
58 '$this->env->getExtension(\'form\')->renderer->setTheme(%s, array(0 => "tpl1", 1 => "tpl2"));',
59 $this->getVariableGetter('form')
60 ),
61 trim($compiler->compile($node)->getSource())
62 );
63
64 $resources = new \Twig_Node_Expression_Constant('tpl1', 0);
65
66 $node = new FormThemeNode($form, $resources, 0);
67
68 $this->assertEquals(
69 sprintf(
70 '$this->env->getExtension(\'form\')->renderer->setTheme(%s, "tpl1");',
71 $this->getVariableGetter('form')
72 ),
73 trim($compiler->compile($node)->getSource())
74 );
75 }
76
77 protected function getVariableGetter($name)
78 {
79 if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
80 return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name);
81 }
82
83 return sprintf('$this->getContext($context, "%s")', $name);
84 }
85}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php
new file mode 100644
index 00000000..c1f247ca
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php
@@ -0,0 +1,282 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Node;
13
14use Symfony\Bridge\Twig\Tests\TestCase;
15use Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode;
16
17class SearchAndRenderBlockNodeTest extends TestCase
18{
19 protected function setUp()
20 {
21 parent::setUp();
22
23 if (version_compare(\Twig_Environment::VERSION, '1.5.0', '<')) {
24 $this->markTestSkipped('Requires Twig version to be at least 1.5.0.');
25 }
26 }
27
28 public function testCompileWidget()
29 {
30 $arguments = new \Twig_Node(array(
31 new \Twig_Node_Expression_Name('form', 0),
32 ));
33
34 $node = new SearchAndRenderBlockNode('form_widget', $arguments, 0);
35
36 $compiler = new \Twig_Compiler(new \Twig_Environment());
37
38 $this->assertEquals(
39 sprintf(
40 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'widget\')',
41 $this->getVariableGetter('form')
42 ),
43 trim($compiler->compile($node)->getSource())
44 );
45 }
46
47 public function testCompileWidgetWithVariables()
48 {
49 $arguments = new \Twig_Node(array(
50 new \Twig_Node_Expression_Name('form', 0),
51 new \Twig_Node_Expression_Array(array(
52 new \Twig_Node_Expression_Constant('foo', 0),
53 new \Twig_Node_Expression_Constant('bar', 0),
54 ), 0),
55 ));
56
57 $node = new SearchAndRenderBlockNode('form_widget', $arguments, 0);
58
59 $compiler = new \Twig_Compiler(new \Twig_Environment());
60
61 $this->assertEquals(
62 sprintf(
63 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'widget\', array("foo" => "bar"))',
64 $this->getVariableGetter('form')
65 ),
66 trim($compiler->compile($node)->getSource())
67 );
68 }
69
70 public function testCompileLabelWithLabel()
71 {
72 $arguments = new \Twig_Node(array(
73 new \Twig_Node_Expression_Name('form', 0),
74 new \Twig_Node_Expression_Constant('my label', 0),
75 ));
76
77 $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
78
79 $compiler = new \Twig_Compiler(new \Twig_Environment());
80
81 $this->assertEquals(
82 sprintf(
83 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("label" => "my label"))',
84 $this->getVariableGetter('form')
85 ),
86 trim($compiler->compile($node)->getSource())
87 );
88 }
89
90 public function testCompileLabelWithNullLabel()
91 {
92 $arguments = new \Twig_Node(array(
93 new \Twig_Node_Expression_Name('form', 0),
94 new \Twig_Node_Expression_Constant(null, 0),
95 ));
96
97 $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
98
99 $compiler = new \Twig_Compiler(new \Twig_Environment());
100
101 // "label" => null must not be included in the output!
102 // Otherwise the default label is overwritten with null.
103 $this->assertEquals(
104 sprintf(
105 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\')',
106 $this->getVariableGetter('form')
107 ),
108 trim($compiler->compile($node)->getSource())
109 );
110 }
111
112 public function testCompileLabelWithEmptyStringLabel()
113 {
114 $arguments = new \Twig_Node(array(
115 new \Twig_Node_Expression_Name('form', 0),
116 new \Twig_Node_Expression_Constant('', 0),
117 ));
118
119 $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
120
121 $compiler = new \Twig_Compiler(new \Twig_Environment());
122
123 // "label" => null must not be included in the output!
124 // Otherwise the default label is overwritten with null.
125 $this->assertEquals(
126 sprintf(
127 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\')',
128 $this->getVariableGetter('form')
129 ),
130 trim($compiler->compile($node)->getSource())
131 );
132 }
133
134 public function testCompileLabelWithDefaultLabel()
135 {
136 $arguments = new \Twig_Node(array(
137 new \Twig_Node_Expression_Name('form', 0),
138 ));
139
140 $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
141
142 $compiler = new \Twig_Compiler(new \Twig_Environment());
143
144 $this->assertEquals(
145 sprintf(
146 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\')',
147 $this->getVariableGetter('form')
148 ),
149 trim($compiler->compile($node)->getSource())
150 );
151 }
152
153 public function testCompileLabelWithAttributes()
154 {
155 $arguments = new \Twig_Node(array(
156 new \Twig_Node_Expression_Name('form', 0),
157 new \Twig_Node_Expression_Constant(null, 0),
158 new \Twig_Node_Expression_Array(array(
159 new \Twig_Node_Expression_Constant('foo', 0),
160 new \Twig_Node_Expression_Constant('bar', 0),
161 ), 0),
162 ));
163
164 $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
165
166 $compiler = new \Twig_Compiler(new \Twig_Environment());
167
168 // "label" => null must not be included in the output!
169 // Otherwise the default label is overwritten with null.
170 // https://github.com/symfony/symfony/issues/5029
171 $this->assertEquals(
172 sprintf(
173 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("foo" => "bar"))',
174 $this->getVariableGetter('form')
175 ),
176 trim($compiler->compile($node)->getSource())
177 );
178 }
179
180 public function testCompileLabelWithLabelAndAttributes()
181 {
182 $arguments = new \Twig_Node(array(
183 new \Twig_Node_Expression_Name('form', 0),
184 new \Twig_Node_Expression_Constant('value in argument', 0),
185 new \Twig_Node_Expression_Array(array(
186 new \Twig_Node_Expression_Constant('foo', 0),
187 new \Twig_Node_Expression_Constant('bar', 0),
188 new \Twig_Node_Expression_Constant('label', 0),
189 new \Twig_Node_Expression_Constant('value in attributes', 0),
190 ), 0),
191 ));
192
193 $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
194
195 $compiler = new \Twig_Compiler(new \Twig_Environment());
196
197 $this->assertEquals(
198 sprintf(
199 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("foo" => "bar", "label" => "value in argument"))',
200 $this->getVariableGetter('form')
201 ),
202 trim($compiler->compile($node)->getSource())
203 );
204 }
205
206 public function testCompileLabelWithLabelThatEvaluatesToNull()
207 {
208 $arguments = new \Twig_Node(array(
209 new \Twig_Node_Expression_Name('form', 0),
210 new \Twig_Node_Expression_Conditional(
211 // if
212 new \Twig_Node_Expression_Constant(true, 0),
213 // then
214 new \Twig_Node_Expression_Constant(null, 0),
215 // else
216 new \Twig_Node_Expression_Constant(null, 0),
217 0
218 ),
219 ));
220
221 $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
222
223 $compiler = new \Twig_Compiler(new \Twig_Environment());
224
225 // "label" => null must not be included in the output!
226 // Otherwise the default label is overwritten with null.
227 // https://github.com/symfony/symfony/issues/5029
228 $this->assertEquals(
229 sprintf(
230 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? array() : array("label" => $_label_)))',
231 $this->getVariableGetter('form')
232 ),
233 trim($compiler->compile($node)->getSource())
234 );
235 }
236
237 public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes()
238 {
239 $arguments = new \Twig_Node(array(
240 new \Twig_Node_Expression_Name('form', 0),
241 new \Twig_Node_Expression_Conditional(
242 // if
243 new \Twig_Node_Expression_Constant(true, 0),
244 // then
245 new \Twig_Node_Expression_Constant(null, 0),
246 // else
247 new \Twig_Node_Expression_Constant(null, 0),
248 0
249 ),
250 new \Twig_Node_Expression_Array(array(
251 new \Twig_Node_Expression_Constant('foo', 0),
252 new \Twig_Node_Expression_Constant('bar', 0),
253 new \Twig_Node_Expression_Constant('label', 0),
254 new \Twig_Node_Expression_Constant('value in attributes', 0),
255 ), 0),
256 ));
257
258 $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
259
260 $compiler = new \Twig_Compiler(new \Twig_Environment());
261
262 // "label" => null must not be included in the output!
263 // Otherwise the default label is overwritten with null.
264 // https://github.com/symfony/symfony/issues/5029
265 $this->assertEquals(
266 sprintf(
267 '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("foo" => "bar", "label" => "value in attributes") + (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? array() : array("label" => $_label_)))',
268 $this->getVariableGetter('form')
269 ),
270 trim($compiler->compile($node)->getSource())
271 );
272 }
273
274 protected function getVariableGetter($name)
275 {
276 if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
277 return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name);
278 }
279
280 return sprintf('$this->getContext($context, "%s")', $name);
281 }
282}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/ScopeTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/ScopeTest.php
new file mode 100644
index 00000000..bcae5919
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/ScopeTest.php
@@ -0,0 +1,25 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
13
14use Symfony\Bridge\Twig\NodeVisitor\Scope;
15use Symfony\Bridge\Twig\Tests\TestCase;
16
17class ScopeTest extends TestCase
18{
19 public function testScopeInitiation()
20 {
21 $scope = new Scope();
22 $scope->enter();
23 $this->assertNull($scope->get('test'));
24 }
25}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationDefaultDomainNodeVisitorTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationDefaultDomainNodeVisitorTest.php
new file mode 100644
index 00000000..24a6215e
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationDefaultDomainNodeVisitorTest.php
@@ -0,0 +1,83 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
13
14use Symfony\Bridge\Twig\NodeVisitor\TranslationDefaultDomainNodeVisitor;
15use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
16use Symfony\Bridge\Twig\Tests\TestCase;
17
18class TranslationDefaultDomainNodeVisitorTest extends TestCase
19{
20 private static $message = 'message';
21 private static $domain = 'domain';
22
23 /** @dataProvider getDefaultDomainAssignmentTestData */
24 public function testDefaultDomainAssignment(\Twig_Node $node)
25 {
26 $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
27 $visitor = new TranslationDefaultDomainNodeVisitor();
28
29 // visit trans_default_domain tag
30 $defaultDomain = TwigNodeProvider::getTransDefaultDomainTag(self::$domain);
31 $visitor->enterNode($defaultDomain, $env);
32 $visitor->leaveNode($defaultDomain, $env);
33
34 // visit tested node
35 $enteredNode = $visitor->enterNode($node, $env);
36 $leavedNode = $visitor->leaveNode($node, $env);
37 $this->assertSame($node, $enteredNode);
38 $this->assertSame($node, $leavedNode);
39
40 // extracting tested node messages
41 $visitor = new TranslationNodeVisitor();
42 $visitor->enable();
43 $visitor->enterNode($node, $env);
44 $visitor->leaveNode($node, $env);
45
46 $this->assertEquals(array(array(self::$message, self::$domain)), $visitor->getMessages());
47 }
48
49 /** @dataProvider getDefaultDomainAssignmentTestData */
50 public function testNewModuleWithoutDefaultDomainTag(\Twig_Node $node)
51 {
52 $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
53 $visitor = new TranslationDefaultDomainNodeVisitor();
54
55 // visit trans_default_domain tag
56 $newModule = TwigNodeProvider::getModule('test');
57 $visitor->enterNode($newModule, $env);
58 $visitor->leaveNode($newModule, $env);
59
60 // visit tested node
61 $enteredNode = $visitor->enterNode($node, $env);
62 $leavedNode = $visitor->leaveNode($node, $env);
63 $this->assertSame($node, $enteredNode);
64 $this->assertSame($node, $leavedNode);
65
66 // extracting tested node messages
67 $visitor = new TranslationNodeVisitor();
68 $visitor->enable();
69 $visitor->enterNode($node, $env);
70 $visitor->leaveNode($node, $env);
71
72 $this->assertEquals(array(array(self::$message, null)), $visitor->getMessages());
73 }
74
75 public function getDefaultDomainAssignmentTestData()
76 {
77 return array(
78 array(TwigNodeProvider::getTransFilter(self::$message)),
79 array(TwigNodeProvider::getTransChoiceFilter(self::$message)),
80 array(TwigNodeProvider::getTransTag(self::$message)),
81 );
82 }
83}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationNodeVisitorTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationNodeVisitorTest.php
new file mode 100644
index 00000000..4e3ee6fd
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TranslationNodeVisitorTest.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
13
14use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
15use Symfony\Bridge\Twig\Tests\TestCase;
16
17class TranslationNodeVisitorTest extends TestCase
18{
19 /** @dataProvider getMessagesExtractionTestData */
20 public function testMessagesExtraction(\Twig_Node $node, array $expectedMessages)
21 {
22 $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
23 $visitor = new TranslationNodeVisitor();
24 $visitor->enable();
25 $visitor->enterNode($node, $env);
26 $visitor->leaveNode($node, $env);
27 $this->assertEquals($expectedMessages, $visitor->getMessages());
28 }
29
30 public function testMessageExtractionWithInvalidDomainNode()
31 {
32 $message = 'new key';
33
34 $node = new \Twig_Node_Expression_Filter(
35 new \Twig_Node_Expression_Constant($message, 0),
36 new \Twig_Node_Expression_Constant('trans', 0),
37 new \Twig_Node(array(
38 new \Twig_Node_Expression_Array(array(), 0),
39 new \Twig_Node_Expression_Name('variable', 0),
40 )),
41 0
42 );
43
44 $this->testMessagesExtraction($node, array(array($message, TranslationNodeVisitor::UNDEFINED_DOMAIN)));
45 }
46
47 public function getMessagesExtractionTestData()
48 {
49 $message = 'new key';
50 $domain = 'domain';
51
52 return array(
53 array(TwigNodeProvider::getTransFilter($message), array(array($message, null))),
54 array(TwigNodeProvider::getTransChoiceFilter($message), array(array($message, null))),
55 array(TwigNodeProvider::getTransTag($message), array(array($message, null))),
56 array(TwigNodeProvider::getTransFilter($message, $domain), array(array($message, $domain))),
57 array(TwigNodeProvider::getTransChoiceFilter($message, $domain), array(array($message, $domain))),
58 array(TwigNodeProvider::getTransTag($message, $domain), array(array($message, $domain))),
59 );
60 }
61}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php
new file mode 100644
index 00000000..277e7774
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php
@@ -0,0 +1,77 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
13
14use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
15use Symfony\Bridge\Twig\Node\TransNode;
16
17class TwigNodeProvider
18{
19 public static function getModule($content)
20 {
21 return new \Twig_Node_Module(
22 new \Twig_Node_Expression_Constant($content, 0),
23 null,
24 new \Twig_Node_Expression_Array(array(), 0),
25 new \Twig_Node_Expression_Array(array(), 0),
26 new \Twig_Node_Expression_Array(array(), 0),
27 null,
28 null
29 );
30 }
31
32 public static function getTransFilter($message, $domain = null)
33 {
34 $arguments = $domain ? array(
35 new \Twig_Node_Expression_Array(array(), 0),
36 new \Twig_Node_Expression_Constant($domain, 0),
37 ) : array();
38
39 return new \Twig_Node_Expression_Filter(
40 new \Twig_Node_Expression_Constant($message, 0),
41 new \Twig_Node_Expression_Constant('trans', 0),
42 new \Twig_Node($arguments),
43 0
44 );
45 }
46
47 public static function getTransChoiceFilter($message, $domain = null)
48 {
49 $arguments = $domain ? array(
50 new \Twig_Node_Expression_Constant(0, 0),
51 new \Twig_Node_Expression_Array(array(), 0),
52 new \Twig_Node_Expression_Constant($domain, 0),
53 ) : array();
54
55 return new \Twig_Node_Expression_Filter(
56 new \Twig_Node_Expression_Constant($message, 0),
57 new \Twig_Node_Expression_Constant('transchoice', 0),
58 new \Twig_Node($arguments),
59 0
60 );
61 }
62
63 public static function getTransTag($message, $domain = null)
64 {
65 return new TransNode(
66 new \Twig_Node_Body(array(), array('data' => $message)),
67 $domain ? new \Twig_Node_Expression_Constant($domain, 0) : null
68 );
69 }
70
71 public static function getTransDefaultDomainTag($domain)
72 {
73 return new TransDefaultDomainNode(
74 new \Twig_Node_Expression_Constant($domain, 0)
75 );
76 }
77}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TestCase.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TestCase.php
new file mode 100644
index 00000000..ecfb7daf
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TestCase.php
@@ -0,0 +1,22 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests;
13
14abstract class TestCase extends \PHPUnit_Framework_TestCase
15{
16 protected function setUp()
17 {
18 if (!class_exists('Twig_Environment')) {
19 $this->markTestSkipped('Twig is not available.');
20 }
21 }
22}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php
new file mode 100644
index 00000000..077cd76a
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php
@@ -0,0 +1,108 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Node;
13
14use Symfony\Bridge\Twig\Tests\TestCase;
15use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
16use Symfony\Bridge\Twig\Node\FormThemeNode;
17
18class FormThemeTokenParserTest extends TestCase
19{
20 protected function setUp()
21 {
22 parent::setUp();
23
24 if (version_compare(\Twig_Environment::VERSION, '1.5.0', '<')) {
25 $this->markTestSkipped('Requires Twig version to be at least 1.5.0.');
26 }
27 }
28
29 /**
30 * @dataProvider getTestsForFormTheme
31 */
32 public function testCompile($source, $expected)
33 {
34 $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
35 $env->addTokenParser(new FormThemeTokenParser());
36 $stream = $env->tokenize($source);
37 $parser = new \Twig_Parser($env);
38
39 $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0));
40 }
41
42 public function getTestsForFormTheme()
43 {
44 return array(
45 array(
46 '{% form_theme form "tpl1" %}',
47 new FormThemeNode(
48 new \Twig_Node_Expression_Name('form', 1),
49 new \Twig_Node_Expression_Array(array(
50 new \Twig_Node_Expression_Constant(0, 1),
51 new \Twig_Node_Expression_Constant('tpl1', 1),
52 ), 1),
53 1,
54 'form_theme'
55 )
56 ),
57 array(
58 '{% form_theme form "tpl1" "tpl2" %}',
59 new FormThemeNode(
60 new \Twig_Node_Expression_Name('form', 1),
61 new \Twig_Node_Expression_Array(array(
62 new \Twig_Node_Expression_Constant(0, 1),
63 new \Twig_Node_Expression_Constant('tpl1', 1),
64 new \Twig_Node_Expression_Constant(1, 1),
65 new \Twig_Node_Expression_Constant('tpl2', 1)
66 ), 1),
67 1,
68 'form_theme'
69 )
70 ),
71 array(
72 '{% form_theme form with "tpl1" %}',
73 new FormThemeNode(
74 new \Twig_Node_Expression_Name('form', 1),
75 new \Twig_Node_Expression_Constant('tpl1', 1),
76 1,
77 'form_theme'
78 )
79 ),
80 array(
81 '{% form_theme form with ["tpl1"] %}',
82 new FormThemeNode(
83 new \Twig_Node_Expression_Name('form', 1),
84 new \Twig_Node_Expression_Array(array(
85 new \Twig_Node_Expression_Constant(0, 1),
86 new \Twig_Node_Expression_Constant('tpl1', 1),
87 ), 1),
88 1,
89 'form_theme'
90 )
91 ),
92 array(
93 '{% form_theme form with ["tpl1", "tpl2"] %}',
94 new FormThemeNode(
95 new \Twig_Node_Expression_Name('form', 1),
96 new \Twig_Node_Expression_Array(array(
97 new \Twig_Node_Expression_Constant(0, 1),
98 new \Twig_Node_Expression_Constant('tpl1', 1),
99 new \Twig_Node_Expression_Constant(1, 1),
100 new \Twig_Node_Expression_Constant('tpl2', 1)
101 ), 1),
102 1,
103 'form_theme'
104 )
105 ),
106 );
107 }
108}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php
new file mode 100644
index 00000000..a2c5cd3d
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php
@@ -0,0 +1,81 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Tests\Translation;
13
14use Symfony\Bridge\Twig\Extension\TranslationExtension;
15use Symfony\Bridge\Twig\Translation\TwigExtractor;
16use Symfony\Component\Translation\MessageCatalogue;
17use Symfony\Bridge\Twig\Tests\TestCase;
18
19class TwigExtractorTest extends TestCase
20{
21 protected function setUp()
22 {
23 if (!class_exists('Symfony\Component\Translation\Translator')) {
24 $this->markTestSkipped('The "Translation" component is not available');
25 }
26 }
27
28 /**
29 * @dataProvider getExtractData
30 */
31 public function testExtract($template, $messages)
32 {
33 $loader = new \Twig_Loader_Array(array());
34 $twig = new \Twig_Environment($loader, array(
35 'strict_variables' => true,
36 'debug' => true,
37 'cache' => false,
38 'autoescape' => false,
39 ));
40 $twig->addExtension(new TranslationExtension($this->getMock('Symfony\Component\Translation\TranslatorInterface')));
41
42 $extractor = new TwigExtractor($twig);
43 $extractor->setPrefix('prefix');
44 $catalogue = new MessageCatalogue('en');
45
46 $m = new \ReflectionMethod($extractor, 'extractTemplate');
47 $m->setAccessible(true);
48 $m->invoke($extractor, $template, $catalogue);
49
50 foreach ($messages as $key => $domain) {
51 $this->assertTrue($catalogue->has($key, $domain));
52 $this->assertEquals('prefix'.$key, $catalogue->get($key, $domain));
53 }
54 }
55
56 public function getExtractData()
57 {
58 return array(
59 array('{{ "new key" | trans() }}', array('new key' => 'messages')),
60 array('{{ "new key" | trans() | upper }}', array('new key' => 'messages')),
61 array('{{ "new key" | trans({}, "domain") }}', array('new key' => 'domain')),
62 array('{{ "new key" | transchoice(1) }}', array('new key' => 'messages')),
63 array('{{ "new key" | transchoice(1) | upper }}', array('new key' => 'messages')),
64 array('{{ "new key" | transchoice(1, {}, "domain") }}', array('new key' => 'domain')),
65 array('{% trans %}new key{% endtrans %}', array('new key' => 'messages')),
66 array('{% trans %} new key {% endtrans %}', array('new key' => 'messages')),
67 array('{% trans from "domain" %}new key{% endtrans %}', array('new key' => 'domain')),
68 array('{% set foo = "new key" | trans %}', array('new key' => 'messages')),
69 array('{{ 1 ? "new key" | trans : "another key" | trans }}', array('new key' => 'messages', 'another key' => 'messages')),
70
71 // make sure 'trans_default_domain' tag is supported
72 array('{% trans_default_domain "domain" %}{{ "new key"|trans }}', array('new key' => 'domain')),
73 array('{% trans_default_domain "domain" %}{{ "new key"|transchoice }}', array('new key' => 'domain')),
74 array('{% trans_default_domain "domain" %}{% trans %}new key{% endtrans %}', array('new key' => 'domain')),
75
76 // make sure this works with twig's named arguments
77 array('{{ "new key" | trans(domain="domain") }}', array('new key' => 'domain')),
78 array('{{ "new key" | transchoice(domain="domain", count=1) }}', array('new key' => 'domain')),
79 );
80 }
81}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php
new file mode 100644
index 00000000..244d676e
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\TokenParser;
13
14use Symfony\Bridge\Twig\Node\FormThemeNode;
15
16/**
17 * Token Parser for the 'form_theme' tag.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class FormThemeTokenParser extends \Twig_TokenParser
22{
23 /**
24 * Parses a token and returns a node.
25 *
26 * @param \Twig_Token $token A Twig_Token instance
27 *
28 * @return \Twig_NodeInterface A Twig_NodeInterface instance
29 */
30 public function parse(\Twig_Token $token)
31 {
32 $lineno = $token->getLine();
33 $stream = $this->parser->getStream();
34
35 $form = $this->parser->getExpressionParser()->parseExpression();
36
37 if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'with')) {
38 $this->parser->getStream()->next();
39 $resources = $this->parser->getExpressionParser()->parseExpression();
40 } else {
41 $resources = new \Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
42 do {
43 $resources->addElement($this->parser->getExpressionParser()->parseExpression());
44 } while (!$stream->test(\Twig_Token::BLOCK_END_TYPE));
45 }
46
47 $stream->expect(\Twig_Token::BLOCK_END_TYPE);
48
49 return new FormThemeNode($form, $resources, $lineno, $this->getTag());
50 }
51
52 /**
53 * Gets the tag name associated with this token parser.
54 *
55 * @return string The tag name
56 */
57 public function getTag()
58 {
59 return 'form_theme';
60 }
61}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransChoiceTokenParser.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransChoiceTokenParser.php
new file mode 100644
index 00000000..be8ac5cf
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransChoiceTokenParser.php
@@ -0,0 +1,89 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\TokenParser;
13
14use Symfony\Bridge\Twig\Node\TransNode;
15
16/**
17 * Token Parser for the 'transchoice' tag.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class TransChoiceTokenParser extends TransTokenParser
22{
23 /**
24 * Parses a token and returns a node.
25 *
26 * @param \Twig_Token $token A Twig_Token instance
27 *
28 * @return \Twig_NodeInterface A Twig_NodeInterface instance
29 *
30 * @throws \Twig_Error_Syntax
31 */
32 public function parse(\Twig_Token $token)
33 {
34 $lineno = $token->getLine();
35 $stream = $this->parser->getStream();
36
37 $vars = new \Twig_Node_Expression_Array(array(), $lineno);
38
39 $count = $this->parser->getExpressionParser()->parseExpression();
40
41 $domain = null;
42 $locale = null;
43
44 if ($stream->test('with')) {
45 // {% transchoice count with vars %}
46 $stream->next();
47 $vars = $this->parser->getExpressionParser()->parseExpression();
48 }
49
50 if ($stream->test('from')) {
51 // {% transchoice count from "messages" %}
52 $stream->next();
53 $domain = $this->parser->getExpressionParser()->parseExpression();
54 }
55
56 if ($stream->test('into')) {
57 // {% transchoice count into "fr" %}
58 $stream->next();
59 $locale = $this->parser->getExpressionParser()->parseExpression();
60 }
61
62 $stream->expect(\Twig_Token::BLOCK_END_TYPE);
63
64 $body = $this->parser->subparse(array($this, 'decideTransChoiceFork'), true);
65
66 if (!$body instanceof \Twig_Node_Text && !$body instanceof \Twig_Node_Expression) {
67 throw new \Twig_Error_Syntax('A message must be a simple text.');
68 }
69
70 $stream->expect(\Twig_Token::BLOCK_END_TYPE);
71
72 return new TransNode($body, $domain, $count, $vars, $locale, $lineno, $this->getTag());
73 }
74
75 public function decideTransChoiceFork($token)
76 {
77 return $token->test(array('endtranschoice'));
78 }
79
80 /**
81 * Gets the tag name associated with this token parser.
82 *
83 * @return string The tag name
84 */
85 public function getTag()
86 {
87 return 'transchoice';
88 }
89}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php
new file mode 100644
index 00000000..0a0ed55b
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php
@@ -0,0 +1,48 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\TokenParser;
13
14use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
15
16/**
17 * Token Parser for the 'trans_default_domain' tag.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class TransDefaultDomainTokenParser extends \Twig_TokenParser
22{
23 /**
24 * Parses a token and returns a node.
25 *
26 * @param \Twig_Token $token A Twig_Token instance
27 *
28 * @return \Twig_NodeInterface A Twig_NodeInterface instance
29 */
30 public function parse(\Twig_Token $token)
31 {
32 $expr = $this->parser->getExpressionParser()->parseExpression();
33
34 $this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE);
35
36 return new TransDefaultDomainNode($expr, $token->getLine(), $this->getTag());
37 }
38
39 /**
40 * Gets the tag name associated with this token parser.
41 *
42 * @return string The tag name
43 */
44 public function getTag()
45 {
46 return 'trans_default_domain';
47 }
48}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransTokenParser.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransTokenParser.php
new file mode 100644
index 00000000..a11681c2
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TokenParser/TransTokenParser.php
@@ -0,0 +1,89 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\TokenParser;
13
14use Symfony\Bridge\Twig\Node\TransNode;
15
16/**
17 * Token Parser for the 'trans' tag.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class TransTokenParser extends \Twig_TokenParser
22{
23 /**
24 * Parses a token and returns a node.
25 *
26 * @param \Twig_Token $token A Twig_Token instance
27 *
28 * @return \Twig_NodeInterface A Twig_NodeInterface instance
29 *
30 * @throws \Twig_Error_Syntax
31 */
32 public function parse(\Twig_Token $token)
33 {
34 $lineno = $token->getLine();
35 $stream = $this->parser->getStream();
36
37 $vars = new \Twig_Node_Expression_Array(array(), $lineno);
38 $domain = null;
39 $locale = null;
40 if (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) {
41 if ($stream->test('with')) {
42 // {% trans with vars %}
43 $stream->next();
44 $vars = $this->parser->getExpressionParser()->parseExpression();
45 }
46
47 if ($stream->test('from')) {
48 // {% trans from "messages" %}
49 $stream->next();
50 $domain = $this->parser->getExpressionParser()->parseExpression();
51 }
52
53 if ($stream->test('into')) {
54 // {% trans into "fr" %}
55 $stream->next();
56 $locale = $this->parser->getExpressionParser()->parseExpression();
57 } elseif (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) {
58 throw new \Twig_Error_Syntax('Unexpected token. Twig was looking for the "with" or "from" keyword.');
59 }
60 }
61
62 // {% trans %}message{% endtrans %}
63 $stream->expect(\Twig_Token::BLOCK_END_TYPE);
64 $body = $this->parser->subparse(array($this, 'decideTransFork'), true);
65
66 if (!$body instanceof \Twig_Node_Text && !$body instanceof \Twig_Node_Expression) {
67 throw new \Twig_Error_Syntax('A message inside a trans tag must be a simple text');
68 }
69
70 $stream->expect(\Twig_Token::BLOCK_END_TYPE);
71
72 return new TransNode($body, $domain, null, $vars, $locale, $lineno, $this->getTag());
73 }
74
75 public function decideTransFork($token)
76 {
77 return $token->test(array('endtrans'));
78 }
79
80 /**
81 * Gets the tag name associated with this token parser.
82 *
83 * @return string The tag name
84 */
85 public function getTag()
86 {
87 return 'trans';
88 }
89}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Translation/TwigExtractor.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Translation/TwigExtractor.php
new file mode 100644
index 00000000..b93193f2
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Translation/TwigExtractor.php
@@ -0,0 +1,86 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig\Translation;
13
14use Symfony\Component\Finder\Finder;
15use Symfony\Component\Translation\Extractor\ExtractorInterface;
16use Symfony\Component\Translation\MessageCatalogue;
17
18/**
19 * TwigExtractor extracts translation messages from a twig template.
20 *
21 * @author Michel Salib <michelsalib@hotmail.com>
22 * @author Fabien Potencier <fabien@symfony.com>
23 */
24class TwigExtractor implements ExtractorInterface
25{
26 /**
27 * Default domain for found messages.
28 *
29 * @var string
30 */
31 private $defaultDomain = 'messages';
32
33 /**
34 * Prefix for found message.
35 *
36 * @var string
37 */
38 private $prefix = '';
39
40 /**
41 * The twig environment.
42 *
43 * @var \Twig_Environment
44 */
45 private $twig;
46
47 public function __construct(\Twig_Environment $twig)
48 {
49 $this->twig = $twig;
50 }
51
52 /**
53 * {@inheritDoc}
54 */
55 public function extract($directory, MessageCatalogue $catalogue)
56 {
57 // load any existing translation files
58 $finder = new Finder();
59 $files = $finder->files()->name('*.twig')->in($directory);
60 foreach ($files as $file) {
61 $this->extractTemplate(file_get_contents($file->getPathname()), $catalogue);
62 }
63 }
64
65 /**
66 * {@inheritDoc}
67 */
68 public function setPrefix($prefix)
69 {
70 $this->prefix = $prefix;
71 }
72
73 protected function extractTemplate($template, MessageCatalogue $catalogue)
74 {
75 $visitor = $this->twig->getExtension('translator')->getTranslationNodeVisitor();
76 $visitor->enable();
77
78 $this->twig->parse($this->twig->tokenize($template));
79
80 foreach ($visitor->getMessages() as $message) {
81 $catalogue->set(trim($message[0]), $this->prefix.trim($message[0]), $message[1] ? $message[1] : $this->defaultDomain);
82 }
83
84 $visitor->disable();
85 }
86}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TwigEngine.php b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TwigEngine.php
new file mode 100644
index 00000000..955d4e0b
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/TwigEngine.php
@@ -0,0 +1,126 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bridge\Twig;
13
14use Symfony\Component\Templating\EngineInterface;
15use Symfony\Component\Templating\StreamingEngineInterface;
16use Symfony\Component\Templating\TemplateNameParserInterface;
17
18/**
19 * This engine knows how to render Twig templates.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 */
23class TwigEngine implements EngineInterface, StreamingEngineInterface
24{
25 protected $environment;
26 protected $parser;
27
28 /**
29 * Constructor.
30 *
31 * @param \Twig_Environment $environment A \Twig_Environment instance
32 * @param TemplateNameParserInterface $parser A TemplateNameParserInterface instance
33 */
34 public function __construct(\Twig_Environment $environment, TemplateNameParserInterface $parser)
35 {
36 $this->environment = $environment;
37 $this->parser = $parser;
38 }
39
40 /**
41 * Renders a template.
42 *
43 * @param mixed $name A template name
44 * @param array $parameters An array of parameters to pass to the template
45 *
46 * @return string The evaluated template as a string
47 *
48 * @throws \InvalidArgumentException if the template does not exist
49 * @throws \RuntimeException if the template cannot be rendered
50 */
51 public function render($name, array $parameters = array())
52 {
53 return $this->load($name)->render($parameters);
54 }
55
56 /**
57 * Streams a template.
58 *
59 * @param mixed $name A template name or a TemplateReferenceInterface instance
60 * @param array $parameters An array of parameters to pass to the template
61 *
62 * @throws \RuntimeException if the template cannot be rendered
63 */
64 public function stream($name, array $parameters = array())
65 {
66 $this->load($name)->display($parameters);
67 }
68
69 /**
70 * Returns true if the template exists.
71 *
72 * @param mixed $name A template name
73 *
74 * @return Boolean true if the template exists, false otherwise
75 */
76 public function exists($name)
77 {
78 try {
79 $this->load($name);
80 } catch (\InvalidArgumentException $e) {
81 return false;
82 }
83
84 return true;
85 }
86
87 /**
88 * Returns true if this class is able to render the given template.
89 *
90 * @param string $name A template name
91 *
92 * @return Boolean True if this class supports the given resource, false otherwise
93 */
94 public function supports($name)
95 {
96 if ($name instanceof \Twig_Template) {
97 return true;
98 }
99
100 $template = $this->parser->parse($name);
101
102 return 'twig' === $template->get('engine');
103 }
104
105 /**
106 * Loads the given template.
107 *
108 * @param mixed $name A template name or an instance of Twig_Template
109 *
110 * @return \Twig_TemplateInterface A \Twig_TemplateInterface instance
111 *
112 * @throws \InvalidArgumentException if the template does not exist
113 */
114 protected function load($name)
115 {
116 if ($name instanceof \Twig_Template) {
117 return $name;
118 }
119
120 try {
121 return $this->environment->loadTemplate($name);
122 } catch (\Twig_Error_Loader $e) {
123 throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
124 }
125 }
126}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/composer.json b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/composer.json
new file mode 100644
index 00000000..9cd57ae6
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/composer.json
@@ -0,0 +1,50 @@
1{
2 "name": "symfony/twig-bridge",
3 "type": "symfony-bridge",
4 "description": "Symfony Twig Bridge",
5 "keywords": [],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3",
20 "twig/twig": "~1.11"
21 },
22 "require-dev": {
23 "symfony/form": "2.2.*",
24 "symfony/http-kernel": "~2.2",
25 "symfony/routing": "~2.2",
26 "symfony/templating": "~2.1",
27 "symfony/translation": "~2.2",
28 "symfony/yaml": "~2.0",
29 "symfony/security": "~2.0"
30 },
31 "suggest": {
32 "symfony/form": "",
33 "symfony/http-kernel": "",
34 "symfony/routing": "",
35 "symfony/templating": "",
36 "symfony/translation": "",
37 "symfony/yaml": "",
38 "symfony/security": ""
39 },
40 "autoload": {
41 "psr-0": { "Symfony\\Bridge\\Twig\\": "" }
42 },
43 "target-dir": "Symfony/Bridge/Twig",
44 "minimum-stability": "dev",
45 "extra": {
46 "branch-alias": {
47 "dev-master": "2.3-dev"
48 }
49 }
50}
diff --git a/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/phpunit.xml.dist b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/phpunit.xml.dist
new file mode 100644
index 00000000..cc9e0e86
--- /dev/null
+++ b/vendor/symfony/twig-bridge/Symfony/Bridge/Twig/phpunit.xml.dist
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony Twig Bridge Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./Resources</directory>
25 <directory>./Tests</directory>
26 <directory>./vendor</directory>
27 </exclude>
28 </whitelist>
29 </filter>
30</phpunit>