aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor
diff options
context:
space:
mode:
authorNicolas Lœuillet <nicolas.loeuillet@gmail.com>2013-08-03 19:26:54 +0200
committerNicolas Lœuillet <nicolas.loeuillet@gmail.com>2013-08-03 19:26:54 +0200
commit4f5b44bd3bd490309eb2ba7b44df4769816ba729 (patch)
tree6cefe170dfe0a5a361cb1e2d1fc4d580a3316d02 /vendor
parent2b840e0cfb63a453bea67a98541f3df9c273c5f5 (diff)
downloadwallabag-4f5b44bd3bd490309eb2ba7b44df4769816ba729.tar.gz
wallabag-4f5b44bd3bd490309eb2ba7b44df4769816ba729.tar.zst
wallabag-4f5b44bd3bd490309eb2ba7b44df4769816ba729.zip
twig implementation
Diffstat (limited to 'vendor')
-rw-r--r--vendor/autoload.php7
l---------vendor/bin/twig-gettext-extractor1
-rw-r--r--vendor/composer/ClassLoader.php246
-rw-r--r--vendor/composer/autoload_classmap.php13
-rw-r--r--vendor/composer/autoload_files.php10
-rw-r--r--vendor/composer/autoload_namespaces.php22
-rw-r--r--vendor/composer/autoload_real.php47
-rw-r--r--vendor/composer/installed.json747
-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
m---------vendor/twig/extensions0
-rw-r--r--vendor/twig/twig/.editorconfig18
-rw-r--r--vendor/twig/twig/.gitignore2
-rw-r--r--vendor/twig/twig/.travis.yml15
-rw-r--r--vendor/twig/twig/AUTHORS9
-rw-r--r--vendor/twig/twig/CHANGELOG637
-rw-r--r--vendor/twig/twig/LICENSE31
-rw-r--r--vendor/twig/twig/README.markdown17
-rw-r--r--vendor/twig/twig/composer.json31
-rw-r--r--vendor/twig/twig/doc/advanced.rst829
-rw-r--r--vendor/twig/twig/doc/advanced_legacy.rst887
-rw-r--r--vendor/twig/twig/doc/api.rst529
-rw-r--r--vendor/twig/twig/doc/coding_standards.rst101
-rw-r--r--vendor/twig/twig/doc/deprecated.rst98
-rw-r--r--vendor/twig/twig/doc/filters/abs.rst18
-rw-r--r--vendor/twig/twig/doc/filters/batch.rst45
-rw-r--r--vendor/twig/twig/doc/filters/capitalize.rst11
-rw-r--r--vendor/twig/twig/doc/filters/convert_encoding.rst28
-rw-r--r--vendor/twig/twig/doc/filters/date.rst88
-rw-r--r--vendor/twig/twig/doc/filters/date_modify.rst23
-rw-r--r--vendor/twig/twig/doc/filters/default.rst33
-rw-r--r--vendor/twig/twig/doc/filters/escape.rst93
-rw-r--r--vendor/twig/twig/doc/filters/first.rst25
-rw-r--r--vendor/twig/twig/doc/filters/format.rst16
-rw-r--r--vendor/twig/twig/doc/filters/index.rst36
-rw-r--r--vendor/twig/twig/doc/filters/join.rst23
-rw-r--r--vendor/twig/twig/doc/filters/json_encode.rst21
-rw-r--r--vendor/twig/twig/doc/filters/keys.rst11
-rw-r--r--vendor/twig/twig/doc/filters/last.rst25
-rw-r--r--vendor/twig/twig/doc/filters/length.rst12
-rw-r--r--vendor/twig/twig/doc/filters/lower.rst10
-rw-r--r--vendor/twig/twig/doc/filters/merge.rst41
-rw-r--r--vendor/twig/twig/doc/filters/nl2br.rst22
-rw-r--r--vendor/twig/twig/doc/filters/number_format.rst45
-rw-r--r--vendor/twig/twig/doc/filters/raw.rst12
-rw-r--r--vendor/twig/twig/doc/filters/replace.rst19
-rw-r--r--vendor/twig/twig/doc/filters/reverse.rst47
-rw-r--r--vendor/twig/twig/doc/filters/slice.rst70
-rw-r--r--vendor/twig/twig/doc/filters/sort.rst17
-rw-r--r--vendor/twig/twig/doc/filters/split.rst53
-rw-r--r--vendor/twig/twig/doc/filters/striptags.rst15
-rw-r--r--vendor/twig/twig/doc/filters/title.rst11
-rw-r--r--vendor/twig/twig/doc/filters/trim.rst29
-rw-r--r--vendor/twig/twig/doc/filters/upper.rst10
-rw-r--r--vendor/twig/twig/doc/filters/url_encode.rst28
-rw-r--r--vendor/twig/twig/doc/functions/attribute.rst18
-rw-r--r--vendor/twig/twig/doc/functions/block.rst15
-rw-r--r--vendor/twig/twig/doc/functions/constant.rst18
-rw-r--r--vendor/twig/twig/doc/functions/cycle.rst25
-rw-r--r--vendor/twig/twig/doc/functions/date.rst52
-rw-r--r--vendor/twig/twig/doc/functions/dump.rst69
-rw-r--r--vendor/twig/twig/doc/functions/include.rst80
-rw-r--r--vendor/twig/twig/doc/functions/index.rst17
-rw-r--r--vendor/twig/twig/doc/functions/parent.rst20
-rw-r--r--vendor/twig/twig/doc/functions/random.rst29
-rw-r--r--vendor/twig/twig/doc/functions/range.rst45
-rw-r--r--vendor/twig/twig/doc/functions/template_from_string.rst32
-rw-r--r--vendor/twig/twig/doc/index.rst18
-rw-r--r--vendor/twig/twig/doc/internals.rst140
-rw-r--r--vendor/twig/twig/doc/intro.rst164
-rw-r--r--vendor/twig/twig/doc/recipes.rst475
-rw-r--r--vendor/twig/twig/doc/tags/autoescape.rst71
-rw-r--r--vendor/twig/twig/doc/tags/block.rst11
-rw-r--r--vendor/twig/twig/doc/tags/do.rst12
-rw-r--r--vendor/twig/twig/doc/tags/embed.rst178
-rw-r--r--vendor/twig/twig/doc/tags/extends.rst268
-rw-r--r--vendor/twig/twig/doc/tags/filter.rst21
-rw-r--r--vendor/twig/twig/doc/tags/flush.rst17
-rw-r--r--vendor/twig/twig/doc/tags/for.rst172
-rw-r--r--vendor/twig/twig/doc/tags/from.rst8
-rw-r--r--vendor/twig/twig/doc/tags/if.rst43
-rw-r--r--vendor/twig/twig/doc/tags/import.rst57
-rw-r--r--vendor/twig/twig/doc/tags/include.rst86
-rw-r--r--vendor/twig/twig/doc/tags/index.rst24
-rw-r--r--vendor/twig/twig/doc/tags/macro.rst83
-rw-r--r--vendor/twig/twig/doc/tags/sandbox.rst30
-rw-r--r--vendor/twig/twig/doc/tags/set.rst78
-rw-r--r--vendor/twig/twig/doc/tags/spaceless.rst37
-rw-r--r--vendor/twig/twig/doc/tags/use.rst123
-rw-r--r--vendor/twig/twig/doc/tags/verbatim.rst24
-rw-r--r--vendor/twig/twig/doc/templates.rst851
-rw-r--r--vendor/twig/twig/doc/tests/constant.rst22
-rw-r--r--vendor/twig/twig/doc/tests/defined.rst30
-rw-r--r--vendor/twig/twig/doc/tests/divisibleby.rst10
-rw-r--r--vendor/twig/twig/doc/tests/empty.rst11
-rw-r--r--vendor/twig/twig/doc/tests/even.rst10
-rw-r--r--vendor/twig/twig/doc/tests/index.rst15
-rw-r--r--vendor/twig/twig/doc/tests/iterable.rst19
-rw-r--r--vendor/twig/twig/doc/tests/null.rst12
-rw-r--r--vendor/twig/twig/doc/tests/odd.rst10
-rw-r--r--vendor/twig/twig/doc/tests/sameas.rst11
-rw-r--r--vendor/twig/twig/ext/twig/.gitignore30
-rw-r--r--vendor/twig/twig/ext/twig/LICENSE22
-rw-r--r--vendor/twig/twig/ext/twig/config.m48
-rw-r--r--vendor/twig/twig/ext/twig/config.w328
-rw-r--r--vendor/twig/twig/ext/twig/php_twig.h31
-rw-r--r--vendor/twig/twig/ext/twig/twig.c1076
-rw-r--r--vendor/twig/twig/lib/Twig/Autoloader.php48
-rw-r--r--vendor/twig/twig/lib/Twig/Compiler.php267
-rw-r--r--vendor/twig/twig/lib/Twig/CompilerInterface.php35
-rw-r--r--vendor/twig/twig/lib/Twig/Environment.php1224
-rw-r--r--vendor/twig/twig/lib/Twig/Error.php243
-rw-r--r--vendor/twig/twig/lib/Twig/Error/Loader.php31
-rw-r--r--vendor/twig/twig/lib/Twig/Error/Runtime.php20
-rw-r--r--vendor/twig/twig/lib/Twig/Error/Syntax.php20
-rw-r--r--vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php28
-rw-r--r--vendor/twig/twig/lib/Twig/ExpressionParser.php600
-rw-r--r--vendor/twig/twig/lib/Twig/Extension.php93
-rw-r--r--vendor/twig/twig/lib/Twig/Extension/Core.php1355
-rw-r--r--vendor/twig/twig/lib/Twig/Extension/Debug.php71
-rw-r--r--vendor/twig/twig/lib/Twig/Extension/Escaper.php107
-rw-r--r--vendor/twig/twig/lib/Twig/Extension/Optimizer.php35
-rw-r--r--vendor/twig/twig/lib/Twig/Extension/Sandbox.php112
-rw-r--r--vendor/twig/twig/lib/Twig/Extension/Staging.php113
-rw-r--r--vendor/twig/twig/lib/Twig/Extension/StringLoader.php64
-rw-r--r--vendor/twig/twig/lib/Twig/ExtensionInterface.php83
-rw-r--r--vendor/twig/twig/lib/Twig/Filter.php81
-rw-r--r--vendor/twig/twig/lib/Twig/Filter/Function.php37
-rw-r--r--vendor/twig/twig/lib/Twig/Filter/Method.php39
-rw-r--r--vendor/twig/twig/lib/Twig/Filter/Node.php39
-rw-r--r--vendor/twig/twig/lib/Twig/FilterCallableInterface.php23
-rw-r--r--vendor/twig/twig/lib/Twig/FilterInterface.php42
-rw-r--r--vendor/twig/twig/lib/Twig/Function.php71
-rw-r--r--vendor/twig/twig/lib/Twig/Function/Function.php38
-rw-r--r--vendor/twig/twig/lib/Twig/Function/Method.php40
-rw-r--r--vendor/twig/twig/lib/Twig/Function/Node.php39
-rw-r--r--vendor/twig/twig/lib/Twig/FunctionCallableInterface.php23
-rw-r--r--vendor/twig/twig/lib/Twig/FunctionInterface.php39
-rw-r--r--vendor/twig/twig/lib/Twig/Lexer.php408
-rw-r--r--vendor/twig/twig/lib/Twig/LexerInterface.php29
-rw-r--r--vendor/twig/twig/lib/Twig/Loader/Array.php98
-rw-r--r--vendor/twig/twig/lib/Twig/Loader/Chain.php139
-rw-r--r--vendor/twig/twig/lib/Twig/Loader/Filesystem.php226
-rw-r--r--vendor/twig/twig/lib/Twig/Loader/String.php59
-rw-r--r--vendor/twig/twig/lib/Twig/LoaderInterface.php52
-rw-r--r--vendor/twig/twig/lib/Twig/Markup.php37
-rw-r--r--vendor/twig/twig/lib/Twig/Node.php226
-rw-r--r--vendor/twig/twig/lib/Twig/Node/AutoEscape.php39
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Block.php44
-rw-r--r--vendor/twig/twig/lib/Twig/Node/BlockReference.php37
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Body.php19
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Do.php38
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Embed.php38
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression.php20
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Array.php86
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php28
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary.php40
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php17
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php29
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php17
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php17
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.php33
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php17
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php17
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php17
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php33
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.php33
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.php33
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.php51
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Call.php178
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php31
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Constant.php23
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php33
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Filter.php36
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.php43
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Function.php35
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php53
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.php41
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Name.php88
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Parent.php47
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/TempName.php26
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Test.php32
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php46
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php54
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php33
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.php32
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.php31
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.php32
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php29
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Unary.php30
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php18
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Flush.php36
-rw-r--r--vendor/twig/twig/lib/Twig/Node/For.php112
-rw-r--r--vendor/twig/twig/lib/Twig/Node/ForLoop.php55
-rw-r--r--vendor/twig/twig/lib/Twig/Node/If.php66
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Import.php50
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Include.php99
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Macro.php96
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Module.php371
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Print.php39
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Sandbox.php47
-rw-r--r--vendor/twig/twig/lib/Twig/Node/SandboxedModule.php60
-rw-r--r--vendor/twig/twig/lib/Twig/Node/SandboxedPrint.php59
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Set.php101
-rw-r--r--vendor/twig/twig/lib/Twig/Node/SetTemp.php35
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Spaceless.php40
-rw-r--r--vendor/twig/twig/lib/Twig/Node/Text.php39
-rw-r--r--vendor/twig/twig/lib/Twig/NodeInterface.php30
-rw-r--r--vendor/twig/twig/lib/Twig/NodeOutputInterface.php19
-rw-r--r--vendor/twig/twig/lib/Twig/NodeTraverser.php88
-rw-r--r--vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.php167
-rw-r--r--vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php246
-rw-r--r--vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php131
-rw-r--r--vendor/twig/twig/lib/Twig/NodeVisitor/Sandbox.php92
-rw-r--r--vendor/twig/twig/lib/Twig/NodeVisitorInterface.php47
-rw-r--r--vendor/twig/twig/lib/Twig/Parser.php394
-rw-r--r--vendor/twig/twig/lib/Twig/ParserInterface.php28
-rw-r--r--vendor/twig/twig/lib/Twig/Sandbox/SecurityError.php19
-rw-r--r--vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php119
-rw-r--r--vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php24
-rw-r--r--vendor/twig/twig/lib/Twig/SimpleFilter.php94
-rw-r--r--vendor/twig/twig/lib/Twig/SimpleFunction.php84
-rw-r--r--vendor/twig/twig/lib/Twig/SimpleTest.php46
-rw-r--r--vendor/twig/twig/lib/Twig/Template.php455
-rw-r--r--vendor/twig/twig/lib/Twig/TemplateInterface.php47
-rw-r--r--vendor/twig/twig/lib/Twig/Test.php34
-rw-r--r--vendor/twig/twig/lib/Twig/Test/Function.php35
-rw-r--r--vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php154
-rw-r--r--vendor/twig/twig/lib/Twig/Test/Method.php37
-rw-r--r--vendor/twig/twig/lib/Twig/Test/Node.php37
-rw-r--r--vendor/twig/twig/lib/Twig/Test/NodeTestCase.php58
-rw-r--r--vendor/twig/twig/lib/Twig/TestCallableInterface.php21
-rw-r--r--vendor/twig/twig/lib/Twig/TestInterface.php26
-rw-r--r--vendor/twig/twig/lib/Twig/Token.php218
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser.php33
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/AutoEscape.php89
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Block.php83
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Do.php42
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Embed.php66
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Extends.php52
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Filter.php61
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Flush.php42
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/For.php136
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/From.php74
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/If.php94
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Import.php49
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Include.php80
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Macro.php68
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Sandbox.php68
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Set.php84
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Spaceless.php59
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParser/Use.php82
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParserBroker.php136
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php45
-rw-r--r--vendor/twig/twig/lib/Twig/TokenParserInterface.php41
-rw-r--r--vendor/twig/twig/lib/Twig/TokenStream.php144
-rw-r--r--vendor/twig/twig/phpunit.xml.dist25
-rw-r--r--vendor/twig/twig/test/Twig/Tests/AutoloaderTest.php21
-rw-r--r--vendor/twig/twig/test/Twig/Tests/CompilerTest.php33
-rw-r--r--vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php288
-rw-r--r--vendor/twig/twig/test/Twig/Tests/ErrorTest.php159
-rw-r--r--vendor/twig/twig/test/Twig/Tests/ExpressionParserTest.php332
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php117
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php212
-rw-r--r--vendor/twig/twig/test/Twig/Tests/FileCachingTest.php70
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/errors/base.html1
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/errors/index.html7
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test20
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array.test61
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array_call.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/binary.test46
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/bitwise.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/comparison.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/dotdot.test20
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/grouping.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/literals.test22
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/magic_call.test27
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/method_call.test28
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/postfix.test22
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/strings.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator.test18
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_noelse.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_nothen.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_precedence.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/abs.test30
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch.test31
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_float.php31
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_empty_fill.test37
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_fill.test37
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/convert_encoding.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date.test76
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format_interval.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_interval.test19
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_modify.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test13
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/default.test150
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/dynamic_filter.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_non_supported_charset.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/force_escape.test18
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/format.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/join.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/json_encode.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length_utf8.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/merge.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/nl2br.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format.test18
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format_default.test21
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/reverse.test18
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test42
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/sort.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/split.test18
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/trim.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/block.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/constant.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/cycle.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test27
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date_namedargs.test11
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump_array.test19
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dynamic_function.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test13
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/basic.test17
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/expression.test17
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/ignore_missing.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing_nested.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/template_instance.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/templates_as_array.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_context.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_variables.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/range.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test11
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/macros/default_values.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/macros/nested_calls.test18
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/macros/reserved_variables.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test22
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test17
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/regression/strings_like_numbers.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/basic.test26
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/blocks.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/double_escaping.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/functions.test83
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/literal.test45
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/nested.test26
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/objects.test26
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/raw.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test17
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/type.test69
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test131
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test23
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_pre_escape_filters.test68
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_preserves_safety_filters.test50
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/basic.test11
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/block_unique_name.test11
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/basic.test35
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/multiple.test50
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/nested.test42
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/with_extends.test57
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/basic.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/json_encode.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/multiple.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/nested.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_for_tag.test13
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_if_tag.test29
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/condition.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/context.test18
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/else.test23
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/inner_variables.test17
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys.test11
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys_and_values.test11
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context.test19
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context_local.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined_cond.test9
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/nested_else.test17
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects.test43
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects_countable.test47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/recursive.test18
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/values.test11
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/from.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/basic.test22
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/expression.test22
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/basic.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/expression.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing_nested.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/only.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/template_instance.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/templates_as_array.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/with_variables.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/basic.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/conditional.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/dynamic.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/empty.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks.test22
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks_parent_only.test15
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_inheritance.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_change.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_in_a_block.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_isolation.test20
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_nested.test28
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/template_instance.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/use.test44
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/basic.test17
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/endmacro_name.test16
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/external.test17
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from.test18
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/global.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/self_import.test17
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/basic.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/mixed_usage_with_raw.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/whitespace_control.test56
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid1.test11
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid2.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/simple.test22
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/basic.test20
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture-empty.test9
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/expression.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/spaceless/simple.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test8
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/trim_block.test74
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/aliases.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/basic.test12
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep.test22
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep_empty.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple.test21
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple_aliases.test23
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/basic.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/mixed_usage_with_raw.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/whitespace_control.test56
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tests/array.test24
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tests/defined.test108
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tests/empty.test45
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tests/even.test14
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in.test48
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in_with_objects.test19
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tests/iterable.test19
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Fixtures/tests/odd.test10
-rw-r--r--vendor/twig/twig/test/Twig/Tests/IntegrationTest.php217
-rw-r--r--vendor/twig/twig/test/Twig/Tests/LexerTest.php301
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/ArrayTest.php97
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php79
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php97
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named/index.html1
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_bis/index.html1
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_final/index.html1
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_ter/index.html1
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal/index.html1
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_bis/index.html1
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_final/index.html1
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_ter/index.html1
-rw-r--r--vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php29
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/AutoEscapeTest.php44
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/BlockReferenceTest.php43
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/BlockTest.php51
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/DoTest.php44
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/ArrayTest.php49
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/AssignNameTest.php41
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AddTest.php47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AndTest.php47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ConcatTest.php47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/DivTest.php47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/FloorDivTest.php47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ModTest.php47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/MulTest.php47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/OrTest.php47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/SubTest.php47
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php67
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/ConditionalTest.php50
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/ConstantTest.php42
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php133
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php99
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php62
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php49
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FilterInclude.php6
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FunctionInclude.php6
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/TestInclude.php6
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/ParentTest.php40
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php68
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NegTest.php44
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NotTest.php44
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/PosTest.php44
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/ForTest.php203
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/IfTest.php100
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/ImportTest.php52
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/IncludeTest.php96
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/MacroTest.php73
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php196
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/PrintTest.php41
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/SandboxTest.php56
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php173
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/SandboxedPrintTest.php45
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/SetTest.php81
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/SpacelessTest.php49
-rw-r--r--vendor/twig/twig/test/Twig/Tests/Node/TextTest.php40
-rw-r--r--vendor/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php114
-rw-r--r--vendor/twig/twig/test/Twig/Tests/ParserTest.php180
-rw-r--r--vendor/twig/twig/test/Twig/Tests/TemplateTest.php626
-rw-r--r--vendor/twig/twig/test/Twig/Tests/TokenStreamTest.php70
-rw-r--r--vendor/twig/twig/test/Twig/Tests/escapingTest.php320
-rw-r--r--vendor/twig/twig/test/bootstrap.php13
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/.gitignore3
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/.travis.yml10
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/LICENSE19
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/README.md49
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Extractor.php95
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Loader/Filesystem.php58
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Routing/Generator/UrlGenerator.php39
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/ExtractorTest.php123
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/empty.twig1
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/plural.twig5
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/singular.twig9
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/composer.json30
-rw-r--r--vendor/umpirsky/twig-gettext-extractor/phpunit.xml.dist14
-rwxr-xr-xvendor/umpirsky/twig-gettext-extractor/twig-gettext-extractor58
1348 files changed, 122370 insertions, 0 deletions
diff --git a/vendor/autoload.php b/vendor/autoload.php
new file mode 100644
index 00000000..9e19b465
--- /dev/null
+++ b/vendor/autoload.php
@@ -0,0 +1,7 @@
1<?php
2
3// autoload.php generated by Composer
4
5require_once __DIR__ . '/composer' . '/autoload_real.php';
6
7return ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029::getLoader();
diff --git a/vendor/bin/twig-gettext-extractor b/vendor/bin/twig-gettext-extractor
new file mode 120000
index 00000000..006816c8
--- /dev/null
+++ b/vendor/bin/twig-gettext-extractor
@@ -0,0 +1 @@
../umpirsky/twig-gettext-extractor/twig-gettext-extractor \ No newline at end of file
diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php
new file mode 100644
index 00000000..1db8d9a0
--- /dev/null
+++ b/vendor/composer/ClassLoader.php
@@ -0,0 +1,246 @@
1<?php
2
3/*
4 * This file is part of Composer.
5 *
6 * (c) Nils Adermann <naderman@naderman.de>
7 * Jordi Boggiano <j.boggiano@seld.be>
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13namespace Composer\Autoload;
14
15/**
16 * ClassLoader implements a PSR-0 class loader
17 *
18 * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
19 *
20 * $loader = new \Composer\Autoload\ClassLoader();
21 *
22 * // register classes with namespaces
23 * $loader->add('Symfony\Component', __DIR__.'/component');
24 * $loader->add('Symfony', __DIR__.'/framework');
25 *
26 * // activate the autoloader
27 * $loader->register();
28 *
29 * // to enable searching the include path (eg. for PEAR packages)
30 * $loader->setUseIncludePath(true);
31 *
32 * In this example, if you try to use a class in the Symfony\Component
33 * namespace or one of its children (Symfony\Component\Console for instance),
34 * the autoloader will first look for the class under the component/
35 * directory, and it will then fallback to the framework/ directory if not
36 * found before giving up.
37 *
38 * This class is loosely based on the Symfony UniversalClassLoader.
39 *
40 * @author Fabien Potencier <fabien@symfony.com>
41 * @author Jordi Boggiano <j.boggiano@seld.be>
42 */
43class ClassLoader
44{
45 private $prefixes = array();
46 private $fallbackDirs = array();
47 private $useIncludePath = false;
48 private $classMap = array();
49
50 public function getPrefixes()
51 {
52 return call_user_func_array('array_merge', $this->prefixes);
53 }
54
55 public function getFallbackDirs()
56 {
57 return $this->fallbackDirs;
58 }
59
60 public function getClassMap()
61 {
62 return $this->classMap;
63 }
64
65 /**
66 * @param array $classMap Class to filename map
67 */
68 public function addClassMap(array $classMap)
69 {
70 if ($this->classMap) {
71 $this->classMap = array_merge($this->classMap, $classMap);
72 } else {
73 $this->classMap = $classMap;
74 }
75 }
76
77 /**
78 * Registers a set of classes, merging with any others previously set.
79 *
80 * @param string $prefix The classes prefix
81 * @param array|string $paths The location(s) of the classes
82 * @param bool $prepend Prepend the location(s)
83 */
84 public function add($prefix, $paths, $prepend = false)
85 {
86 if (!$prefix) {
87 if ($prepend) {
88 $this->fallbackDirs = array_merge(
89 (array) $paths,
90 $this->fallbackDirs
91 );
92 } else {
93 $this->fallbackDirs = array_merge(
94 $this->fallbackDirs,
95 (array) $paths
96 );
97 }
98
99 return;
100 }
101
102 $first = $prefix[0];
103 if (!isset($this->prefixes[$first][$prefix])) {
104 $this->prefixes[$first][$prefix] = (array) $paths;
105
106 return;
107 }
108 if ($prepend) {
109 $this->prefixes[$first][$prefix] = array_merge(
110 (array) $paths,
111 $this->prefixes[$first][$prefix]
112 );
113 } else {
114 $this->prefixes[$first][$prefix] = array_merge(
115 $this->prefixes[$first][$prefix],
116 (array) $paths
117 );
118 }
119 }
120
121 /**
122 * Registers a set of classes, replacing any others previously set.
123 *
124 * @param string $prefix The classes prefix
125 * @param array|string $paths The location(s) of the classes
126 */
127 public function set($prefix, $paths)
128 {
129 if (!$prefix) {
130 $this->fallbackDirs = (array) $paths;
131
132 return;
133 }
134 $this->prefixes[substr($prefix, 0, 1)][$prefix] = (array) $paths;
135 }
136
137 /**
138 * Turns on searching the include path for class files.
139 *
140 * @param bool $useIncludePath
141 */
142 public function setUseIncludePath($useIncludePath)
143 {
144 $this->useIncludePath = $useIncludePath;
145 }
146
147 /**
148 * Can be used to check if the autoloader uses the include path to check
149 * for classes.
150 *
151 * @return bool
152 */
153 public function getUseIncludePath()
154 {
155 return $this->useIncludePath;
156 }
157
158 /**
159 * Registers this instance as an autoloader.
160 *
161 * @param bool $prepend Whether to prepend the autoloader or not
162 */
163 public function register($prepend = false)
164 {
165 spl_autoload_register(array($this, 'loadClass'), true, $prepend);
166 }
167
168 /**
169 * Unregisters this instance as an autoloader.
170 */
171 public function unregister()
172 {
173 spl_autoload_unregister(array($this, 'loadClass'));
174 }
175
176 /**
177 * Loads the given class or interface.
178 *
179 * @param string $class The name of the class
180 * @return bool|null True if loaded, null otherwise
181 */
182 public function loadClass($class)
183 {
184 if ($file = $this->findFile($class)) {
185 include $file;
186
187 return true;
188 }
189 }
190
191 /**
192 * Finds the path to the file where the class is defined.
193 *
194 * @param string $class The name of the class
195 *
196 * @return string|false The path if found, false otherwise
197 */
198 public function findFile($class)
199 {
200 // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
201 if ('\\' == $class[0]) {
202 $class = substr($class, 1);
203 }
204
205 if (isset($this->classMap[$class])) {
206 return $this->classMap[$class];
207 }
208
209 if (false !== $pos = strrpos($class, '\\')) {
210 // namespaced class name
211 $classPath = strtr(substr($class, 0, $pos), '\\', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
212 $className = substr($class, $pos + 1);
213 } else {
214 // PEAR-like class name
215 $classPath = null;
216 $className = $class;
217 }
218
219 $classPath .= strtr($className, '_', DIRECTORY_SEPARATOR) . '.php';
220
221 $first = $class[0];
222 if (isset($this->prefixes[$first])) {
223 foreach ($this->prefixes[$first] as $prefix => $dirs) {
224 if (0 === strpos($class, $prefix)) {
225 foreach ($dirs as $dir) {
226 if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
227 return $dir . DIRECTORY_SEPARATOR . $classPath;
228 }
229 }
230 }
231 }
232 }
233
234 foreach ($this->fallbackDirs as $dir) {
235 if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
236 return $dir . DIRECTORY_SEPARATOR . $classPath;
237 }
238 }
239
240 if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
241 return $file;
242 }
243
244 return $this->classMap[$class] = false;
245 }
246}
diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php
new file mode 100644
index 00000000..7574eb5b
--- /dev/null
+++ b/vendor/composer/autoload_classmap.php
@@ -0,0 +1,13 @@
1<?php
2
3// autoload_classmap.php generated by Composer
4
5$vendorDir = dirname(dirname(__FILE__));
6$baseDir = dirname($vendorDir);
7
8return array(
9 'Collator' => $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/Collator.php',
10 'IntlDateFormatter' => $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/IntlDateFormatter.php',
11 'Locale' => $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/Locale.php',
12 'NumberFormatter' => $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/NumberFormatter.php',
13);
diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php
new file mode 100644
index 00000000..a6552d0f
--- /dev/null
+++ b/vendor/composer/autoload_files.php
@@ -0,0 +1,10 @@
1<?php
2
3// autoload_files.php generated by Composer
4
5$vendorDir = dirname(dirname(__FILE__));
6$baseDir = dirname($vendorDir);
7
8return array(
9 $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/functions.php',
10); \ No newline at end of file
diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php
new file mode 100644
index 00000000..5d64b487
--- /dev/null
+++ b/vendor/composer/autoload_namespaces.php
@@ -0,0 +1,22 @@
1<?php
2
3// autoload_namespaces.php generated by Composer
4
5$vendorDir = dirname(dirname(__FILE__));
6$baseDir = dirname($vendorDir);
7
8return array(
9 'Twig_Extensions_' => array($vendorDir . '/twig/extensions/lib'),
10 'Twig_' => array($vendorDir . '/twig/twig/lib'),
11 'Twig\\Gettext' => array($vendorDir . '/umpirsky/twig-gettext-extractor'),
12 'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
13 'Symfony\\Component\\Routing\\' => array($vendorDir . '/symfony/routing'),
14 'Symfony\\Component\\PropertyAccess\\' => array($vendorDir . '/symfony/property-access'),
15 'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
16 'Symfony\\Component\\Intl\\' => array($vendorDir . '/symfony/intl'),
17 'Symfony\\Component\\Icu\\' => array($vendorDir . '/symfony/icu'),
18 'Symfony\\Component\\Form\\' => array($vendorDir . '/symfony/form'),
19 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
20 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
21 'Symfony\\Bridge\\Twig\\' => array($vendorDir . '/symfony/twig-bridge'),
22);
diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php
new file mode 100644
index 00000000..f398fe33
--- /dev/null
+++ b/vendor/composer/autoload_real.php
@@ -0,0 +1,47 @@
1<?php
2
3// autoload_real.php generated by Composer
4
5class ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029
6{
7 private static $loader;
8
9 public static function loadClassLoader($class)
10 {
11 if ('Composer\Autoload\ClassLoader' === $class) {
12 require __DIR__ . '/ClassLoader.php';
13 }
14 }
15
16 public static function getLoader()
17 {
18 if (null !== self::$loader) {
19 return self::$loader;
20 }
21
22 spl_autoload_register(array('ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029', 'loadClassLoader'), true, true);
23 self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24 spl_autoload_unregister(array('ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029', 'loadClassLoader'));
25
26 $vendorDir = dirname(__DIR__);
27 $baseDir = dirname($vendorDir);
28
29 $map = require __DIR__ . '/autoload_namespaces.php';
30 foreach ($map as $namespace => $path) {
31 $loader->set($namespace, $path);
32 }
33
34 $classMap = require __DIR__ . '/autoload_classmap.php';
35 if ($classMap) {
36 $loader->addClassMap($classMap);
37 }
38
39 $loader->register(true);
40
41 foreach (require __DIR__ . '/autoload_files.php' as $file) {
42 require $file;
43 }
44
45 return $loader;
46 }
47}
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
new file mode 100644
index 00000000..21a9b56f
--- /dev/null
+++ b/vendor/composer/installed.json
@@ -0,0 +1,747 @@
1[
2 {
3 "name": "twig/twig",
4 "version": "v1.13.2",
5 "version_normalized": "1.13.2.0",
6 "source": {
7 "type": "git",
8 "url": "https://github.com/fabpot/Twig.git",
9 "reference": "v1.13.2"
10 },
11 "dist": {
12 "type": "zip",
13 "url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.13.2",
14 "reference": "v1.13.2",
15 "shasum": ""
16 },
17 "require": {
18 "php": ">=5.2.4"
19 },
20 "time": "2013-08-03 15:35:31",
21 "type": "library",
22 "extra": {
23 "branch-alias": {
24 "dev-master": "1.13-dev"
25 }
26 },
27 "installation-source": "dist",
28 "autoload": {
29 "psr-0": {
30 "Twig_": "lib/"
31 }
32 },
33 "notification-url": "https://packagist.org/downloads/",
34 "license": [
35 "BSD-3-Clause"
36 ],
37 "authors": [
38 {
39 "name": "Fabien Potencier",
40 "email": "fabien@symfony.com"
41 },
42 {
43 "name": "Armin Ronacher",
44 "email": "armin.ronacher@active-4.com"
45 }
46 ],
47 "description": "Twig, the flexible, fast, and secure template language for PHP",
48 "homepage": "http://twig.sensiolabs.org",
49 "keywords": [
50 "templating"
51 ]
52 },
53 {
54 "name": "twig/extensions",
55 "version": "dev-master",
56 "version_normalized": "9999999-dev",
57 "source": {
58 "type": "git",
59 "url": "https://github.com/fabpot/Twig-extensions.git",
60 "reference": "f5b0c84f3699e494c84ee627d7d583e115d2c4a2"
61 },
62 "dist": {
63 "type": "zip",
64 "url": "https://api.github.com/repos/fabpot/Twig-extensions/zipball/f5b0c84f3699e494c84ee627d7d583e115d2c4a2",
65 "reference": "f5b0c84f3699e494c84ee627d7d583e115d2c4a2",
66 "shasum": ""
67 },
68 "require": {
69 "twig/twig": "~1.0"
70 },
71 "time": "2013-07-02 11:21:55",
72 "type": "library",
73 "extra": {
74 "branch-alias": {
75 "dev-master": "1.0.x-dev"
76 }
77 },
78 "installation-source": "source",
79 "autoload": {
80 "psr-0": {
81 "Twig_Extensions_": "lib/"
82 }
83 },
84 "notification-url": "https://packagist.org/downloads/",
85 "license": [
86 "MIT"
87 ],
88 "authors": [
89 {
90 "name": "Fabien Potencier",
91 "email": "fabien@symfony.com"
92 }
93 ],
94 "description": "Common additional features for Twig that do not directly belong in core",
95 "homepage": "https://github.com/fabpot/Twig-extensions",
96 "keywords": [
97 "debug",
98 "i18n",
99 "text"
100 ]
101 },
102 {
103 "name": "symfony/icu",
104 "version": "v1.0.0",
105 "version_normalized": "1.0.0.0",
106 "target-dir": "Symfony/Component/Icu",
107 "source": {
108 "type": "git",
109 "url": "https://github.com/symfony/Icu.git",
110 "reference": "v1.0.0"
111 },
112 "dist": {
113 "type": "zip",
114 "url": "https://api.github.com/repos/symfony/Icu/zipball/v1.0.0",
115 "reference": "v1.0.0",
116 "shasum": ""
117 },
118 "require": {
119 "php": ">=5.3.3",
120 "symfony/intl": ">=2.3,<3.0"
121 },
122 "time": "2013-06-03 18:32:07",
123 "type": "library",
124 "installation-source": "dist",
125 "autoload": {
126 "psr-0": {
127 "Symfony\\Component\\Icu\\": ""
128 }
129 },
130 "notification-url": "https://packagist.org/downloads/",
131 "license": [
132 "MIT"
133 ],
134 "authors": [
135 {
136 "name": "Symfony Community",
137 "homepage": "http://symfony.com/contributors"
138 },
139 {
140 "name": "Bernhard Schussek",
141 "email": "bschussek@gmail.com"
142 }
143 ],
144 "description": "Contains an excerpt of the ICU data and classes to load it.",
145 "homepage": "http://symfony.com",
146 "keywords": [
147 "icu",
148 "intl"
149 ]
150 },
151 {
152 "name": "symfony/intl",
153 "version": "v2.3.2",
154 "version_normalized": "2.3.2.0",
155 "target-dir": "Symfony/Component/Intl",
156 "source": {
157 "type": "git",
158 "url": "https://github.com/symfony/Intl.git",
159 "reference": "v2.3.2"
160 },
161 "dist": {
162 "type": "zip",
163 "url": "https://api.github.com/repos/symfony/Intl/zipball/v2.3.2",
164 "reference": "v2.3.2",
165 "shasum": ""
166 },
167 "require": {
168 "php": ">=5.3.3",
169 "symfony/icu": "~1.0-RC"
170 },
171 "require-dev": {
172 "symfony/filesystem": ">=2.1"
173 },
174 "suggest": {
175 "ext-intl": "to use the component with locales other than \"en\""
176 },
177 "time": "2013-07-08 13:00:35",
178 "type": "library",
179 "extra": {
180 "branch-alias": {
181 "dev-master": "2.3-dev"
182 }
183 },
184 "installation-source": "dist",
185 "autoload": {
186 "psr-0": {
187 "Symfony\\Component\\Intl\\": ""
188 },
189 "classmap": [
190 "Symfony/Component/Intl/Resources/stubs"
191 ],
192 "files": [
193 "Symfony/Component/Intl/Resources/stubs/functions.php"
194 ]
195 },
196 "notification-url": "https://packagist.org/downloads/",
197 "license": [
198 "MIT"
199 ],
200 "authors": [
201 {
202 "name": "Symfony Community",
203 "homepage": "http://symfony.com/contributors"
204 },
205 {
206 "name": "Igor Wiedler",
207 "email": "igor@wiedler.ch",
208 "homepage": "http://wiedler.ch/igor/"
209 },
210 {
211 "name": "Bernhard Schussek",
212 "email": "bschussek@gmail.com"
213 },
214 {
215 "name": "Eriksen Costa",
216 "email": "eriksen.costa@infranology.com.br"
217 }
218 ],
219 "description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.",
220 "homepage": "http://symfony.com",
221 "keywords": [
222 "i18n",
223 "icu",
224 "internationalization",
225 "intl",
226 "l10n",
227 "localization"
228 ]
229 },
230 {
231 "name": "symfony/property-access",
232 "version": "v2.3.2",
233 "version_normalized": "2.3.2.0",
234 "target-dir": "Symfony/Component/PropertyAccess",
235 "source": {
236 "type": "git",
237 "url": "https://github.com/symfony/PropertyAccess.git",
238 "reference": "v2.3.2"
239 },
240 "dist": {
241 "type": "zip",
242 "url": "https://api.github.com/repos/symfony/PropertyAccess/zipball/v2.3.2",
243 "reference": "v2.3.2",
244 "shasum": ""
245 },
246 "require": {
247 "php": ">=5.3.3"
248 },
249 "time": "2013-07-01 12:24:43",
250 "type": "library",
251 "extra": {
252 "branch-alias": {
253 "dev-master": "2.3-dev"
254 }
255 },
256 "installation-source": "dist",
257 "autoload": {
258 "psr-0": {
259 "Symfony\\Component\\PropertyAccess\\": ""
260 }
261 },
262 "notification-url": "https://packagist.org/downloads/",
263 "license": [
264 "MIT"
265 ],
266 "authors": [
267 {
268 "name": "Fabien Potencier",
269 "email": "fabien@symfony.com"
270 },
271 {
272 "name": "Symfony Community",
273 "homepage": "http://symfony.com/contributors"
274 }
275 ],
276 "description": "Symfony PropertyAccess Component",
277 "homepage": "http://symfony.com",
278 "keywords": [
279 "access",
280 "array",
281 "extraction",
282 "index",
283 "injection",
284 "object",
285 "property",
286 "property path",
287 "reflection"
288 ]
289 },
290 {
291 "name": "symfony/options-resolver",
292 "version": "v2.3.2",
293 "version_normalized": "2.3.2.0",
294 "target-dir": "Symfony/Component/OptionsResolver",
295 "source": {
296 "type": "git",
297 "url": "https://github.com/symfony/OptionsResolver.git",
298 "reference": "v2.3.2"
299 },
300 "dist": {
301 "type": "zip",
302 "url": "https://api.github.com/repos/symfony/OptionsResolver/zipball/v2.3.2",
303 "reference": "v2.3.2",
304 "shasum": ""
305 },
306 "require": {
307 "php": ">=5.3.3"
308 },
309 "time": "2013-04-11 06:50:46",
310 "type": "library",
311 "extra": {
312 "branch-alias": {
313 "dev-master": "2.3-dev"
314 }
315 },
316 "installation-source": "dist",
317 "autoload": {
318 "psr-0": {
319 "Symfony\\Component\\OptionsResolver\\": ""
320 }
321 },
322 "notification-url": "https://packagist.org/downloads/",
323 "license": [
324 "MIT"
325 ],
326 "authors": [
327 {
328 "name": "Fabien Potencier",
329 "email": "fabien@symfony.com"
330 },
331 {
332 "name": "Symfony Community",
333 "homepage": "http://symfony.com/contributors"
334 }
335 ],
336 "description": "Symfony OptionsResolver Component",
337 "homepage": "http://symfony.com",
338 "keywords": [
339 "config",
340 "configuration",
341 "options"
342 ]
343 },
344 {
345 "name": "symfony/event-dispatcher",
346 "version": "v2.3.2",
347 "version_normalized": "2.3.2.0",
348 "target-dir": "Symfony/Component/EventDispatcher",
349 "source": {
350 "type": "git",
351 "url": "https://github.com/symfony/EventDispatcher.git",
352 "reference": "v2.3.2"
353 },
354 "dist": {
355 "type": "zip",
356 "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.2",
357 "reference": "v2.3.2",
358 "shasum": ""
359 },
360 "require": {
361 "php": ">=5.3.3"
362 },
363 "require-dev": {
364 "symfony/dependency-injection": "~2.0"
365 },
366 "suggest": {
367 "symfony/dependency-injection": "",
368 "symfony/http-kernel": ""
369 },
370 "time": "2013-05-13 14:36:40",
371 "type": "library",
372 "extra": {
373 "branch-alias": {
374 "dev-master": "2.3-dev"
375 }
376 },
377 "installation-source": "dist",
378 "autoload": {
379 "psr-0": {
380 "Symfony\\Component\\EventDispatcher\\": ""
381 }
382 },
383 "notification-url": "https://packagist.org/downloads/",
384 "license": [
385 "MIT"
386 ],
387 "authors": [
388 {
389 "name": "Fabien Potencier",
390 "email": "fabien@symfony.com"
391 },
392 {
393 "name": "Symfony Community",
394 "homepage": "http://symfony.com/contributors"
395 }
396 ],
397 "description": "Symfony EventDispatcher Component",
398 "homepage": "http://symfony.com"
399 },
400 {
401 "name": "symfony/form",
402 "version": "v2.3.2",
403 "version_normalized": "2.3.2.0",
404 "target-dir": "Symfony/Component/Form",
405 "source": {
406 "type": "git",
407 "url": "https://github.com/symfony/Form.git",
408 "reference": "v2.3.2"
409 },
410 "dist": {
411 "type": "zip",
412 "url": "https://api.github.com/repos/symfony/Form/zipball/v2.3.2",
413 "reference": "v2.3.2",
414 "shasum": ""
415 },
416 "require": {
417 "php": ">=5.3.3",
418 "symfony/event-dispatcher": "~2.1",
419 "symfony/intl": "~2.3",
420 "symfony/options-resolver": "~2.1",
421 "symfony/property-access": "~2.2"
422 },
423 "require-dev": {
424 "symfony/http-foundation": "~2.2",
425 "symfony/validator": "~2.2"
426 },
427 "suggest": {
428 "symfony/http-foundation": "",
429 "symfony/validator": ""
430 },
431 "time": "2013-07-01 12:24:43",
432 "type": "library",
433 "extra": {
434 "branch-alias": {
435 "dev-master": "2.3-dev"
436 }
437 },
438 "installation-source": "dist",
439 "autoload": {
440 "psr-0": {
441 "Symfony\\Component\\Form\\": ""
442 }
443 },
444 "notification-url": "https://packagist.org/downloads/",
445 "license": [
446 "MIT"
447 ],
448 "authors": [
449 {
450 "name": "Fabien Potencier",
451 "email": "fabien@symfony.com"
452 },
453 {
454 "name": "Symfony Community",
455 "homepage": "http://symfony.com/contributors"
456 }
457 ],
458 "description": "Symfony Form Component",
459 "homepage": "http://symfony.com"
460 },
461 {
462 "name": "symfony/translation",
463 "version": "v2.3.2",
464 "version_normalized": "2.3.2.0",
465 "target-dir": "Symfony/Component/Translation",
466 "source": {
467 "type": "git",
468 "url": "https://github.com/symfony/Translation.git",
469 "reference": "v2.3.2"
470 },
471 "dist": {
472 "type": "zip",
473 "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.2",
474 "reference": "v2.3.2",
475 "shasum": ""
476 },
477 "require": {
478 "php": ">=5.3.3"
479 },
480 "require-dev": {
481 "symfony/config": "~2.0",
482 "symfony/yaml": "~2.2"
483 },
484 "suggest": {
485 "symfony/config": "",
486 "symfony/yaml": ""
487 },
488 "time": "2013-05-13 14:36:40",
489 "type": "library",
490 "extra": {
491 "branch-alias": {
492 "dev-master": "2.3-dev"
493 }
494 },
495 "installation-source": "dist",
496 "autoload": {
497 "psr-0": {
498 "Symfony\\Component\\Translation\\": ""
499 }
500 },
501 "notification-url": "https://packagist.org/downloads/",
502 "license": [
503 "MIT"
504 ],
505 "authors": [
506 {
507 "name": "Fabien Potencier",
508 "email": "fabien@symfony.com"
509 },
510 {
511 "name": "Symfony Community",
512 "homepage": "http://symfony.com/contributors"
513 }
514 ],
515 "description": "Symfony Translation Component",
516 "homepage": "http://symfony.com"
517 },
518 {
519 "name": "symfony/filesystem",
520 "version": "v2.3.2",
521 "version_normalized": "2.3.2.0",
522 "target-dir": "Symfony/Component/Filesystem",
523 "source": {
524 "type": "git",
525 "url": "https://github.com/symfony/Filesystem.git",
526 "reference": "v2.3.2"
527 },
528 "dist": {
529 "type": "zip",
530 "url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.3.2",
531 "reference": "v2.3.2",
532 "shasum": ""
533 },
534 "require": {
535 "php": ">=5.3.3"
536 },
537 "time": "2013-06-04 15:02:05",
538 "type": "library",
539 "extra": {
540 "branch-alias": {
541 "dev-master": "2.3-dev"
542 }
543 },
544 "installation-source": "dist",
545 "autoload": {
546 "psr-0": {
547 "Symfony\\Component\\Filesystem\\": ""
548 }
549 },
550 "notification-url": "https://packagist.org/downloads/",
551 "license": [
552 "MIT"
553 ],
554 "authors": [
555 {
556 "name": "Fabien Potencier",
557 "email": "fabien@symfony.com"
558 },
559 {
560 "name": "Symfony Community",
561 "homepage": "http://symfony.com/contributors"
562 }
563 ],
564 "description": "Symfony Filesystem Component",
565 "homepage": "http://symfony.com"
566 },
567 {
568 "name": "symfony/routing",
569 "version": "v2.3.2",
570 "version_normalized": "2.3.2.0",
571 "target-dir": "Symfony/Component/Routing",
572 "source": {
573 "type": "git",
574 "url": "https://github.com/symfony/Routing.git",
575 "reference": "v2.3.2"
576 },
577 "dist": {
578 "type": "zip",
579 "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.2",
580 "reference": "v2.3.2",
581 "shasum": ""
582 },
583 "require": {
584 "php": ">=5.3.3"
585 },
586 "require-dev": {
587 "doctrine/common": "~2.2",
588 "psr/log": "~1.0",
589 "symfony/config": "~2.2",
590 "symfony/yaml": "~2.0"
591 },
592 "suggest": {
593 "doctrine/common": "",
594 "symfony/config": "",
595 "symfony/yaml": ""
596 },
597 "time": "2013-06-23 08:16:02",
598 "type": "library",
599 "extra": {
600 "branch-alias": {
601 "dev-master": "2.3-dev"
602 }
603 },
604 "installation-source": "dist",
605 "autoload": {
606 "psr-0": {
607 "Symfony\\Component\\Routing\\": ""
608 }
609 },
610 "notification-url": "https://packagist.org/downloads/",
611 "license": [
612 "MIT"
613 ],
614 "authors": [
615 {
616 "name": "Fabien Potencier",
617 "email": "fabien@symfony.com"
618 },
619 {
620 "name": "Symfony Community",
621 "homepage": "http://symfony.com/contributors"
622 }
623 ],
624 "description": "Symfony Routing Component",
625 "homepage": "http://symfony.com"
626 },
627 {
628 "name": "symfony/twig-bridge",
629 "version": "v2.3.2",
630 "version_normalized": "2.3.2.0",
631 "target-dir": "Symfony/Bridge/Twig",
632 "source": {
633 "type": "git",
634 "url": "https://github.com/symfony/TwigBridge.git",
635 "reference": "v2.3.2"
636 },
637 "dist": {
638 "type": "zip",
639 "url": "https://api.github.com/repos/symfony/TwigBridge/zipball/v2.3.2",
640 "reference": "v2.3.2",
641 "shasum": ""
642 },
643 "require": {
644 "php": ">=5.3.3",
645 "twig/twig": "~1.11"
646 },
647 "require-dev": {
648 "symfony/form": "2.2.*",
649 "symfony/http-kernel": "~2.2",
650 "symfony/routing": "~2.2",
651 "symfony/security": "~2.0",
652 "symfony/templating": "~2.1",
653 "symfony/translation": "~2.2",
654 "symfony/yaml": "~2.0"
655 },
656 "suggest": {
657 "symfony/form": "",
658 "symfony/http-kernel": "",
659 "symfony/routing": "",
660 "symfony/security": "",
661 "symfony/templating": "",
662 "symfony/translation": "",
663 "symfony/yaml": ""
664 },
665 "time": "2013-05-16 10:19:58",
666 "type": "symfony-bridge",
667 "extra": {
668 "branch-alias": {
669 "dev-master": "2.3-dev"
670 }
671 },
672 "installation-source": "dist",
673 "autoload": {
674 "psr-0": {
675 "Symfony\\Bridge\\Twig\\": ""
676 }
677 },
678 "notification-url": "https://packagist.org/downloads/",
679 "license": [
680 "MIT"
681 ],
682 "authors": [
683 {
684 "name": "Fabien Potencier",
685 "email": "fabien@symfony.com"
686 },
687 {
688 "name": "Symfony Community",
689 "homepage": "http://symfony.com/contributors"
690 }
691 ],
692 "description": "Symfony Twig Bridge",
693 "homepage": "http://symfony.com"
694 },
695 {
696 "name": "umpirsky/twig-gettext-extractor",
697 "version": "1.1.3",
698 "version_normalized": "1.1.3.0",
699 "source": {
700 "type": "git",
701 "url": "https://github.com/umpirsky/Twig-Gettext-Extractor.git",
702 "reference": "1.1.3"
703 },
704 "dist": {
705 "type": "zip",
706 "url": "https://api.github.com/repos/umpirsky/Twig-Gettext-Extractor/zipball/1.1.3",
707 "reference": "1.1.3",
708 "shasum": ""
709 },
710 "require": {
711 "php": ">=5.3.3",
712 "symfony/filesystem": ">=2.0,<3.0",
713 "symfony/form": ">=2.0,<3.0",
714 "symfony/routing": ">=2.0,<3.0",
715 "symfony/translation": ">=2.0,<3.0",
716 "symfony/twig-bridge": ">=2.0,<3.0",
717 "twig/extensions": "1.0.*",
718 "twig/twig": ">=1.2.0,<2.0-dev"
719 },
720 "require-dev": {
721 "symfony/config": "2.1.*"
722 },
723 "time": "2013-02-14 16:41:48",
724 "bin": [
725 "twig-gettext-extractor"
726 ],
727 "type": "application",
728 "installation-source": "dist",
729 "autoload": {
730 "psr-0": {
731 "Twig\\Gettext": "."
732 }
733 },
734 "notification-url": "https://packagist.org/downloads/",
735 "license": [
736 "MIT"
737 ],
738 "authors": [
739 {
740 "name": "Саша Стаменковић",
741 "email": "umpirsky@gmail.com",
742 "homepage": "http://umpirsky.com"
743 }
744 ],
745 "description": "The Twig Gettext Extractor is Poedit friendly tool which extracts translations from twig templates."
746 }
747]
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>br</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>
diff --git a/vendor/twig/extensions b/vendor/twig/extensions
new file mode 160000
Subproject f5b0c84f3699e494c84ee627d7d583e115d2c4a
diff --git a/vendor/twig/twig/.editorconfig b/vendor/twig/twig/.editorconfig
new file mode 100644
index 00000000..270f1d1b
--- /dev/null
+++ b/vendor/twig/twig/.editorconfig
@@ -0,0 +1,18 @@
1; top-most EditorConfig file
2root = true
3
4; Unix-style newlines
5[*]
6end_of_line = LF
7
8[*.php]
9indent_style = space
10indent_size = 4
11
12[*.test]
13indent_style = space
14indent_size = 4
15
16[*.rst]
17indent_style = space
18indent_size = 4
diff --git a/vendor/twig/twig/.gitignore b/vendor/twig/twig/.gitignore
new file mode 100644
index 00000000..840b78e7
--- /dev/null
+++ b/vendor/twig/twig/.gitignore
@@ -0,0 +1,2 @@
1/ext/twig/autom4te.cache/
2
diff --git a/vendor/twig/twig/.travis.yml b/vendor/twig/twig/.travis.yml
new file mode 100644
index 00000000..8569a395
--- /dev/null
+++ b/vendor/twig/twig/.travis.yml
@@ -0,0 +1,15 @@
1language: php
2
3php:
4 - 5.2
5 - 5.3
6 - 5.4
7 - 5.5
8
9env:
10 - TWIG_EXT=no
11 - TWIG_EXT=yes
12
13before_script:
14 - if [ "$TWIG_EXT" == "yes" ]; then sh -c "cd ext/twig && phpize && ./configure --enable-twig && make && sudo make install"; fi
15 - if [ "$TWIG_EXT" == "yes" ]; then echo "extension=twig.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi
diff --git a/vendor/twig/twig/AUTHORS b/vendor/twig/twig/AUTHORS
new file mode 100644
index 00000000..eb5db051
--- /dev/null
+++ b/vendor/twig/twig/AUTHORS
@@ -0,0 +1,9 @@
1Twig is written and maintained by the Twig Team:
2
3Lead Developer:
4
5- Fabien Potencier <fabien.potencier@symfony-project.org>
6
7Project Founder:
8
9- Armin Ronacher <armin.ronacher@active-4.com>
diff --git a/vendor/twig/twig/CHANGELOG b/vendor/twig/twig/CHANGELOG
new file mode 100644
index 00000000..80ff9d2d
--- /dev/null
+++ b/vendor/twig/twig/CHANGELOG
@@ -0,0 +1,637 @@
1* 1.13.2 (2013-08-03)
2
3 * fixed the error line number for an error occurs in and embedded template
4 * fixed crashes of the C extension on some edge cases
5
6* 1.13.1 (2013-06-06)
7
8 * added the possibility to ignore the filesystem constructor argument in Twig_Loader_Filesystem
9 * fixed Twig_Loader_Chain::exists() for a loader which implements Twig_ExistsLoaderInterface
10 * adjusted backtrace call to reduce memory usage when an error occurs
11 * added support for object instances as the second argument of the constant test
12 * fixed the include function when used in an assignment
13
14* 1.13.0 (2013-05-10)
15
16 * fixed getting a numeric-like item on a variable ('09' for instance)
17 * fixed getting a boolean or float key on an array, so it is consistent with PHP's array access:
18 `{{ array[false] }}` behaves the same as `echo $array[false];` (equals `$array[0]`)
19 * made the escape filter 20% faster for happy path (escaping string for html with UTF-8)
20 * changed ☃ to § in tests
21 * enforced usage of named arguments after positional ones
22
23* 1.12.3 (2013-04-08)
24
25 * fixed a security issue in the filesystem loader where it was possible to include a template one
26 level above the configured path
27 * fixed fatal error that should be an exception when adding a filter/function/test too late
28 * added a batch filter
29 * added support for encoding an array as query string in the url_encode filter
30
31* 1.12.2 (2013-02-09)
32
33 * fixed the timezone used by the date filter and function when the given date contains a timezone (like 2010-01-28T15:00:00+02:00)
34 * fixed globals when getGlobals is called early on
35 * added the first and last filter
36
37* 1.12.1 (2013-01-15)
38
39 * added support for object instances as the second argument of the constant function
40 * relaxed globals management to avoid a BC break
41 * added support for {{ some_string[:2] }}
42
43* 1.12.0 (2013-01-08)
44
45 * added verbatim as an alias for the raw tag to avoid confusion with the raw filter
46 * fixed registration of tests and functions as anonymous functions
47 * fixed globals management
48
49* 1.12.0-RC1 (2012-12-29)
50
51 * added an include function (does the same as the include tag but in a more flexible way)
52 * added the ability to use any PHP callable to define filters, functions, and tests
53 * added a syntax error when using a loop variable that is not defined
54 * added the ability to set default values for macro arguments
55 * added support for named arguments for filters, tests, and functions
56 * moved filters/functions/tests syntax errors to the parser
57 * added support for extended ternary operator syntaxes
58
59* 1.11.1 (2012-11-11)
60
61 * fixed debug info line numbering (was off by 2)
62 * fixed escaping when calling a macro inside another one (regression introduced in 1.9.1)
63 * optimized variable access on PHP 5.4
64 * fixed a crash of the C extension when an exception was thrown from a macro called without being imported (using _self.XXX)
65
66* 1.11.0 (2012-11-07)
67
68 * fixed macro compilation when a variable name is a PHP reserved keyword
69 * changed the date filter behavior to always apply the default timezone, except if false is passed as the timezone
70 * fixed bitwise operator precedences
71 * added the template_from_string function
72 * fixed default timezone usage for the date function
73 * optimized the way Twig exceptions are managed (to make them faster)
74 * added Twig_ExistsLoaderInterface (implementing this interface in your loader make the chain loader much faster)
75
76* 1.10.3 (2012-10-19)
77
78 * fixed wrong template location in some error messages
79 * reverted a BC break introduced in 1.10.2
80 * added a split filter
81
82* 1.10.2 (2012-10-15)
83
84 * fixed macro calls on PHP 5.4
85
86* 1.10.1 (2012-10-15)
87
88 * made a speed optimization to macro calls when imported via the "import" tag
89 * fixed C extension compilation on Windows
90 * fixed a segfault in the C extension when using DateTime objects
91
92* 1.10.0 (2012-09-28)
93
94 * extracted functional tests framework to make it reusable for third-party extensions
95 * added namespaced templates support in Twig_Loader_Filesystem
96 * added Twig_Loader_Filesystem::prependPath()
97 * fixed an error when a token parser pass a closure as a test to the subparse() method
98
99* 1.9.2 (2012-08-25)
100
101 * fixed the in operator for objects that contain circular references
102 * fixed the C extension when accessing a public property of an object implementing the \ArrayAccess interface
103
104* 1.9.1 (2012-07-22)
105
106 * optimized macro calls when auto-escaping is on
107 * fixed wrong parent class for Twig_Function_Node
108 * made Twig_Loader_Chain more explicit about problems
109
110* 1.9.0 (2012-07-13)
111
112 * made the parsing independent of the template loaders
113 * fixed exception trace when an error occurs when rendering a child template
114 * added escaping strategies for CSS, URL, and HTML attributes
115 * fixed nested embed tag calls
116 * added the date_modify filter
117
118* 1.8.3 (2012-06-17)
119
120 * fixed paths in the filesystem loader when passing a path that ends with a slash or a backslash
121 * fixed escaping when a project defines a function named html or js
122 * fixed chmod mode to apply the umask correctly
123
124* 1.8.2 (2012-05-30)
125
126 * added the abs filter
127 * fixed a regression when using a number in template attributes
128 * fixed compiler when mbstring.func_overload is set to 2
129 * fixed DateTimeZone support in date filter
130
131* 1.8.1 (2012-05-17)
132
133 * fixed a regression when dealing with SimpleXMLElement instances in templates
134 * fixed "is_safe" value for the "dump" function when "html_errors" is not defined in php.ini
135 * switched to use mbstring whenever possible instead of iconv (you might need to update your encoding as mbstring and iconv encoding names sometimes differ)
136
137* 1.8.0 (2012-05-08)
138
139 * enforced interface when adding tests, filters, functions, and node visitors from extensions
140 * fixed a side-effect of the date filter where the timezone might be changed
141 * simplified usage of the autoescape tag; the only (optional) argument is now the escaping strategy or false (with a BC layer)
142 * added a way to dynamically change the auto-escaping strategy according to the template "filename"
143 * changed the autoescape option to also accept a supported escaping strategy (for BC, true is equivalent to html)
144 * added an embed tag
145
146* 1.7.0 (2012-04-24)
147
148 * fixed a PHP warning when using CIFS
149 * fixed template line number in some exceptions
150 * added an iterable test
151 * added an error when defining two blocks with the same name in a template
152 * added the preserves_safety option for filters
153 * fixed a PHP notice when trying to access a key on a non-object/array variable
154 * enhanced error reporting when the template file is an instance of SplFileInfo
155 * added Twig_Environment::mergeGlobals()
156 * added compilation checks to avoid misuses of the sandbox tag
157 * fixed filesystem loader freshness logic for high traffic websites
158 * fixed random function when charset is null
159
160* 1.6.5 (2012-04-11)
161
162 * fixed a regression when a template only extends another one without defining any blocks
163
164* 1.6.4 (2012-04-02)
165
166 * fixed PHP notice in Twig_Error::guessTemplateLine() introduced in 1.6.3
167 * fixed performance when compiling large files
168 * optimized parent template creation when the template does not use dynamic inheritance
169
170* 1.6.3 (2012-03-22)
171
172 * fixed usage of Z_ADDREF_P for PHP 5.2 in the C extension
173 * fixed compilation of numeric values used in templates when using a locale where the decimal separator is not a dot
174 * made the strategy used to guess the real template file name and line number in exception messages much faster and more accurate
175
176* 1.6.2 (2012-03-18)
177
178 * fixed sandbox mode when used with inheritance
179 * added preserveKeys support for the slice filter
180 * fixed the date filter when a DateTime instance is passed with a specific timezone
181 * added a trim filter
182
183* 1.6.1 (2012-02-29)
184
185 * fixed Twig C extension
186 * removed the creation of Twig_Markup instances when not needed
187 * added a way to set the default global timezone for dates
188 * fixed the slice filter on strings when the length is not specified
189 * fixed the creation of the cache directory in case of a race condition
190
191* 1.6.0 (2012-02-04)
192
193 * fixed raw blocks when used with the whitespace trim option
194 * made a speed optimization to macro calls when imported via the "from" tag
195 * fixed globals, parsers, visitors, filters, tests, and functions management in Twig_Environment when a new one or new extension is added
196 * fixed the attribute function when passing arguments
197 * added slice notation support for the [] operator (syntactic sugar for the slice operator)
198 * added a slice filter
199 * added string support for the reverse filter
200 * fixed the empty test and the length filter for Twig_Markup instances
201 * added a date function to ease date comparison
202 * fixed unary operators precedence
203 * added recursive parsing support in the parser
204 * added string and integer handling for the random function
205
206* 1.5.1 (2012-01-05)
207
208 * fixed a regression when parsing strings
209
210* 1.5.0 (2012-01-04)
211
212 * added Traversable objects support for the join filter
213
214* 1.5.0-RC2 (2011-12-30)
215
216 * added a way to set the default global date interval format
217 * fixed the date filter for DateInterval instances (setTimezone() does not exist for them)
218 * refactored Twig_Template::display() to ease its extension
219 * added a number_format filter
220
221* 1.5.0-RC1 (2011-12-26)
222
223 * removed the need to quote hash keys
224 * allowed hash keys to be any expression
225 * added a do tag
226 * added a flush tag
227 * added support for dynamically named filters and functions
228 * added a dump function to help debugging templates
229 * added a nl2br filter
230 * added a random function
231 * added a way to change the default format for the date filter
232 * fixed the lexer when an operator ending with a letter ends a line
233 * added string interpolation support
234 * enhanced exceptions for unknown filters, functions, tests, and tags
235
236* 1.4.0 (2011-12-07)
237
238 * fixed lexer when using big numbers (> PHP_INT_MAX)
239 * added missing preserveKeys argument to the reverse filter
240 * fixed macros containing filter tag calls
241
242* 1.4.0-RC2 (2011-11-27)
243
244 * removed usage of Reflection in Twig_Template::getAttribute()
245 * added a C extension that can optionally replace Twig_Template::getAttribute()
246 * added negative timestamp support to the date filter
247
248* 1.4.0-RC1 (2011-11-20)
249
250 * optimized variable access when using PHP 5.4
251 * changed the precedence of the .. operator to be more consistent with languages that implements such a feature like Ruby
252 * added an Exception to Twig_Loader_Array::isFresh() method when the template does not exist to be consistent with other loaders
253 * added Twig_Function_Node to allow more complex functions to have their own Node class
254 * added Twig_Filter_Node to allow more complex filters to have their own Node class
255 * added Twig_Test_Node to allow more complex tests to have their own Node class
256 * added a better error message when a template is empty but contain a BOM
257 * fixed "in" operator for empty strings
258 * fixed the "defined" test and the "default" filter (now works with more than one call (foo.bar.foo) and for both values of the strict_variables option)
259 * changed the way extensions are loaded (addFilter/addFunction/addGlobal/addTest/addNodeVisitor/addTokenParser/addExtension can now be called in any order)
260 * added Twig_Environment::display()
261 * made the escape filter smarter when the encoding is not supported by PHP
262 * added a convert_encoding filter
263 * moved all node manipulations outside the compile() Node method
264 * made several speed optimizations
265
266* 1.3.0 (2011-10-08)
267
268no changes
269
270* 1.3.0-RC1 (2011-10-04)
271
272 * added an optimization for the parent() function
273 * added cache reloading when auto_reload is true and an extension has been modified
274 * added the possibility to force the escaping of a string already marked as safe (instance of Twig_Markup)
275 * allowed empty templates to be used as traits
276 * added traits support for the "parent" function
277
278* 1.2.0 (2011-09-13)
279
280no changes
281
282* 1.2.0-RC1 (2011-09-10)
283
284 * enhanced the exception when a tag remains unclosed
285 * added support for empty Countable objects for the "empty" test
286 * fixed algorithm that determines if a template using inheritance is valid (no output between block definitions)
287 * added better support for encoding problems when escaping a string (available as of PHP 5.4)
288 * added a way to ignore a missing template when using the "include" tag ({% include "foo" ignore missing %})
289 * added support for an array of templates to the "include" and "extends" tags ({% include ['foo', 'bar'] %})
290 * added support for bitwise operators in expressions
291 * added the "attribute" function to allow getting dynamic attributes on variables
292 * added Twig_Loader_Chain
293 * added Twig_Loader_Array::setTemplate()
294 * added an optimization for the set tag when used to capture a large chunk of static text
295 * changed name regex to match PHP one "[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*" (works for blocks, tags, functions, filters, and macros)
296 * removed the possibility to use the "extends" tag from a block
297 * added "if" modifier support to "for" loops
298
299* 1.1.2 (2011-07-30)
300
301 * fixed json_encode filter on PHP 5.2
302 * fixed regression introduced in 1.1.1 ({{ block(foo|lower) }})
303 * fixed inheritance when using conditional parents
304 * fixed compilation of templates when the body of a child template is not empty
305 * fixed output when a macro throws an exception
306 * fixed a parsing problem when a large chunk of text is enclosed in a comment tag
307 * added PHPDoc for all Token parsers and Core extension functions
308
309* 1.1.1 (2011-07-17)
310
311 * added a performance optimization in the Optimizer (also helps to lower the number of nested level calls)
312 * made some performance improvement for some edge cases
313
314* 1.1.0 (2011-06-28)
315
316 * fixed json_encode filter
317
318* 1.1.0-RC3 (2011-06-24)
319
320 * fixed method case-sensitivity when using the sandbox mode
321 * added timezone support for the date filter
322 * fixed possible security problems with NUL bytes
323
324* 1.1.0-RC2 (2011-06-16)
325
326 * added an exception when the template passed to "use" is not a string
327 * made 'a.b is defined' not throw an exception if a is not defined (in strict mode)
328 * added {% line \d+ %} directive
329
330* 1.1.0-RC1 (2011-05-28)
331
332Flush your cache after upgrading.
333
334 * fixed date filter when using a timestamp
335 * fixed the defined test for some cases
336 * fixed a parsing problem when a large chunk of text is enclosed in a raw tag
337 * added support for horizontal reuse of template blocks (see docs for more information)
338 * added whitespace control modifier to all tags (see docs for more information)
339 * added null as an alias for none (the null test is also an alias for the none test now)
340 * made TRUE, FALSE, NONE equivalent to their lowercase counterparts
341 * wrapped all compilation and runtime exceptions with Twig_Error_Runtime and added logic to guess the template name and line
342 * moved display() method to Twig_Template (generated templates should now use doDisplay() instead)
343
344* 1.0.0 (2011-03-27)
345
346 * fixed output when using mbstring
347 * fixed duplicate call of methods when using the sandbox
348 * made the charset configurable for the escape filter
349
350* 1.0.0-RC2 (2011-02-21)
351
352 * changed the way {% set %} works when capturing (the content is now marked as safe)
353 * added support for macro name in the endmacro tag
354 * make Twig_Error compatible with PHP 5.3.0 >
355 * fixed an infinite loop on some Windows configurations
356 * fixed the "length" filter for numbers
357 * fixed Template::getAttribute() as properties in PHP are case sensitive
358 * removed coupling between Twig_Node and Twig_Template
359 * fixed the ternary operator precedence rule
360
361* 1.0.0-RC1 (2011-01-09)
362
363Backward incompatibilities:
364
365 * the "items" filter, which has been deprecated for quite a long time now, has been removed
366 * the "range" filter has been converted to a function: 0|range(10) -> range(0, 10)
367 * the "constant" filter has been converted to a function: {{ some_date|date('DATE_W3C'|constant) }} -> {{ some_date|date(constant('DATE_W3C')) }}
368 * the "cycle" filter has been converted to a function: {{ ['odd', 'even']|cycle(i) }} -> {{ cycle(['odd', 'even'], i) }}
369 * the "for" tag does not support "joined by" anymore
370 * the "autoescape" first argument is now "true"/"false" (instead of "on"/"off")
371 * the "parent" tag has been replaced by a "parent" function ({{ parent() }} instead of {% parent %})
372 * the "display" tag has been replaced by a "block" function ({{ block('title') }} instead of {% display title %})
373 * removed the grammar and simple token parser (moved to the Twig Extensions repository)
374
375Changes:
376
377 * added "needs_context" option for filters and functions (the context is then passed as a first argument)
378 * added global variables support
379 * made macros return their value instead of echoing directly (fixes calling a macro in sandbox mode)
380 * added the "from" tag to import macros as functions
381 * added support for functions (a function is just syntactic sugar for a getAttribute() call)
382 * made macros callable when sandbox mode is enabled
383 * added an exception when a macro uses a reserved name
384 * the "default" filter now uses the "empty" test instead of just checking for null
385 * added the "empty" test
386
387* 0.9.10 (2010-12-16)
388
389Backward incompatibilities:
390
391 * The Escaper extension is enabled by default, which means that all displayed
392 variables are now automatically escaped. You can revert to the previous
393 behavior by removing the extension via $env->removeExtension('escaper')
394 or just set the 'autoescape' option to 'false'.
395 * removed the "without loop" attribute for the "for" tag (not needed anymore
396 as the Optimizer take care of that for most cases)
397 * arrays and hashes have now a different syntax
398 * arrays keep the same syntax with square brackets: [1, 2]
399 * hashes now use curly braces (["a": "b"] should now be written as {"a": "b"})
400 * support for "arrays with keys" and "hashes without keys" is not supported anymore ([1, "foo": "bar"] or {"foo": "bar", 1})
401 * the i18n extension is now part of the Twig Extensions repository
402
403Changes:
404
405 * added the merge filter
406 * removed 'is_escaper' option for filters (a left over from the previous version) -- you must use 'is_safe' now instead
407 * fixed usage of operators as method names (like is, in, and not)
408 * changed the order of execution for node visitors
409 * fixed default() filter behavior when used with strict_variables set to on
410 * fixed filesystem loader compatibility with PHAR files
411 * enhanced error messages when an unexpected token is parsed in an expression
412 * fixed filename not being added to syntax error messages
413 * added the autoescape option to enable/disable autoescaping
414 * removed the newline after a comment (mimics PHP behavior)
415 * added a syntax error exception when parent block is used on a template that does not extend another one
416 * made the Escaper extension enabled by default
417 * fixed sandbox extension when used with auto output escaping
418 * fixed escaper when wrapping a Twig_Node_Print (the original class must be preserved)
419 * added an Optimizer extension (enabled by default; optimizes "for" loops and "raw" filters)
420 * added priority to node visitors
421
422* 0.9.9 (2010-11-28)
423
424Backward incompatibilities:
425 * the self special variable has been renamed to _self
426 * the odd and even filters are now tests:
427 {{ foo|odd }} must now be written {{ foo is odd }}
428 * the "safe" filter has been renamed to "raw"
429 * in Node classes,
430 sub-nodes are now accessed via getNode() (instead of property access)
431 attributes via getAttribute() (instead of array access)
432 * the urlencode filter had been renamed to url_encode
433 * the include tag now merges the passed variables with the current context by default
434 (the old behavior is still possible by adding the "only" keyword)
435 * moved Exceptions to Twig_Error_* (Twig_SyntaxError/Twig_RuntimeError are now Twig_Error_Syntax/Twig_Error_Runtime)
436 * removed support for {{ 1 < i < 3 }} (use {{ i > 1 and i < 3 }} instead)
437 * the "in" filter has been removed ({{ a|in(b) }} should now be written {{ a in b }})
438
439Changes:
440 * added file and line to Twig_Error_Runtime exceptions thrown from Twig_Template
441 * changed trans tag to accept any variable for the plural count
442 * fixed sandbox mode (__toString() method check was not enforced if called implicitly from complex statements)
443 * added the ** (power) operator
444 * changed the algorithm used for parsing expressions
445 * added the spaceless tag
446 * removed trim_blocks option
447 * added support for is*() methods for attributes (foo.bar now looks for foo->getBar() or foo->isBar())
448 * changed all exceptions to extend Twig_Error
449 * fixed unary expressions ({{ not(1 or 0) }})
450 * fixed child templates (with an extend tag) that uses one or more imports
451 * added support for {{ 1 not in [2, 3] }} (more readable than the current {{ not (1 in [2, 3]) }})
452 * escaping has been rewritten
453 * the implementation of template inheritance has been rewritten
454 (blocks can now be called individually and still work with inheritance)
455 * fixed error handling for if tag when a syntax error occurs within a subparse process
456 * added a way to implement custom logic for resolving token parsers given a tag name
457 * fixed js escaper to be stricter (now uses a whilelist-based js escaper)
458 * added the following filers: "constant", "trans", "replace", "json_encode"
459 * added a "constant" test
460 * fixed objects with __toString() not being autoescaped
461 * fixed subscript expressions when calling __call() (methods now keep the case)
462 * added "test" feature (accessible via the "is" operator)
463 * removed the debug tag (should be done in an extension)
464 * fixed trans tag when no vars are used in plural form
465 * fixed race condition when writing template cache
466 * added the special _charset variable to reference the current charset
467 * added the special _context variable to reference the current context
468 * renamed self to _self (to avoid conflict)
469 * fixed Twig_Template::getAttribute() for protected properties
470
471* 0.9.8 (2010-06-28)
472
473Backward incompatibilities:
474 * the trans tag plural count is now attached to the plural tag:
475 old: `{% trans count %}...{% plural %}...{% endtrans %}`
476 new: `{% trans %}...{% plural count %}...{% endtrans %}`
477
478 * added a way to translate strings coming from a variable ({% trans var %})
479 * fixed trans tag when used with the Escaper extension
480 * fixed default cache umask
481 * removed Twig_Template instances from the debug tag output
482 * fixed objects with __isset() defined
483 * fixed set tag when used with a capture
484 * fixed type hinting for Twig_Environment::addFilter() method
485
486* 0.9.7 (2010-06-12)
487
488Backward incompatibilities:
489 * changed 'as' to '=' for the set tag ({% set title as "Title" %} must now be {% set title = "Title" %})
490 * removed the sandboxed attribute of the include tag (use the new sandbox tag instead)
491 * refactored the Node system (if you have custom nodes, you will have to update them to use the new API)
492
493 * added self as a special variable that refers to the current template (useful for importing macros from the current template)
494 * added Twig_Template instance support to the include tag
495 * added support for dynamic and conditional inheritance ({% extends some_var %} and {% extends standalone ? "minimum" : "base" %})
496 * added a grammar sub-framework to ease the creation of custom tags
497 * fixed the for tag for large arrays (some loop variables are now only available for arrays and objects that implement the Countable interface)
498 * removed the Twig_Resource::resolveMissingFilter() method
499 * fixed the filter tag which did not apply filtering to included files
500 * added a bunch of unit tests
501 * added a bunch of phpdoc
502 * added a sandbox tag in the sandbox extension
503 * changed the date filter to support any date format supported by DateTime
504 * added strict_variable setting to throw an exception when an invalid variable is used in a template (disabled by default)
505 * added the lexer, parser, and compiler as arguments to the Twig_Environment constructor
506 * changed the cache option to only accepts an explicit path to a cache directory or false
507 * added a way to add token parsers, filters, and visitors without creating an extension
508 * added three interfaces: Twig_NodeInterface, Twig_TokenParserInterface, and Twig_FilterInterface
509 * changed the generated code to match the new coding standards
510 * fixed sandbox mode (__toString() method check was not enforced if called implicitly from a simple statement like {{ article }})
511 * added an exception when a child template has a non-empty body (as it is always ignored when rendering)
512
513* 0.9.6 (2010-05-12)
514
515 * fixed variables defined outside a loop and for which the value changes in a for loop
516 * fixed the test suite for PHP 5.2 and older versions of PHPUnit
517 * added support for __call() in expression resolution
518 * fixed node visiting for macros (macros are now visited by visitors as any other node)
519 * fixed nested block definitions with a parent call (rarely useful but nonetheless supported now)
520 * added the cycle filter
521 * fixed the Lexer when mbstring.func_overload is used with an mbstring.internal_encoding different from ASCII
522 * added a long-syntax for the set tag ({% set foo %}...{% endset %})
523 * unit tests are now powered by PHPUnit
524 * added support for gettext via the `i18n` extension
525 * fixed twig_capitalize_string_filter() and fixed twig_length_filter() when used with UTF-8 values
526 * added a more useful exception if an if tag is not closed properly
527 * added support for escaping strategy in the autoescape tag
528 * fixed lexer when a template has a big chunk of text between/in a block
529
530* 0.9.5 (2010-01-20)
531
532As for any new release, don't forget to remove all cached templates after
533upgrading.
534
535If you have defined custom filters, you MUST upgrade them for this release. To
536upgrade, replace "array" with "new Twig_Filter_Function", and replace the
537environment constant by the "needs_environment" option:
538
539 // before
540 'even' => array('twig_is_even_filter', false),
541 'escape' => array('twig_escape_filter', true),
542
543 // after
544 'even' => new Twig_Filter_Function('twig_is_even_filter'),
545 'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)),
546
547If you have created NodeTransformer classes, you will need to upgrade them to
548the new interface (please note that the interface is not yet considered
549stable).
550
551 * fixed list nodes that did not extend the Twig_NodeListInterface
552 * added the "without loop" option to the for tag (it disables the generation of the loop variable)
553 * refactored node transformers to node visitors
554 * fixed automatic-escaping for blocks
555 * added a way to specify variables to pass to an included template
556 * changed the automatic-escaping rules to be more sensible and more configurable in custom filters (the documentation lists all the rules)
557 * improved the filter system to allow object methods to be used as filters
558 * changed the Array and String loaders to actually make use of the cache mechanism
559 * included the default filter function definitions in the extension class files directly (Core, Escaper)
560 * added the // operator (like the floor() PHP function)
561 * added the .. operator (as a syntactic sugar for the range filter when the step is 1)
562 * added the in operator (as a syntactic sugar for the in filter)
563 * added the following filters in the Core extension: in, range
564 * added support for arrays (same behavior as in PHP, a mix between lists and dictionaries, arrays and hashes)
565 * enhanced some error messages to provide better feedback in case of parsing errors
566
567* 0.9.4 (2009-12-02)
568
569If you have custom loaders, you MUST upgrade them for this release: The
570Twig_Loader base class has been removed, and the Twig_LoaderInterface has also
571been changed (see the source code for more information or the documentation).
572
573 * added support for DateTime instances for the date filter
574 * fixed loop.last when the array only has one item
575 * made it possible to insert newlines in tag and variable blocks
576 * fixed a bug when a literal '\n' were present in a template text
577 * fixed bug when the filename of a template contains */
578 * refactored loaders
579
580* 0.9.3 (2009-11-11)
581
582This release is NOT backward compatible with the previous releases.
583
584 The loaders do not take the cache and autoReload arguments anymore. Instead,
585 the Twig_Environment class has two new options: cache and auto_reload.
586 Upgrading your code means changing this kind of code:
587
588 $loader = new Twig_Loader_Filesystem('/path/to/templates', '/path/to/compilation_cache', true);
589 $twig = new Twig_Environment($loader);
590
591 to something like this:
592
593 $loader = new Twig_Loader_Filesystem('/path/to/templates');
594 $twig = new Twig_Environment($loader, array(
595 'cache' => '/path/to/compilation_cache',
596 'auto_reload' => true,
597 ));
598
599 * deprecated the "items" filter as it is not needed anymore
600 * made cache and auto_reload options of Twig_Environment instead of arguments of Twig_Loader
601 * optimized template loading speed
602 * removed output when an error occurs in a template and render() is used
603 * made major speed improvements for loops (up to 300% on even the smallest loops)
604 * added properties as part of the sandbox mode
605 * added public properties support (obj.item can now be the item property on the obj object)
606 * extended set tag to support expression as value ({% set foo as 'foo' ~ 'bar' %} )
607 * fixed bug when \ was used in HTML
608
609* 0.9.2 (2009-10-29)
610
611 * made some speed optimizations
612 * changed the cache extension to .php
613 * added a js escaping strategy
614 * added support for short block tag
615 * changed the filter tag to allow chained filters
616 * made lexer more flexible as you can now change the default delimiters
617 * added set tag
618 * changed default directory permission when cache dir does not exist (more secure)
619 * added macro support
620 * changed filters first optional argument to be a Twig_Environment instance instead of a Twig_Template instance
621 * made Twig_Autoloader::autoload() a static method
622 * avoid writing template file if an error occurs
623 * added $ escaping when outputting raw strings
624 * enhanced some error messages to ease debugging
625 * fixed empty cache files when the template contains an error
626
627* 0.9.1 (2009-10-14)
628
629 * fixed a bug in PHP 5.2.6
630 * fixed numbers with one than one decimal
631 * added support for method calls with arguments ({{ foo.bar('a', 43) }})
632 * made small speed optimizations
633 * made minor tweaks to allow better extensibility and flexibility
634
635* 0.9.0 (2009-10-12)
636
637 * Initial release
diff --git a/vendor/twig/twig/LICENSE b/vendor/twig/twig/LICENSE
new file mode 100644
index 00000000..3384cc55
--- /dev/null
+++ b/vendor/twig/twig/LICENSE
@@ -0,0 +1,31 @@
1Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details.
2
3Some rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16
17 * The names of the contributors may not be used to endorse or
18 promote products derived from this software without specific
19 prior written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/twig/twig/README.markdown b/vendor/twig/twig/README.markdown
new file mode 100644
index 00000000..88d6fabc
--- /dev/null
+++ b/vendor/twig/twig/README.markdown
@@ -0,0 +1,17 @@
1Twig, the flexible, fast, and secure template language for PHP
2==============================================================
3
4[![Build Status](https://secure.travis-ci.org/fabpot/Twig.png?branch=master)](http://travis-ci.org/fabpot/Twig)
5
6Twig is a template language for PHP, released under the new BSD license (code
7and documentation).
8
9Twig uses a syntax similar to the Django and Jinja template languages which
10inspired the Twig runtime environment.
11
12More Information
13----------------
14
15Read the [documentation][1] for more information.
16
17[1]: http://twig.sensiolabs.org/documentation
diff --git a/vendor/twig/twig/composer.json b/vendor/twig/twig/composer.json
new file mode 100644
index 00000000..67a08aad
--- /dev/null
+++ b/vendor/twig/twig/composer.json
@@ -0,0 +1,31 @@
1{
2 "name": "twig/twig",
3 "type": "library",
4 "description": "Twig, the flexible, fast, and secure template language for PHP",
5 "keywords": ["templating"],
6 "homepage": "http://twig.sensiolabs.org",
7 "license": "BSD-3-Clause",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Armin Ronacher",
15 "email": "armin.ronacher@active-4.com"
16 }
17 ],
18 "require": {
19 "php": ">=5.2.4"
20 },
21 "autoload": {
22 "psr-0" : {
23 "Twig_" : "lib/"
24 }
25 },
26 "extra": {
27 "branch-alias": {
28 "dev-master": "1.13-dev"
29 }
30 }
31}
diff --git a/vendor/twig/twig/doc/advanced.rst b/vendor/twig/twig/doc/advanced.rst
new file mode 100644
index 00000000..e1945ebb
--- /dev/null
+++ b/vendor/twig/twig/doc/advanced.rst
@@ -0,0 +1,829 @@
1Extending Twig
2==============
3
4.. caution::
5
6 This section describes how to extend Twig as of **Twig 1.12**. If you are
7 using an older version, read the :doc:`legacy<advanced_legacy>` chapter
8 instead.
9
10Twig can be extended in many ways; you can add extra tags, filters, tests,
11operators, global variables, and functions. You can even extend the parser
12itself with node visitors.
13
14.. note::
15
16 The first section of this chapter describes how to extend Twig easily. If
17 you want to reuse your changes in different projects or if you want to
18 share them with others, you should then create an extension as described
19 in the following section.
20
21.. caution::
22
23 When extending Twig without creating an extension, Twig won't be able to
24 recompile your templates when the PHP code is updated. To see your changes
25 in real-time, either disable template caching or package your code into an
26 extension (see the next section of this chapter).
27
28Before extending Twig, you must understand the differences between all the
29different possible extension points and when to use them.
30
31First, remember that Twig has two main language constructs:
32
33* ``{{ }}``: used to print the result of an expression evaluation;
34
35* ``{% %}``: used to execute statements.
36
37To understand why Twig exposes so many extension points, let's see how to
38implement a *Lorem ipsum* generator (it needs to know the number of words to
39generate).
40
41You can use a ``lipsum`` *tag*:
42
43.. code-block:: jinja
44
45 {% lipsum 40 %}
46
47That works, but using a tag for ``lipsum`` is not a good idea for at least
48three main reasons:
49
50* ``lipsum`` is not a language construct;
51* The tag outputs something;
52* The tag is not flexible as you cannot use it in an expression:
53
54 .. code-block:: jinja
55
56 {{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }}
57
58In fact, you rarely need to create tags; and that's good news because tags are
59the most complex extension point of Twig.
60
61Now, let's use a ``lipsum`` *filter*:
62
63.. code-block:: jinja
64
65 {{ 40|lipsum }}
66
67Again, it works, but it looks weird. A filter transforms the passed value to
68something else but here we use the value to indicate the number of words to
69generate (so, ``40`` is an argument of the filter, not the value we want to
70transform).
71
72Next, let's use a ``lipsum`` *function*:
73
74.. code-block:: jinja
75
76 {{ lipsum(40) }}
77
78Here we go. For this specific example, the creation of a function is the
79extension point to use. And you can use it anywhere an expression is accepted:
80
81.. code-block:: jinja
82
83 {{ 'some text' ~ lipsum(40) ~ 'some more text' }}
84
85 {% set lipsum = lipsum(40) %}
86
87Last but not the least, you can also use a *global* object with a method able
88to generate lorem ipsum text:
89
90.. code-block:: jinja
91
92 {{ text.lipsum(40) }}
93
94As a rule of thumb, use functions for frequently used features and global
95objects for everything else.
96
97Keep in mind the following when you want to extend Twig:
98
99========== ========================== ========== =========================
100What? Implementation difficulty? How often? When?
101========== ========================== ========== =========================
102*macro* trivial frequent Content generation
103*global* trivial frequent Helper object
104*function* trivial frequent Content generation
105*filter* trivial frequent Value transformation
106*tag* complex rare DSL language construct
107*test* trivial rare Boolean decision
108*operator* trivial rare Values transformation
109========== ========================== ========== =========================
110
111Globals
112-------
113
114A global variable is like any other template variable, except that it's
115available in all templates and macros::
116
117 $twig = new Twig_Environment($loader);
118 $twig->addGlobal('text', new Text());
119
120You can then use the ``text`` variable anywhere in a template:
121
122.. code-block:: jinja
123
124 {{ text.lipsum(40) }}
125
126Filters
127-------
128
129Creating a filter is as simple as associating a name with a PHP callable::
130
131 // an anonymous function
132 $filter = new Twig_SimpleFilter('rot13', function ($string) {
133 return str_rot13($string);
134 });
135
136 // or a simple PHP function
137 $filter = new Twig_SimpleFilter('rot13', 'str_rot13');
138
139 // or a class method
140 $filter = new Twig_SimpleFilter('rot13', array('SomeClass', 'rot13Filter'));
141
142The first argument passed to the ``Twig_SimpleFilter`` constructor is the name
143of the filter you will use in templates and the second one is the PHP callable
144to associate with it.
145
146Then, add the filter to your Twig environment::
147
148 $twig = new Twig_Environment($loader);
149 $twig->addFilter($filter);
150
151And here is how to use it in a template:
152
153.. code-block:: jinja
154
155 {{ 'Twig'|rot13 }}
156
157 {# will output Gjvt #}
158
159When called by Twig, the PHP callable receives the left side of the filter
160(before the pipe ``|``) as the first argument and the extra arguments passed
161to the filter (within parentheses ``()``) as extra arguments.
162
163For instance, the following code:
164
165.. code-block:: jinja
166
167 {{ 'TWIG'|lower }}
168 {{ now|date('d/m/Y') }}
169
170is compiled to something like the following::
171
172 <?php echo strtolower('TWIG') ?>
173 <?php echo twig_date_format_filter($now, 'd/m/Y') ?>
174
175The ``Twig_SimpleFilter`` class takes an array of options as its last
176argument::
177
178 $filter = new Twig_SimpleFilter('rot13', 'str_rot13', $options);
179
180Environment aware Filters
181~~~~~~~~~~~~~~~~~~~~~~~~~
182
183If you want to access the current environment instance in your filter, set the
184``needs_environment`` option to ``true``; Twig will pass the current
185environment as the first argument to the filter call::
186
187 $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $string) {
188 // get the current charset for instance
189 $charset = $env->getCharset();
190
191 return str_rot13($string);
192 }, array('needs_environment' => true));
193
194Context aware Filters
195~~~~~~~~~~~~~~~~~~~~~
196
197If you want to access the current context in your filter, set the
198``needs_context`` option to ``true``; Twig will pass the current context as
199the first argument to the filter call (or the second one if
200``needs_environment`` is also set to ``true``)::
201
202 $filter = new Twig_SimpleFilter('rot13', function ($context, $string) {
203 // ...
204 }, array('needs_context' => true));
205
206 $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $context, $string) {
207 // ...
208 }, array('needs_context' => true, 'needs_environment' => true));
209
210Automatic Escaping
211~~~~~~~~~~~~~~~~~~
212
213If automatic escaping is enabled, the output of the filter may be escaped
214before printing. If your filter acts as an escaper (or explicitly outputs html
215or JavaScript code), you will want the raw output to be printed. In such a
216case, set the ``is_safe`` option::
217
218 $filter = new Twig_SimpleFilter('nl2br', 'nl2br', array('is_safe' => array('html')));
219
220Some filters may need to work on input that is already escaped or safe, for
221example when adding (safe) html tags to originally unsafe output. In such a
222case, set the ``pre_escape`` option to escape the input data before it is run
223through your filter::
224
225 $filter = new Twig_SimpleFilter('somefilter', 'somefilter', array('pre_escape' => 'html', 'is_safe' => array('html')));
226
227Dynamic Filters
228~~~~~~~~~~~~~~~
229
230A filter name containing the special ``*`` character is a dynamic filter as
231the ``*`` can be any string::
232
233 $filter = new Twig_SimpleFilter('*_path', function ($name, $arguments) {
234 // ...
235 });
236
237The following filters will be matched by the above defined dynamic filter:
238
239* ``product_path``
240* ``category_path``
241
242A dynamic filter can define more than one dynamic parts::
243
244 $filter = new Twig_SimpleFilter('*_path_*', function ($name, $suffix, $arguments) {
245 // ...
246 });
247
248The filter will receive all dynamic part values before the normal filter
249arguments, but after the environment and the context. For instance, a call to
250``'foo'|a_path_b()`` will result in the following arguments to be passed to
251the filter: ``('a', 'b', 'foo')``.
252
253Functions
254---------
255
256Functions are defined in the exact same way as filters, but you need to create
257an instance of ``Twig_SimpleFunction``::
258
259 $twig = new Twig_Environment($loader);
260 $function = new Twig_SimpleFunction('function_name', function () {
261 // ...
262 });
263 $twig->addFunction($function);
264
265Functions support the same features as filters, except for the ``pre_escape``
266and ``preserves_safety`` options.
267
268Tests
269-----
270
271Tests are defined in the exact same way as filters and functions, but you need
272to create an instance of ``Twig_SimpleTest``::
273
274 $twig = new Twig_Environment($loader);
275 $test = new Twig_SimpleTest('test_name', function () {
276 // ...
277 });
278 $twig->addTest($test);
279
280Tests allow you to create custom application specific logic for evaluating
281boolean conditions. As a simple, example let's create a Twig test that checks if
282objects are 'red'::
283
284 $twig = new Twig_Environment($loader)
285 $test = new Twig_SimpleTest('red', function ($value) {
286 if (isset($value->color) && $value->color == 'red') {
287 return true;
288 }
289 if (isset($value->paint) && $value->paint == 'red') {
290 return true;
291 }
292 return false;
293 });
294 $twig->addTest($test);
295
296Test functions should always return true/false.
297
298When creating tests you can use the ``node_class`` option to provide custom test
299compilation. This is useful if your test can be compiled into PHP primitives.
300This is used by many of the tests built into Twig::
301
302 $twig = new Twig_Environment($loader)
303 $test = new Twig_SimpleTest(
304 'odd',
305 null,
306 array('node_class' => 'Twig_Node_Expression_Test_Odd'));
307 $twig->addTest($test);
308
309 class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
310 {
311 public function compile(Twig_Compiler $compiler)
312 {
313 $compiler
314 ->raw('(')
315 ->subcompile($this->getNode('node'))
316 ->raw(' % 2 == 1')
317 ->raw(')')
318 ;
319 }
320 }
321
322The above example, shows how you can create tests that use a node class. The
323node class has access to one sub-node called 'node'. This sub-node contains the
324value that is being tested. When the ``odd`` filter is used in code like:
325
326.. code-block:: jinja
327
328 {% if my_value is odd %}
329
330The ``node`` sub-node will contain an expression of ``my_value``. Node based
331tests also have access to the ``arguments`` node. This node will contain the
332various other arguments that have been provided to your test.
333
334Tags
335----
336
337One of the most exciting feature of a template engine like Twig is the
338possibility to define new language constructs. This is also the most complex
339feature as you need to understand how Twig's internals work.
340
341Let's create a simple ``set`` tag that allows the definition of simple
342variables from within a template. The tag can be used like follows:
343
344.. code-block:: jinja
345
346 {% set name = "value" %}
347
348 {{ name }}
349
350 {# should output value #}
351
352.. note::
353
354 The ``set`` tag is part of the Core extension and as such is always
355 available. The built-in version is slightly more powerful and supports
356 multiple assignments by default (cf. the template designers chapter for
357 more information).
358
359Three steps are needed to define a new tag:
360
361* Defining a Token Parser class (responsible for parsing the template code);
362
363* Defining a Node class (responsible for converting the parsed code to PHP);
364
365* Registering the tag.
366
367Registering a new tag
368~~~~~~~~~~~~~~~~~~~~~
369
370Adding a tag is as simple as calling the ``addTokenParser`` method on the
371``Twig_Environment`` instance::
372
373 $twig = new Twig_Environment($loader);
374 $twig->addTokenParser(new Project_Set_TokenParser());
375
376Defining a Token Parser
377~~~~~~~~~~~~~~~~~~~~~~~
378
379Now, let's see the actual code of this class::
380
381 class Project_Set_TokenParser extends Twig_TokenParser
382 {
383 public function parse(Twig_Token $token)
384 {
385 $parser = $this->parser;
386 $stream = $parser->getStream();
387
388 $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
389 $stream->expect(Twig_Token::OPERATOR_TYPE, '=');
390 $value = $parser->getExpressionParser()->parseExpression();
391 $stream->expect(Twig_Token::BLOCK_END_TYPE);
392
393 return new Project_Set_Node($name, $value, $token->getLine(), $this->getTag());
394 }
395
396 public function getTag()
397 {
398 return 'set';
399 }
400 }
401
402The ``getTag()`` method must return the tag we want to parse, here ``set``.
403
404The ``parse()`` method is invoked whenever the parser encounters a ``set``
405tag. It should return a ``Twig_Node`` instance that represents the node (the
406``Project_Set_Node`` calls creating is explained in the next section).
407
408The parsing process is simplified thanks to a bunch of methods you can call
409from the token stream (``$this->parser->getStream()``):
410
411* ``getCurrent()``: Gets the current token in the stream.
412
413* ``next()``: Moves to the next token in the stream, *but returns the old one*.
414
415* ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether
416 the current token is of a particular type or value (or both). The value may be an
417 array of several possible values.
418
419* ``expect($type[, $value[, $message]])``: If the current token isn't of the given
420 type/value a syntax error is thrown. Otherwise, if the type and value are correct,
421 the token is returned and the stream moves to the next token.
422
423* ``look()``: Looks a the next token without consuming it.
424
425Parsing expressions is done by calling the ``parseExpression()`` like we did for
426the ``set`` tag.
427
428.. tip::
429
430 Reading the existing ``TokenParser`` classes is the best way to learn all
431 the nitty-gritty details of the parsing process.
432
433Defining a Node
434~~~~~~~~~~~~~~~
435
436The ``Project_Set_Node`` class itself is rather simple::
437
438 class Project_Set_Node extends Twig_Node
439 {
440 public function __construct($name, Twig_Node_Expression $value, $line, $tag = null)
441 {
442 parent::__construct(array('value' => $value), array('name' => $name), $line, $tag);
443 }
444
445 public function compile(Twig_Compiler $compiler)
446 {
447 $compiler
448 ->addDebugInfo($this)
449 ->write('$context[\''.$this->getAttribute('name').'\'] = ')
450 ->subcompile($this->getNode('value'))
451 ->raw(";\n")
452 ;
453 }
454 }
455
456The compiler implements a fluid interface and provides methods that helps the
457developer generate beautiful and readable PHP code:
458
459* ``subcompile()``: Compiles a node.
460
461* ``raw()``: Writes the given string as is.
462
463* ``write()``: Writes the given string by adding indentation at the beginning
464 of each line.
465
466* ``string()``: Writes a quoted string.
467
468* ``repr()``: Writes a PHP representation of a given value (see
469 ``Twig_Node_For`` for a usage example).
470
471* ``addDebugInfo()``: Adds the line of the original template file related to
472 the current node as a comment.
473
474* ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a
475 usage example).
476
477* ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a
478 usage example).
479
480.. _creating_extensions:
481
482Creating an Extension
483---------------------
484
485The main motivation for writing an extension is to move often used code into a
486reusable class like adding support for internationalization. An extension can
487define tags, filters, tests, operators, global variables, functions, and node
488visitors.
489
490Creating an extension also makes for a better separation of code that is
491executed at compilation time and code needed at runtime. As such, it makes
492your code faster.
493
494Most of the time, it is useful to create a single extension for your project,
495to host all the specific tags and filters you want to add to Twig.
496
497.. tip::
498
499 When packaging your code into an extension, Twig is smart enough to
500 recompile your templates whenever you make a change to it (when
501 ``auto_reload`` is enabled).
502
503.. note::
504
505 Before writing your own extensions, have a look at the Twig official
506 extension repository: http://github.com/fabpot/Twig-extensions.
507
508An extension is a class that implements the following interface::
509
510 interface Twig_ExtensionInterface
511 {
512 /**
513 * Initializes the runtime environment.
514 *
515 * This is where you can load some file that contains filter functions for instance.
516 *
517 * @param Twig_Environment $environment The current Twig_Environment instance
518 */
519 function initRuntime(Twig_Environment $environment);
520
521 /**
522 * Returns the token parser instances to add to the existing list.
523 *
524 * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
525 */
526 function getTokenParsers();
527
528 /**
529 * Returns the node visitor instances to add to the existing list.
530 *
531 * @return array An array of Twig_NodeVisitorInterface instances
532 */
533 function getNodeVisitors();
534
535 /**
536 * Returns a list of filters to add to the existing list.
537 *
538 * @return array An array of filters
539 */
540 function getFilters();
541
542 /**
543 * Returns a list of tests to add to the existing list.
544 *
545 * @return array An array of tests
546 */
547 function getTests();
548
549 /**
550 * Returns a list of functions to add to the existing list.
551 *
552 * @return array An array of functions
553 */
554 function getFunctions();
555
556 /**
557 * Returns a list of operators to add to the existing list.
558 *
559 * @return array An array of operators
560 */
561 function getOperators();
562
563 /**
564 * Returns a list of global variables to add to the existing list.
565 *
566 * @return array An array of global variables
567 */
568 function getGlobals();
569
570 /**
571 * Returns the name of the extension.
572 *
573 * @return string The extension name
574 */
575 function getName();
576 }
577
578To keep your extension class clean and lean, it can inherit from the built-in
579``Twig_Extension`` class instead of implementing the whole interface. That
580way, you just need to implement the ``getName()`` method as the
581``Twig_Extension`` provides empty implementations for all other methods.
582
583The ``getName()`` method must return a unique identifier for your extension.
584
585Now, with this information in mind, let's create the most basic extension
586possible::
587
588 class Project_Twig_Extension extends Twig_Extension
589 {
590 public function getName()
591 {
592 return 'project';
593 }
594 }
595
596.. note::
597
598 Of course, this extension does nothing for now. We will customize it in
599 the next sections.
600
601Twig does not care where you save your extension on the filesystem, as all
602extensions must be registered explicitly to be available in your templates.
603
604You can register an extension by using the ``addExtension()`` method on your
605main ``Environment`` object::
606
607 $twig = new Twig_Environment($loader);
608 $twig->addExtension(new Project_Twig_Extension());
609
610Of course, you need to first load the extension file by either using
611``require_once()`` or by using an autoloader (see `spl_autoload_register()`_).
612
613.. tip::
614
615 The bundled extensions are great examples of how extensions work.
616
617Globals
618~~~~~~~
619
620Global variables can be registered in an extension via the ``getGlobals()``
621method::
622
623 class Project_Twig_Extension extends Twig_Extension
624 {
625 public function getGlobals()
626 {
627 return array(
628 'text' => new Text(),
629 );
630 }
631
632 // ...
633 }
634
635Functions
636~~~~~~~~~
637
638Functions can be registered in an extension via the ``getFunctions()``
639method::
640
641 class Project_Twig_Extension extends Twig_Extension
642 {
643 public function getFunctions()
644 {
645 return array(
646 new Twig_SimpleFunction('lipsum', 'generate_lipsum'),
647 );
648 }
649
650 // ...
651 }
652
653Filters
654~~~~~~~
655
656To add a filter to an extension, you need to override the ``getFilters()``
657method. This method must return an array of filters to add to the Twig
658environment::
659
660 class Project_Twig_Extension extends Twig_Extension
661 {
662 public function getFilters()
663 {
664 return array(
665 new Twig_SimpleFilter('rot13', 'str_rot13'),
666 );
667 }
668
669 // ...
670 }
671
672Tags
673~~~~
674
675Adding a tag in an extension can be done by overriding the
676``getTokenParsers()`` method. This method must return an array of tags to add
677to the Twig environment::
678
679 class Project_Twig_Extension extends Twig_Extension
680 {
681 public function getTokenParsers()
682 {
683 return array(new Project_Set_TokenParser());
684 }
685
686 // ...
687 }
688
689In the above code, we have added a single new tag, defined by the
690``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
691responsible for parsing the tag and compiling it to PHP.
692
693Operators
694~~~~~~~~~
695
696The ``getOperators()`` methods allows to add new operators. Here is how to add
697``!``, ``||``, and ``&&`` operators::
698
699 class Project_Twig_Extension extends Twig_Extension
700 {
701 public function getOperators()
702 {
703 return array(
704 array(
705 '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
706 ),
707 array(
708 '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
709 '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
710 ),
711 );
712 }
713
714 // ...
715 }
716
717Tests
718~~~~~
719
720The ``getTests()`` methods allows to add new test functions::
721
722 class Project_Twig_Extension extends Twig_Extension
723 {
724 public function getTests()
725 {
726 return array(
727 new Twig_SimpleTest('even', 'twig_test_even'),
728 );
729 }
730
731 // ...
732 }
733
734Overloading
735-----------
736
737To overload an already defined filter, test, operator, global variable, or
738function, define it again **as late as possible**::
739
740 $twig = new Twig_Environment($loader);
741 $twig->addFilter(new Twig_SimpleFilter('date', function ($timestamp, $format = 'F j, Y H:i') {
742 // do something different from the built-in date filter
743 }));
744
745Here, we have overloaded the built-in ``date`` filter with a custom one.
746
747That also works with an extension::
748
749 class MyCoreExtension extends Twig_Extension
750 {
751 public function getFilters()
752 {
753 return array(
754 new Twig_SimpleFilter('date', array($this, 'dateFilter')),
755 );
756 }
757
758 public function dateFilter($timestamp, $format = 'F j, Y H:i')
759 {
760 // do something different from the built-in date filter
761 }
762
763 public function getName()
764 {
765 return 'project';
766 }
767 }
768
769 $twig = new Twig_Environment($loader);
770 $twig->addExtension(new MyCoreExtension());
771
772.. caution::
773
774 Note that overloading the built-in Twig elements is not recommended as it
775 might be confusing.
776
777Testing an Extension
778--------------------
779
780Functional Tests
781~~~~~~~~~~~~~~~~
782
783You can create functional tests for extensions simply by creating the
784following file structure in your test directory::
785
786 Fixtures/
787 filters/
788 foo.test
789 bar.test
790 functions/
791 foo.test
792 bar.test
793 tags/
794 foo.test
795 bar.test
796 IntegrationTest.php
797
798The ``IntegrationTest.php`` file should look like this::
799
800 class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
801 {
802 public function getExtensions()
803 {
804 return array(
805 new Project_Twig_Extension1(),
806 new Project_Twig_Extension2(),
807 );
808 }
809
810 public function getFixturesDir()
811 {
812 return dirname(__FILE__).'/Fixtures/';
813 }
814 }
815
816Fixtures examples can be found within the Twig repository
817`tests/Twig/Fixtures`_ directory.
818
819Node Tests
820~~~~~~~~~~
821
822Testing the node visitors can be complex, so extend your test cases from
823``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository
824`tests/Twig/Node`_ directory.
825
826.. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register
827.. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php
828.. _`tests/Twig/Fixtures`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures
829.. _`tests/Twig/Node`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node
diff --git a/vendor/twig/twig/doc/advanced_legacy.rst b/vendor/twig/twig/doc/advanced_legacy.rst
new file mode 100644
index 00000000..3d34f932
--- /dev/null
+++ b/vendor/twig/twig/doc/advanced_legacy.rst
@@ -0,0 +1,887 @@
1Extending Twig
2==============
3
4.. caution::
5
6 This section describes how to extends Twig for versions **older than
7 1.12**. If you are using a newer version, read the :doc:`newer<advanced>`
8 chapter instead.
9
10Twig can be extended in many ways; you can add extra tags, filters, tests,
11operators, global variables, and functions. You can even extend the parser
12itself with node visitors.
13
14.. note::
15
16 The first section of this chapter describes how to extend Twig easily. If
17 you want to reuse your changes in different projects or if you want to
18 share them with others, you should then create an extension as described
19 in the following section.
20
21.. caution::
22
23 When extending Twig by calling methods on the Twig environment instance,
24 Twig won't be able to recompile your templates when the PHP code is
25 updated. To see your changes in real-time, either disable template caching
26 or package your code into an extension (see the next section of this
27 chapter).
28
29Before extending Twig, you must understand the differences between all the
30different possible extension points and when to use them.
31
32First, remember that Twig has two main language constructs:
33
34* ``{{ }}``: used to print the result of an expression evaluation;
35
36* ``{% %}``: used to execute statements.
37
38To understand why Twig exposes so many extension points, let's see how to
39implement a *Lorem ipsum* generator (it needs to know the number of words to
40generate).
41
42You can use a ``lipsum`` *tag*:
43
44.. code-block:: jinja
45
46 {% lipsum 40 %}
47
48That works, but using a tag for ``lipsum`` is not a good idea for at least
49three main reasons:
50
51* ``lipsum`` is not a language construct;
52* The tag outputs something;
53* The tag is not flexible as you cannot use it in an expression:
54
55 .. code-block:: jinja
56
57 {{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }}
58
59In fact, you rarely need to create tags; and that's good news because tags are
60the most complex extension point of Twig.
61
62Now, let's use a ``lipsum`` *filter*:
63
64.. code-block:: jinja
65
66 {{ 40|lipsum }}
67
68Again, it works, but it looks weird. A filter transforms the passed value to
69something else but here we use the value to indicate the number of words to
70generate (so, ``40`` is an argument of the filter, not the value we want to
71transform).
72
73Next, let's use a ``lipsum`` *function*:
74
75.. code-block:: jinja
76
77 {{ lipsum(40) }}
78
79Here we go. For this specific example, the creation of a function is the
80extension point to use. And you can use it anywhere an expression is accepted:
81
82.. code-block:: jinja
83
84 {{ 'some text' ~ ipsum(40) ~ 'some more text' }}
85
86 {% set ipsum = ipsum(40) %}
87
88Last but not the least, you can also use a *global* object with a method able
89to generate lorem ipsum text:
90
91.. code-block:: jinja
92
93 {{ text.lipsum(40) }}
94
95As a rule of thumb, use functions for frequently used features and global
96objects for everything else.
97
98Keep in mind the following when you want to extend Twig:
99
100========== ========================== ========== =========================
101What? Implementation difficulty? How often? When?
102========== ========================== ========== =========================
103*macro* trivial frequent Content generation
104*global* trivial frequent Helper object
105*function* trivial frequent Content generation
106*filter* trivial frequent Value transformation
107*tag* complex rare DSL language construct
108*test* trivial rare Boolean decision
109*operator* trivial rare Values transformation
110========== ========================== ========== =========================
111
112Globals
113-------
114
115A global variable is like any other template variable, except that it's
116available in all templates and macros::
117
118 $twig = new Twig_Environment($loader);
119 $twig->addGlobal('text', new Text());
120
121You can then use the ``text`` variable anywhere in a template:
122
123.. code-block:: jinja
124
125 {{ text.lipsum(40) }}
126
127Filters
128-------
129
130A filter is a regular PHP function or an object method that takes the left
131side of the filter (before the pipe ``|``) as first argument and the extra
132arguments passed to the filter (within parentheses ``()``) as extra arguments.
133
134Defining a filter is as easy as associating the filter name with a PHP
135callable. For instance, let's say you have the following code in a template:
136
137.. code-block:: jinja
138
139 {{ 'TWIG'|lower }}
140
141When compiling this template to PHP, Twig looks for the PHP callable
142associated with the ``lower`` filter. The ``lower`` filter is a built-in Twig
143filter, and it is simply mapped to the PHP ``strtolower()`` function. After
144compilation, the generated PHP code is roughly equivalent to:
145
146.. code-block:: html+php
147
148 <?php echo strtolower('TWIG') ?>
149
150As you can see, the ``'TWIG'`` string is passed as a first argument to the PHP
151function.
152
153A filter can also take extra arguments like in the following example:
154
155.. code-block:: jinja
156
157 {{ now|date('d/m/Y') }}
158
159In this case, the extra arguments are passed to the function after the main
160argument, and the compiled code is equivalent to:
161
162.. code-block:: html+php
163
164 <?php echo twig_date_format_filter($now, 'd/m/Y') ?>
165
166Let's see how to create a new filter.
167
168In this section, we will create a ``rot13`` filter, which should return the
169`rot13`_ transformation of a string. Here is an example of its usage and the
170expected output:
171
172.. code-block:: jinja
173
174 {{ "Twig"|rot13 }}
175
176 {# should displays Gjvt #}
177
178Adding a filter is as simple as calling the ``addFilter()`` method on the
179``Twig_Environment`` instance::
180
181 $twig = new Twig_Environment($loader);
182 $twig->addFilter('rot13', new Twig_Filter_Function('str_rot13'));
183
184The second argument of ``addFilter()`` is an instance of ``Twig_Filter``.
185Here, we use ``Twig_Filter_Function`` as the filter is a PHP function. The
186first argument passed to the ``Twig_Filter_Function`` constructor is the name
187of the PHP function to call, here ``str_rot13``, a native PHP function.
188
189Let's say I now want to be able to add a prefix before the converted string:
190
191.. code-block:: jinja
192
193 {{ "Twig"|rot13('prefix_') }}
194
195 {# should displays prefix_Gjvt #}
196
197As the PHP ``str_rot13()`` function does not support this requirement, let's
198create a new PHP function::
199
200 function project_compute_rot13($string, $prefix = '')
201 {
202 return $prefix.str_rot13($string);
203 }
204
205As you can see, the ``prefix`` argument of the filter is passed as an extra
206argument to the ``project_compute_rot13()`` function.
207
208Adding this filter is as easy as before::
209
210 $twig->addFilter('rot13', new Twig_Filter_Function('project_compute_rot13'));
211
212For better encapsulation, a filter can also be defined as a static method of a
213class. The ``Twig_Filter_Function`` class can also be used to register such
214static methods as filters::
215
216 $twig->addFilter('rot13', new Twig_Filter_Function('SomeClass::rot13Filter'));
217
218.. tip::
219
220 In an extension, you can also define a filter as a static method of the
221 extension class.
222
223Environment aware Filters
224~~~~~~~~~~~~~~~~~~~~~~~~~
225
226The ``Twig_Filter`` classes take options as their last argument. For instance,
227if you want access to the current environment instance in your filter, set the
228``needs_environment`` option to ``true``::
229
230 $filter = new Twig_Filter_Function('str_rot13', array('needs_environment' => true));
231
232Twig will then pass the current environment as the first argument to the
233filter call::
234
235 function twig_compute_rot13(Twig_Environment $env, $string)
236 {
237 // get the current charset for instance
238 $charset = $env->getCharset();
239
240 return str_rot13($string);
241 }
242
243Automatic Escaping
244~~~~~~~~~~~~~~~~~~
245
246If automatic escaping is enabled, the output of the filter may be escaped
247before printing. If your filter acts as an escaper (or explicitly outputs html
248or javascript code), you will want the raw output to be printed. In such a
249case, set the ``is_safe`` option::
250
251 $filter = new Twig_Filter_Function('nl2br', array('is_safe' => array('html')));
252
253Some filters may need to work on input that is already escaped or safe, for
254example when adding (safe) html tags to originally unsafe output. In such a
255case, set the ``pre_escape`` option to escape the input data before it is run
256through your filter::
257
258 $filter = new Twig_Filter_Function('somefilter', array('pre_escape' => 'html', 'is_safe' => array('html')));
259
260Dynamic Filters
261~~~~~~~~~~~~~~~
262
263.. versionadded:: 1.5
264 Dynamic filters support was added in Twig 1.5.
265
266A filter name containing the special ``*`` character is a dynamic filter as
267the ``*`` can be any string::
268
269 $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
270
271 function twig_path($name, $arguments)
272 {
273 // ...
274 }
275
276The following filters will be matched by the above defined dynamic filter:
277
278* ``product_path``
279* ``category_path``
280
281A dynamic filter can define more than one dynamic parts::
282
283 $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
284
285 function twig_path($name, $suffix, $arguments)
286 {
287 // ...
288 }
289
290The filter will receive all dynamic part values before the normal filters
291arguments. For instance, a call to ``'foo'|a_path_b()`` will result in the
292following PHP call: ``twig_path('a', 'b', 'foo')``.
293
294Functions
295---------
296
297A function is a regular PHP function or an object method that can be called from
298templates.
299
300.. code-block:: jinja
301
302 {{ constant("DATE_W3C") }}
303
304When compiling this template to PHP, Twig looks for the PHP callable
305associated with the ``constant`` function. The ``constant`` function is a built-in Twig
306function, and it is simply mapped to the PHP ``constant()`` function. After
307compilation, the generated PHP code is roughly equivalent to:
308
309.. code-block:: html+php
310
311 <?php echo constant('DATE_W3C') ?>
312
313Adding a function is similar to adding a filter. This can be done by calling the
314``addFunction()`` method on the ``Twig_Environment`` instance::
315
316 $twig = new Twig_Environment($loader);
317 $twig->addFunction('functionName', new Twig_Function_Function('someFunction'));
318
319You can also expose extension methods as functions in your templates::
320
321 // $this is an object that implements Twig_ExtensionInterface.
322 $twig = new Twig_Environment($loader);
323 $twig->addFunction('otherFunction', new Twig_Function_Method($this, 'someMethod'));
324
325Functions also support ``needs_environment`` and ``is_safe`` parameters.
326
327Dynamic Functions
328~~~~~~~~~~~~~~~~~
329
330.. versionadded:: 1.5
331 Dynamic functions support was added in Twig 1.5.
332
333A function name containing the special ``*`` character is a dynamic function
334as the ``*`` can be any string::
335
336 $twig->addFunction('*_path', new Twig_Function_Function('twig_path'));
337
338 function twig_path($name, $arguments)
339 {
340 // ...
341 }
342
343The following functions will be matched by the above defined dynamic function:
344
345* ``product_path``
346* ``category_path``
347
348A dynamic function can define more than one dynamic parts::
349
350 $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
351
352 function twig_path($name, $suffix, $arguments)
353 {
354 // ...
355 }
356
357The function will receive all dynamic part values before the normal functions
358arguments. For instance, a call to ``a_path_b('foo')`` will result in the
359following PHP call: ``twig_path('a', 'b', 'foo')``.
360
361Tags
362----
363
364One of the most exciting feature of a template engine like Twig is the
365possibility to define new language constructs. This is also the most complex
366feature as you need to understand how Twig's internals work.
367
368Let's create a simple ``set`` tag that allows the definition of simple
369variables from within a template. The tag can be used like follows:
370
371.. code-block:: jinja
372
373 {% set name = "value" %}
374
375 {{ name }}
376
377 {# should output value #}
378
379.. note::
380
381 The ``set`` tag is part of the Core extension and as such is always
382 available. The built-in version is slightly more powerful and supports
383 multiple assignments by default (cf. the template designers chapter for
384 more information).
385
386Three steps are needed to define a new tag:
387
388* Defining a Token Parser class (responsible for parsing the template code);
389
390* Defining a Node class (responsible for converting the parsed code to PHP);
391
392* Registering the tag.
393
394Registering a new tag
395~~~~~~~~~~~~~~~~~~~~~
396
397Adding a tag is as simple as calling the ``addTokenParser`` method on the
398``Twig_Environment`` instance::
399
400 $twig = new Twig_Environment($loader);
401 $twig->addTokenParser(new Project_Set_TokenParser());
402
403Defining a Token Parser
404~~~~~~~~~~~~~~~~~~~~~~~
405
406Now, let's see the actual code of this class::
407
408 class Project_Set_TokenParser extends Twig_TokenParser
409 {
410 public function parse(Twig_Token $token)
411 {
412 $lineno = $token->getLine();
413 $name = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue();
414 $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, '=');
415 $value = $this->parser->getExpressionParser()->parseExpression();
416
417 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
418
419 return new Project_Set_Node($name, $value, $lineno, $this->getTag());
420 }
421
422 public function getTag()
423 {
424 return 'set';
425 }
426 }
427
428The ``getTag()`` method must return the tag we want to parse, here ``set``.
429
430The ``parse()`` method is invoked whenever the parser encounters a ``set``
431tag. It should return a ``Twig_Node`` instance that represents the node (the
432``Project_Set_Node`` calls creating is explained in the next section).
433
434The parsing process is simplified thanks to a bunch of methods you can call
435from the token stream (``$this->parser->getStream()``):
436
437* ``getCurrent()``: Gets the current token in the stream.
438
439* ``next()``: Moves to the next token in the stream, *but returns the old one*.
440
441* ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether
442 the current token is of a particular type or value (or both). The value may be an
443 array of several possible values.
444
445* ``expect($type[, $value[, $message]])``: If the current token isn't of the given
446 type/value a syntax error is thrown. Otherwise, if the type and value are correct,
447 the token is returned and the stream moves to the next token.
448
449* ``look()``: Looks a the next token without consuming it.
450
451Parsing expressions is done by calling the ``parseExpression()`` like we did for
452the ``set`` tag.
453
454.. tip::
455
456 Reading the existing ``TokenParser`` classes is the best way to learn all
457 the nitty-gritty details of the parsing process.
458
459Defining a Node
460~~~~~~~~~~~~~~~
461
462The ``Project_Set_Node`` class itself is rather simple::
463
464 class Project_Set_Node extends Twig_Node
465 {
466 public function __construct($name, Twig_Node_Expression $value, $lineno, $tag = null)
467 {
468 parent::__construct(array('value' => $value), array('name' => $name), $lineno, $tag);
469 }
470
471 public function compile(Twig_Compiler $compiler)
472 {
473 $compiler
474 ->addDebugInfo($this)
475 ->write('$context[\''.$this->getAttribute('name').'\'] = ')
476 ->subcompile($this->getNode('value'))
477 ->raw(";\n")
478 ;
479 }
480 }
481
482The compiler implements a fluid interface and provides methods that helps the
483developer generate beautiful and readable PHP code:
484
485* ``subcompile()``: Compiles a node.
486
487* ``raw()``: Writes the given string as is.
488
489* ``write()``: Writes the given string by adding indentation at the beginning
490 of each line.
491
492* ``string()``: Writes a quoted string.
493
494* ``repr()``: Writes a PHP representation of a given value (see
495 ``Twig_Node_For`` for a usage example).
496
497* ``addDebugInfo()``: Adds the line of the original template file related to
498 the current node as a comment.
499
500* ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a
501 usage example).
502
503* ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a
504 usage example).
505
506.. _creating_extensions:
507
508Creating an Extension
509---------------------
510
511The main motivation for writing an extension is to move often used code into a
512reusable class like adding support for internationalization. An extension can
513define tags, filters, tests, operators, global variables, functions, and node
514visitors.
515
516Creating an extension also makes for a better separation of code that is
517executed at compilation time and code needed at runtime. As such, it makes
518your code faster.
519
520Most of the time, it is useful to create a single extension for your project,
521to host all the specific tags and filters you want to add to Twig.
522
523.. tip::
524
525 When packaging your code into an extension, Twig is smart enough to
526 recompile your templates whenever you make a change to it (when the
527 ``auto_reload`` is enabled).
528
529.. note::
530
531 Before writing your own extensions, have a look at the Twig official
532 extension repository: http://github.com/fabpot/Twig-extensions.
533
534An extension is a class that implements the following interface::
535
536 interface Twig_ExtensionInterface
537 {
538 /**
539 * Initializes the runtime environment.
540 *
541 * This is where you can load some file that contains filter functions for instance.
542 *
543 * @param Twig_Environment $environment The current Twig_Environment instance
544 */
545 function initRuntime(Twig_Environment $environment);
546
547 /**
548 * Returns the token parser instances to add to the existing list.
549 *
550 * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
551 */
552 function getTokenParsers();
553
554 /**
555 * Returns the node visitor instances to add to the existing list.
556 *
557 * @return array An array of Twig_NodeVisitorInterface instances
558 */
559 function getNodeVisitors();
560
561 /**
562 * Returns a list of filters to add to the existing list.
563 *
564 * @return array An array of filters
565 */
566 function getFilters();
567
568 /**
569 * Returns a list of tests to add to the existing list.
570 *
571 * @return array An array of tests
572 */
573 function getTests();
574
575 /**
576 * Returns a list of functions to add to the existing list.
577 *
578 * @return array An array of functions
579 */
580 function getFunctions();
581
582 /**
583 * Returns a list of operators to add to the existing list.
584 *
585 * @return array An array of operators
586 */
587 function getOperators();
588
589 /**
590 * Returns a list of global variables to add to the existing list.
591 *
592 * @return array An array of global variables
593 */
594 function getGlobals();
595
596 /**
597 * Returns the name of the extension.
598 *
599 * @return string The extension name
600 */
601 function getName();
602 }
603
604To keep your extension class clean and lean, it can inherit from the built-in
605``Twig_Extension`` class instead of implementing the whole interface. That
606way, you just need to implement the ``getName()`` method as the
607``Twig_Extension`` provides empty implementations for all other methods.
608
609The ``getName()`` method must return a unique identifier for your extension.
610
611Now, with this information in mind, let's create the most basic extension
612possible::
613
614 class Project_Twig_Extension extends Twig_Extension
615 {
616 public function getName()
617 {
618 return 'project';
619 }
620 }
621
622.. note::
623
624 Of course, this extension does nothing for now. We will customize it in
625 the next sections.
626
627Twig does not care where you save your extension on the filesystem, as all
628extensions must be registered explicitly to be available in your templates.
629
630You can register an extension by using the ``addExtension()`` method on your
631main ``Environment`` object::
632
633 $twig = new Twig_Environment($loader);
634 $twig->addExtension(new Project_Twig_Extension());
635
636Of course, you need to first load the extension file by either using
637``require_once()`` or by using an autoloader (see `spl_autoload_register()`_).
638
639.. tip::
640
641 The bundled extensions are great examples of how extensions work.
642
643Globals
644~~~~~~~
645
646Global variables can be registered in an extension via the ``getGlobals()``
647method::
648
649 class Project_Twig_Extension extends Twig_Extension
650 {
651 public function getGlobals()
652 {
653 return array(
654 'text' => new Text(),
655 );
656 }
657
658 // ...
659 }
660
661Functions
662~~~~~~~~~
663
664Functions can be registered in an extension via the ``getFunctions()``
665method::
666
667 class Project_Twig_Extension extends Twig_Extension
668 {
669 public function getFunctions()
670 {
671 return array(
672 'lipsum' => new Twig_Function_Function('generate_lipsum'),
673 );
674 }
675
676 // ...
677 }
678
679Filters
680~~~~~~~
681
682To add a filter to an extension, you need to override the ``getFilters()``
683method. This method must return an array of filters to add to the Twig
684environment::
685
686 class Project_Twig_Extension extends Twig_Extension
687 {
688 public function getFilters()
689 {
690 return array(
691 'rot13' => new Twig_Filter_Function('str_rot13'),
692 );
693 }
694
695 // ...
696 }
697
698As you can see in the above code, the ``getFilters()`` method returns an array
699where keys are the name of the filters (``rot13``) and the values the
700definition of the filter (``new Twig_Filter_Function('str_rot13')``).
701
702As seen in the previous chapter, you can also define filters as static methods
703on the extension class::
704
705$twig->addFilter('rot13', new Twig_Filter_Function('Project_Twig_Extension::rot13Filter'));
706
707You can also use ``Twig_Filter_Method`` instead of ``Twig_Filter_Function``
708when defining a filter to use a method::
709
710 class Project_Twig_Extension extends Twig_Extension
711 {
712 public function getFilters()
713 {
714 return array(
715 'rot13' => new Twig_Filter_Method($this, 'rot13Filter'),
716 );
717 }
718
719 public function rot13Filter($string)
720 {
721 return str_rot13($string);
722 }
723
724 // ...
725 }
726
727The first argument of the ``Twig_Filter_Method`` constructor is always
728``$this``, the current extension object. The second one is the name of the
729method to call.
730
731Using methods for filters is a great way to package your filter without
732polluting the global namespace. This also gives the developer more flexibility
733at the cost of a small overhead.
734
735Overriding default Filters
736..........................
737
738If some default core filters do not suit your needs, you can easily override
739them by creating your own extension. Just use the same names as the one you
740want to override::
741
742 class MyCoreExtension extends Twig_Extension
743 {
744 public function getFilters()
745 {
746 return array(
747 'date' => new Twig_Filter_Method($this, 'dateFilter'),
748 // ...
749 );
750 }
751
752 public function dateFilter($timestamp, $format = 'F j, Y H:i')
753 {
754 return '...'.twig_date_format_filter($timestamp, $format);
755 }
756
757 public function getName()
758 {
759 return 'project';
760 }
761 }
762
763Here, we override the ``date`` filter with a custom one. Using this extension
764is as simple as registering the ``MyCoreExtension`` extension by calling the
765``addExtension()`` method on the environment instance::
766
767 $twig = new Twig_Environment($loader);
768 $twig->addExtension(new MyCoreExtension());
769
770Tags
771~~~~
772
773Adding a tag in an extension can be done by overriding the
774``getTokenParsers()`` method. This method must return an array of tags to add
775to the Twig environment::
776
777 class Project_Twig_Extension extends Twig_Extension
778 {
779 public function getTokenParsers()
780 {
781 return array(new Project_Set_TokenParser());
782 }
783
784 // ...
785 }
786
787In the above code, we have added a single new tag, defined by the
788``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
789responsible for parsing the tag and compiling it to PHP.
790
791Operators
792~~~~~~~~~
793
794The ``getOperators()`` methods allows to add new operators. Here is how to add
795``!``, ``||``, and ``&&`` operators::
796
797 class Project_Twig_Extension extends Twig_Extension
798 {
799 public function getOperators()
800 {
801 return array(
802 array(
803 '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
804 ),
805 array(
806 '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
807 '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
808 ),
809 );
810 }
811
812 // ...
813 }
814
815Tests
816~~~~~
817
818The ``getTests()`` methods allows to add new test functions::
819
820 class Project_Twig_Extension extends Twig_Extension
821 {
822 public function getTests()
823 {
824 return array(
825 'even' => new Twig_Test_Function('twig_test_even'),
826 );
827 }
828
829 // ...
830 }
831
832Testing an Extension
833--------------------
834
835.. versionadded:: 1.10
836 Support for functional tests was added in Twig 1.10.
837
838Functional Tests
839~~~~~~~~~~~~~~~~
840
841You can create functional tests for extensions simply by creating the
842following file structure in your test directory::
843
844 Fixtures/
845 filters/
846 foo.test
847 bar.test
848 functions/
849 foo.test
850 bar.test
851 tags/
852 foo.test
853 bar.test
854 IntegrationTest.php
855
856The ``IntegrationTest.php`` file should look like this::
857
858 class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
859 {
860 public function getExtensions()
861 {
862 return array(
863 new Project_Twig_Extension1(),
864 new Project_Twig_Extension2(),
865 );
866 }
867
868 public function getFixturesDir()
869 {
870 return dirname(__FILE__).'/Fixtures/';
871 }
872 }
873
874Fixtures examples can be found within the Twig repository
875`tests/Twig/Fixtures`_ directory.
876
877Node Tests
878~~~~~~~~~~
879
880Testing the node visitors can be complex, so extend your test cases from
881``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository
882`tests/Twig/Node`_ directory.
883
884.. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register
885.. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php
886.. _`tests/Twig/Fixtures`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures
887.. _`tests/Twig/Node`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node
diff --git a/vendor/twig/twig/doc/api.rst b/vendor/twig/twig/doc/api.rst
new file mode 100644
index 00000000..cbccb0f7
--- /dev/null
+++ b/vendor/twig/twig/doc/api.rst
@@ -0,0 +1,529 @@
1Twig for Developers
2===================
3
4This chapter describes the API to Twig and not the template language. It will
5be most useful as reference to those implementing the template interface to
6the application and not those who are creating Twig templates.
7
8Basics
9------
10
11Twig uses a central object called the **environment** (of class
12``Twig_Environment``). Instances of this class are used to store the
13configuration and extensions, and are used to load templates from the file
14system or other locations.
15
16Most applications will create one ``Twig_Environment`` object on application
17initialization and use that to load templates. In some cases it's however
18useful to have multiple environments side by side, if different configurations
19are in use.
20
21The simplest way to configure Twig to load templates for your application
22looks roughly like this::
23
24 require_once '/path/to/lib/Twig/Autoloader.php';
25 Twig_Autoloader::register();
26
27 $loader = new Twig_Loader_Filesystem('/path/to/templates');
28 $twig = new Twig_Environment($loader, array(
29 'cache' => '/path/to/compilation_cache',
30 ));
31
32This will create a template environment with the default settings and a loader
33that looks up the templates in the ``/path/to/templates/`` folder. Different
34loaders are available and you can also write your own if you want to load
35templates from a database or other resources.
36
37.. note::
38
39 Notice that the second argument of the environment is an array of options.
40 The ``cache`` option is a compilation cache directory, where Twig caches
41 the compiled templates to avoid the parsing phase for sub-sequent
42 requests. It is very different from the cache you might want to add for
43 the evaluated templates. For such a need, you can use any available PHP
44 cache library.
45
46To load a template from this environment you just have to call the
47``loadTemplate()`` method which then returns a ``Twig_Template`` instance::
48
49 $template = $twig->loadTemplate('index.html');
50
51To render the template with some variables, call the ``render()`` method::
52
53 echo $template->render(array('the' => 'variables', 'go' => 'here'));
54
55.. note::
56
57 The ``display()`` method is a shortcut to output the template directly.
58
59You can also load and render the template in one fell swoop::
60
61 echo $twig->render('index.html', array('the' => 'variables', 'go' => 'here'));
62
63.. _environment_options:
64
65Environment Options
66-------------------
67
68When creating a new ``Twig_Environment`` instance, you can pass an array of
69options as the constructor second argument::
70
71 $twig = new Twig_Environment($loader, array('debug' => true));
72
73The following options are available:
74
75* ``debug``: When set to ``true``, the generated templates have a
76 ``__toString()`` method that you can use to display the generated nodes
77 (default to ``false``).
78
79* ``charset``: The charset used by the templates (default to ``utf-8``).
80
81* ``base_template_class``: The base template class to use for generated
82 templates (default to ``Twig_Template``).
83
84* ``cache``: An absolute path where to store the compiled templates, or
85 ``false`` to disable caching (which is the default).
86
87* ``auto_reload``: When developing with Twig, it's useful to recompile the
88 template whenever the source code changes. If you don't provide a value for
89 the ``auto_reload`` option, it will be determined automatically based on the
90 ``debug`` value.
91
92* ``strict_variables``: If set to ``false``, Twig will silently ignore invalid
93 variables (variables and or attributes/methods that do not exist) and
94 replace them with a ``null`` value. When set to ``true``, Twig throws an
95 exception instead (default to ``false``).
96
97* ``autoescape``: If set to ``true``, auto-escaping will be enabled by default
98 for all templates (default to ``true``). As of Twig 1.8, you can set the
99 escaping strategy to use (``html``, ``js``, ``false`` to disable).
100 As of Twig 1.9, you can set the escaping strategy to use (``css``, ``url``,
101 ``html_attr``, or a PHP callback that takes the template "filename" and must
102 return the escaping strategy to use -- the callback cannot be a function name
103 to avoid collision with built-in escaping strategies).
104
105* ``optimizations``: A flag that indicates which optimizations to apply
106 (default to ``-1`` -- all optimizations are enabled; set it to ``0`` to
107 disable).
108
109Loaders
110-------
111
112Loaders are responsible for loading templates from a resource such as the file
113system.
114
115Compilation Cache
116~~~~~~~~~~~~~~~~~
117
118All template loaders can cache the compiled templates on the filesystem for
119future reuse. It speeds up Twig a lot as templates are only compiled once; and
120the performance boost is even larger if you use a PHP accelerator such as APC.
121See the ``cache`` and ``auto_reload`` options of ``Twig_Environment`` above
122for more information.
123
124Built-in Loaders
125~~~~~~~~~~~~~~~~
126
127Here is a list of the built-in loaders Twig provides:
128
129``Twig_Loader_Filesystem``
130..........................
131
132.. versionadded:: 1.10
133 The ``prependPath()`` and support for namespaces were added in Twig 1.10.
134
135``Twig_Loader_Filesystem`` loads templates from the file system. This loader
136can find templates in folders on the file system and is the preferred way to
137load them::
138
139 $loader = new Twig_Loader_Filesystem($templateDir);
140
141It can also look for templates in an array of directories::
142
143 $loader = new Twig_Loader_Filesystem(array($templateDir1, $templateDir2));
144
145With such a configuration, Twig will first look for templates in
146``$templateDir1`` and if they do not exist, it will fallback to look for them
147in the ``$templateDir2``.
148
149You can add or prepend paths via the ``addPath()`` and ``prependPath()``
150methods::
151
152 $loader->addPath($templateDir3);
153 $loader->prependPath($templateDir4);
154
155The filesystem loader also supports namespaced templates. This allows to group
156your templates under different namespaces which have their own template paths.
157
158When using the ``setPaths()``, ``addPath()``, and ``prependPath()`` methods,
159specify the namespace as the second argument (when not specified, these
160methods act on the "main" namespace)::
161
162 $loader->addPath($templateDir, 'admin');
163
164Namespaced templates can be accessed via the special
165``@namespace_name/template_path`` notation::
166
167 $twig->render('@admin/index.html', array());
168
169``Twig_Loader_String``
170......................
171
172``Twig_Loader_String`` loads templates from strings. It's a dummy loader as
173the template reference is the template source code::
174
175 $loader = new Twig_Loader_String();
176 $twig = new Twig_Environment($loader);
177
178 echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
179
180This loader should only be used for unit testing as it has severe limitations:
181several tags, like ``extends`` or ``include`` do not make sense to use as the
182reference to the template is the template source code itself.
183
184``Twig_Loader_Array``
185.....................
186
187``Twig_Loader_Array`` loads a template from a PHP array. It's passed an array
188of strings bound to template names::
189
190 $loader = new Twig_Loader_Array(array(
191 'index.html' => 'Hello {{ name }}!',
192 ));
193 $twig = new Twig_Environment($loader);
194
195 echo $twig->render('index.html', array('name' => 'Fabien'));
196
197This loader is very useful for unit testing. It can also be used for small
198projects where storing all templates in a single PHP file might make sense.
199
200.. tip::
201
202 When using the ``Array`` or ``String`` loaders with a cache mechanism, you
203 should know that a new cache key is generated each time a template content
204 "changes" (the cache key being the source code of the template). If you
205 don't want to see your cache grows out of control, you need to take care
206 of clearing the old cache file by yourself.
207
208``Twig_Loader_Chain``
209.....................
210
211``Twig_Loader_Chain`` delegates the loading of templates to other loaders::
212
213 $loader1 = new Twig_Loader_Array(array(
214 'base.html' => '{% block content %}{% endblock %}',
215 ));
216 $loader2 = new Twig_Loader_Array(array(
217 'index.html' => '{% extends "base.twig" %}{% block content %}Hello {{ name }}{% endblock %}',
218 'base.html' => 'Will never be loaded',
219 ));
220
221 $loader = new Twig_Loader_Chain(array($loader1, $loader2));
222
223 $twig = new Twig_Environment($loader);
224
225When looking for a template, Twig will try each loader in turn and it will
226return as soon as the template is found. When rendering the ``index.html``
227template from the above example, Twig will load it with ``$loader2`` but the
228``base.html`` template will be loaded from ``$loader1``.
229
230``Twig_Loader_Chain`` accepts any loader that implements
231``Twig_LoaderInterface``.
232
233.. note::
234
235 You can also add loaders via the ``addLoader()`` method.
236
237Create your own Loader
238~~~~~~~~~~~~~~~~~~~~~~
239
240All loaders implement the ``Twig_LoaderInterface``::
241
242 interface Twig_LoaderInterface
243 {
244 /**
245 * Gets the source code of a template, given its name.
246 *
247 * @param string $name string The name of the template to load
248 *
249 * @return string The template source code
250 */
251 function getSource($name);
252
253 /**
254 * Gets the cache key to use for the cache for a given template name.
255 *
256 * @param string $name string The name of the template to load
257 *
258 * @return string The cache key
259 */
260 function getCacheKey($name);
261
262 /**
263 * Returns true if the template is still fresh.
264 *
265 * @param string $name The template name
266 * @param timestamp $time The last modification time of the cached template
267 */
268 function isFresh($name, $time);
269 }
270
271As an example, here is how the built-in ``Twig_Loader_String`` reads::
272
273 class Twig_Loader_String implements Twig_LoaderInterface
274 {
275 public function getSource($name)
276 {
277 return $name;
278 }
279
280 public function getCacheKey($name)
281 {
282 return $name;
283 }
284
285 public function isFresh($name, $time)
286 {
287 return false;
288 }
289 }
290
291The ``isFresh()`` method must return ``true`` if the current cached template
292is still fresh, given the last modification time, or ``false`` otherwise.
293
294.. tip::
295
296 As of Twig 1.11.0, you can also implement ``Twig_ExistsLoaderInterface``
297 to make your loader faster when used with the chain loader.
298
299Using Extensions
300----------------
301
302Twig extensions are packages that add new features to Twig. Using an
303extension is as simple as using the ``addExtension()`` method::
304
305 $twig->addExtension(new Twig_Extension_Sandbox());
306
307Twig comes bundled with the following extensions:
308
309* *Twig_Extension_Core*: Defines all the core features of Twig.
310
311* *Twig_Extension_Escaper*: Adds automatic output-escaping and the possibility
312 to escape/unescape blocks of code.
313
314* *Twig_Extension_Sandbox*: Adds a sandbox mode to the default Twig
315 environment, making it safe to evaluate untrusted code.
316
317* *Twig_Extension_Optimizer*: Optimizes the node tree before compilation.
318
319The core, escaper, and optimizer extensions do not need to be added to the
320Twig environment, as they are registered by default.
321
322Built-in Extensions
323-------------------
324
325This section describes the features added by the built-in extensions.
326
327.. tip::
328
329 Read the chapter about extending Twig to learn how to create your own
330 extensions.
331
332Core Extension
333~~~~~~~~~~~~~~
334
335The ``core`` extension defines all the core features of Twig:
336
337* :doc:`Tags <tags/index>`;
338* :doc:`Filters <filters/index>`;
339* :doc:`Functions <functions/index>`;
340* :doc:`Tests <tests/index>`.
341
342Escaper Extension
343~~~~~~~~~~~~~~~~~
344
345The ``escaper`` extension adds automatic output escaping to Twig. It defines a
346tag, ``autoescape``, and a filter, ``raw``.
347
348When creating the escaper extension, you can switch on or off the global
349output escaping strategy::
350
351 $escaper = new Twig_Extension_Escaper('html');
352 $twig->addExtension($escaper);
353
354If set to ``html``, all variables in templates are escaped (using the ``html``
355escaping strategy), except those using the ``raw`` filter:
356
357.. code-block:: jinja
358
359 {{ article.to_html|raw }}
360
361You can also change the escaping mode locally by using the ``autoescape`` tag
362(see the :doc:`autoescape<tags/autoescape>` doc for the syntax used before
363Twig 1.8):
364
365.. code-block:: jinja
366
367 {% autoescape 'html' %}
368 {{ var }}
369 {{ var|raw }} {# var won't be escaped #}
370 {{ var|escape }} {# var won't be double-escaped #}
371 {% endautoescape %}
372
373.. warning::
374
375 The ``autoescape`` tag has no effect on included files.
376
377The escaping rules are implemented as follows:
378
379* Literals (integers, booleans, arrays, ...) used in the template directly as
380 variables or filter arguments are never automatically escaped:
381
382 .. code-block:: jinja
383
384 {{ "Twig<br />" }} {# won't be escaped #}
385
386 {% set text = "Twig<br />" %}
387 {{ text }} {# will be escaped #}
388
389* Expressions which the result is always a literal or a variable marked safe
390 are never automatically escaped:
391
392 .. code-block:: jinja
393
394 {{ foo ? "Twig<br />" : "<br />Twig" }} {# won't be escaped #}
395
396 {% set text = "Twig<br />" %}
397 {{ foo ? text : "<br />Twig" }} {# will be escaped #}
398
399 {% set text = "Twig<br />" %}
400 {{ foo ? text|raw : "<br />Twig" }} {# won't be escaped #}
401
402 {% set text = "Twig<br />" %}
403 {{ foo ? text|escape : "<br />Twig" }} {# the result of the expression won't be escaped #}
404
405* Escaping is applied before printing, after any other filter is applied:
406
407 .. code-block:: jinja
408
409 {{ var|upper }} {# is equivalent to {{ var|upper|escape }} #}
410
411* The `raw` filter should only be used at the end of the filter chain:
412
413 .. code-block:: jinja
414
415 {{ var|raw|upper }} {# will be escaped #}
416
417 {{ var|upper|raw }} {# won't be escaped #}
418
419* Automatic escaping is not applied if the last filter in the chain is marked
420 safe for the current context (e.g. ``html`` or ``js``). ``escaper`` and
421 ``escaper('html')`` are marked safe for html, ``escaper('js')`` is marked
422 safe for javascript, ``raw`` is marked safe for everything.
423
424 .. code-block:: jinja
425
426 {% autoescape 'js' %}
427 {{ var|escape('html') }} {# will be escaped for html and javascript #}
428 {{ var }} {# will be escaped for javascript #}
429 {{ var|escape('js') }} {# won't be double-escaped #}
430 {% endautoescape %}
431
432.. note::
433
434 Note that autoescaping has some limitations as escaping is applied on
435 expressions after evaluation. For instance, when working with
436 concatenation, ``{{ foo|raw ~ bar }}`` won't give the expected result as
437 escaping is applied on the result of the concatenation, not on the
438 individual variables (so, the ``raw`` filter won't have any effect here).
439
440Sandbox Extension
441~~~~~~~~~~~~~~~~~
442
443The ``sandbox`` extension can be used to evaluate untrusted code. Access to
444unsafe attributes and methods is prohibited. The sandbox security is managed
445by a policy instance. By default, Twig comes with one policy class:
446``Twig_Sandbox_SecurityPolicy``. This class allows you to white-list some
447tags, filters, properties, and methods::
448
449 $tags = array('if');
450 $filters = array('upper');
451 $methods = array(
452 'Article' => array('getTitle', 'getBody'),
453 );
454 $properties = array(
455 'Article' => array('title', 'body'),
456 );
457 $functions = array('range');
458 $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
459
460With the previous configuration, the security policy will only allow usage of
461the ``if`` tag, and the ``upper`` filter. Moreover, the templates will only be
462able to call the ``getTitle()`` and ``getBody()`` methods on ``Article``
463objects, and the ``title`` and ``body`` public properties. Everything else
464won't be allowed and will generate a ``Twig_Sandbox_SecurityError`` exception.
465
466The policy object is the first argument of the sandbox constructor::
467
468 $sandbox = new Twig_Extension_Sandbox($policy);
469 $twig->addExtension($sandbox);
470
471By default, the sandbox mode is disabled and should be enabled when including
472untrusted template code by using the ``sandbox`` tag:
473
474.. code-block:: jinja
475
476 {% sandbox %}
477 {% include 'user.html' %}
478 {% endsandbox %}
479
480You can sandbox all templates by passing ``true`` as the second argument of
481the extension constructor::
482
483 $sandbox = new Twig_Extension_Sandbox($policy, true);
484
485Optimizer Extension
486~~~~~~~~~~~~~~~~~~~
487
488The ``optimizer`` extension optimizes the node tree before compilation::
489
490 $twig->addExtension(new Twig_Extension_Optimizer());
491
492By default, all optimizations are turned on. You can select the ones you want
493to enable by passing them to the constructor::
494
495 $optimizer = new Twig_Extension_Optimizer(Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR);
496
497 $twig->addExtension($optimizer);
498
499Twig supports the following optimizations:
500
501* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_ALL``, enables all optimizations
502 (this is the default value).
503* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_NONE``, disables all optimizations.
504 This reduces the compilation time, but it can increase the execution time
505 and the consumed memory.
506* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR``, optimizes the ``for`` tag by
507 removing the ``loop`` variable creation whenever possible.
508* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_RAW_FILTER``, removes the ``raw``
509 filter whenever possible.
510* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_VAR_ACCESS``, simplifies the creation
511 and access of variables in the compiled templates whenever possible.
512
513Exceptions
514----------
515
516Twig can throw exceptions:
517
518* ``Twig_Error``: The base exception for all errors.
519
520* ``Twig_Error_Syntax``: Thrown to tell the user that there is a problem with
521 the template syntax.
522
523* ``Twig_Error_Runtime``: Thrown when an error occurs at runtime (when a filter
524 does not exist for instance).
525
526* ``Twig_Error_Loader``: Thrown when an error occurs during template loading.
527
528* ``Twig_Sandbox_SecurityError``: Thrown when an unallowed tag, filter, or
529 method is called in a sandboxed template.
diff --git a/vendor/twig/twig/doc/coding_standards.rst b/vendor/twig/twig/doc/coding_standards.rst
new file mode 100644
index 00000000..e0aab35e
--- /dev/null
+++ b/vendor/twig/twig/doc/coding_standards.rst
@@ -0,0 +1,101 @@
1Coding Standards
2================
3
4When writing Twig templates, we recommend you to follow these official coding
5standards:
6
7* Put one (and only one) space after the start of a delimiter (``{{``, ``{%``,
8 and ``{#``) and before the end of a delimiter (``}}``, ``%}``, and ``#}``):
9
10 .. code-block:: jinja
11
12 {{ foo }}
13 {# comment #}
14 {% if foo %}{% endif %}
15
16 When using the whitespace control character, do not put any spaces between
17 it and the delimiter:
18
19 .. code-block:: jinja
20
21 {{- foo -}}
22 {#- comment -#}
23 {%- if foo -%}{%- endif -%}
24
25* Put one (and only one) space before and after the following operators:
26 comparison operators (``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``), math
27 operators (``+``, ``-``, ``/``, ``*``, ``%``, ``//``, ``**``), logic
28 operators (``not``, ``and``, ``or``), ``~``, ``is``, ``in``, and the ternary
29 operator (``?:``):
30
31 .. code-block:: jinja
32
33 {{ 1 + 2 }}
34 {{ foo ~ bar }}
35 {{ true ? true : false }}
36
37* Put one (and only one) space after the ``:`` sign in hashes and ``,`` in
38 arrays and hashes:
39
40 .. code-block:: jinja
41
42 {{ [1, 2, 3] }}
43 {{ {'foo': 'bar'} }}
44
45* Do not put any spaces after an opening parenthesis and before a closing
46 parenthesis in expressions:
47
48 .. code-block:: jinja
49
50 {{ 1 + (2 * 3) }}
51
52* Do not put any spaces before and after string delimiters:
53
54 .. code-block:: jinja
55
56 {{ 'foo' }}
57 {{ "foo" }}
58
59* Do not put any spaces before and after the following operators: ``|``,
60 ``.``, ``..``, ``[]``:
61
62 .. code-block:: jinja
63
64 {{ foo|upper|lower }}
65 {{ user.name }}
66 {{ user[name] }}
67 {% for i in 1..12 %}{% endfor %}
68
69* Do not put any spaces before and after the parenthesis used for filter and
70 function calls:
71
72 .. code-block:: jinja
73
74 {{ foo|default('foo') }}
75 {{ range(1..10) }}
76
77* Do not put any spaces before and after the opening and the closing of arrays
78 and hashes:
79
80 .. code-block:: jinja
81
82 {{ [1, 2, 3] }}
83 {{ {'foo': 'bar'} }}
84
85* Use lower cased and underscored variable names:
86
87 .. code-block:: jinja
88
89 {% set foo = 'foo' %}
90 {% set foo_bar = 'foo' %}
91
92* Indent your code inside tags (use the same indentation as the one used for
93 the main language of the file):
94
95 .. code-block:: jinja
96
97 {% block foo %}
98 {% if true %}
99 true
100 {% endif %}
101 {% endblock %}
diff --git a/vendor/twig/twig/doc/deprecated.rst b/vendor/twig/twig/doc/deprecated.rst
new file mode 100644
index 00000000..f0a3a0f0
--- /dev/null
+++ b/vendor/twig/twig/doc/deprecated.rst
@@ -0,0 +1,98 @@
1Deprecated Features
2===================
3
4This document lists all deprecated features in Twig. Deprecated features are
5kept for backward compatibility and removed in the next major release (a
6feature that was deprecated in Twig 1.x is removed in Twig 2.0).
7
8Token Parsers
9-------------
10
11* As of Twig 1.x, the token parser broker sub-system is deprecated. The
12 following class and interface will be removed in 2.0:
13
14 * ``Twig_TokenParserBrokerInterface``
15 * ``Twig_TokenParserBroker``
16
17Extensions
18----------
19
20* As of Twig 1.x, the ability to remove an extension is deprecated and the
21 ``Twig_Environment::removeExtension()`` method will be removed in 2.0.
22
23PEAR
24----
25
26PEAR support will be discontinued in Twig 2.0, and no PEAR packages will be
27provided. Use Composer instead.
28
29Filters
30-------
31
32* As of Twig 1.x, use ``Twig_SimpleFilter`` to add a filter. The following
33 classes and interfaces will be removed in 2.0:
34
35 * ``Twig_FilterInterface``
36 * ``Twig_FilterCallableInterface``
37 * ``Twig_Filter``
38 * ``Twig_Filter_Function``
39 * ``Twig_Filter_Method``
40 * ``Twig_Filter_Node``
41
42* As of Twig 2.x, the ``Twig_SimpleFilter`` class is deprecated and will be
43 removed in Twig 3.x (use ``Twig_Filter`` instead). In Twig 2.x,
44 ``Twig_SimpleFilter`` is just an alias for ``Twig_Filter``.
45
46Functions
47---------
48
49* As of Twig 1.x, use ``Twig_SimpleFunction`` to add a function. The following
50 classes and interfaces will be removed in 2.0:
51
52 * ``Twig_FunctionInterface``
53 * ``Twig_FunctionCallableInterface``
54 * ``Twig_Function``
55 * ``Twig_Function_Function``
56 * ``Twig_Function_Method``
57 * ``Twig_Function_Node``
58
59* As of Twig 2.x, the ``Twig_SimpleFunction`` class is deprecated and will be
60 removed in Twig 3.x (use ``Twig_Function`` instead). In Twig 2.x,
61 ``Twig_SimpleFunction`` is just an alias for ``Twig_Function``.
62
63Tests
64-----
65
66* As of Twig 1.x, use ``Twig_SimpleTest`` to add a test. The following classes
67 and interfaces will be removed in 2.0:
68
69 * ``Twig_TestInterface``
70 * ``Twig_TestCallableInterface``
71 * ``Twig_Test``
72 * ``Twig_Test_Function``
73 * ``Twig_Test_Method``
74 * ``Twig_Test_Node``
75
76* As of Twig 2.x, the ``Twig_SimpleTest`` class is deprecated and will be
77 removed in Twig 3.x (use ``Twig_Test`` instead). In Twig 2.x,
78 ``Twig_SimpleTest`` is just an alias for ``Twig_Test``.
79
80Interfaces
81----------
82
83* As of Twig 2.x, the following interfaces are deprecated and empty (they will
84 be removed in Twig 3.0):
85
86* ``Twig_CompilerInterface`` (use ``Twig_Compiler`` instead)
87* ``Twig_LexerInterface`` (use ``Twig_Lexer`` instead)
88* ``Twig_NodeInterface`` (use ``Twig_Node`` instead)
89* ``Twig_ParserInterface`` (use ``Twig_Parser`` instead)
90* ``Twig_ExistsLoaderInterface`` (merged with ``Twig_LoaderInterface``)
91* ``Twig_TemplateInterface`` (use ``Twig_Template`` instead)
92
93Globals
94-------
95
96* As of Twig 2.x, the ability to register a global variable after the runtime
97 or the extensions have been initialized is not possible anymore (but
98 changing the value of an already registered global is possible).
diff --git a/vendor/twig/twig/doc/filters/abs.rst b/vendor/twig/twig/doc/filters/abs.rst
new file mode 100644
index 00000000..3a82f62e
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/abs.rst
@@ -0,0 +1,18 @@
1``abs``
2=======
3
4The ``abs`` filter returns the absolute value.
5
6.. code-block:: jinja
7
8 {# number = -5 #}
9
10 {{ number|abs }}
11
12 {# outputs 5 #}
13
14.. note::
15
16 Internally, Twig uses the PHP `abs`_ function.
17
18.. _`abs`: http://php.net/abs
diff --git a/vendor/twig/twig/doc/filters/batch.rst b/vendor/twig/twig/doc/filters/batch.rst
new file mode 100644
index 00000000..4366b57b
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/batch.rst
@@ -0,0 +1,45 @@
1``batch``
2=========
3
4.. versionadded:: 1.12.3
5 The batch filter was added in Twig 1.12.3.
6
7The ``batch`` filter "batches" items by returning a list of lists with the
8given number of items. If you provide a second parameter, it is used to fill
9missing items:
10
11.. code-block:: jinja
12
13 {% set items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] %}
14
15 <table>
16 {% for row in items|batch(3, 'No item') %}
17 <tr>
18 {% for column in row %}
19 <td>{{ column }}</td>
20 {% endfor %}
21 </tr>
22 {% endfor %}
23 </table>
24
25The above example will be rendered as:
26
27.. code-block:: jinja
28
29 <table>
30 <tr>
31 <td>a</td>
32 <td>b</td>
33 <td>c</td>
34 </tr>
35 <tr>
36 <td>d</td>
37 <td>e</td>
38 <td>f</td>
39 </tr>
40 <tr>
41 <td>g</td>
42 <td>No item</td>
43 <td>No item</td>
44 </tr>
45 </table>
diff --git a/vendor/twig/twig/doc/filters/capitalize.rst b/vendor/twig/twig/doc/filters/capitalize.rst
new file mode 100644
index 00000000..10546a1f
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/capitalize.rst
@@ -0,0 +1,11 @@
1``capitalize``
2==============
3
4The ``capitalize`` filter capitalizes a value. The first character will be
5uppercase, all others lowercase:
6
7.. code-block:: jinja
8
9 {{ 'my first car'|capitalize }}
10
11 {# outputs 'My first car' #}
diff --git a/vendor/twig/twig/doc/filters/convert_encoding.rst b/vendor/twig/twig/doc/filters/convert_encoding.rst
new file mode 100644
index 00000000..1b0eb60c
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/convert_encoding.rst
@@ -0,0 +1,28 @@
1``convert_encoding``
2====================
3
4.. versionadded:: 1.4
5 The ``convert_encoding`` filter was added in Twig 1.4.
6
7The ``convert_encoding`` filter converts a string from one encoding to
8another. The first argument is the expected output charset and the second one
9is the input charset:
10
11.. code-block:: jinja
12
13 {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
14
15.. note::
16
17 This filter relies on the `iconv`_ or `mbstring`_ extension, so one of
18 them must be installed. In case both are installed, `mbstring`_ is used by
19 default (Twig before 1.8.1 uses `iconv`_ by default).
20
21Arguments
22---------
23
24 * ``from``: The input charset
25 * ``to``: The output charset
26
27.. _`iconv`: http://php.net/iconv
28.. _`mbstring`: http://php.net/mbstring
diff --git a/vendor/twig/twig/doc/filters/date.rst b/vendor/twig/twig/doc/filters/date.rst
new file mode 100644
index 00000000..8e2f31fa
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/date.rst
@@ -0,0 +1,88 @@
1``date``
2========
3
4.. versionadded:: 1.1
5 The timezone support has been added in Twig 1.1.
6
7.. versionadded:: 1.5
8 The default date format support has been added in Twig 1.5.
9
10.. versionadded:: 1.6.1
11 The default timezone support has been added in Twig 1.6.1.
12
13.. versionadded:: 1.11.0
14 The introduction of the false value for the timezone was introduced in Twig 1.11.0
15
16The ``date`` filter formats a date to a given format:
17
18.. code-block:: jinja
19
20 {{ post.published_at|date("m/d/Y") }}
21
22The ``date`` filter accepts strings (it must be in a format supported by the
23`strtotime`_ function), `DateTime`_ instances, or `DateInterval`_ instances. For
24instance, to display the current date, filter the word "now":
25
26.. code-block:: jinja
27
28 {{ "now"|date("m/d/Y") }}
29
30To escape words and characters in the date format use ``\\`` in front of each
31character:
32
33.. code-block:: jinja
34
35 {{ post.published_at|date("F jS \\a\\t g:ia") }}
36
37If the value passed to the ``date`` filter is ``null``, it will return the
38current date by default. If an empty string is desired instead of the current
39date, use a ternary operator:
40
41.. code-block:: jinja
42
43 {{ post.published_at is empty ? "" : post.published_at|date("m/d/Y") }}
44
45If no format is provided, Twig will use the default one: ``F j, Y H:i``. This
46default can be easily changed by calling the ``setDateFormat()`` method on the
47``core`` extension instance. The first argument is the default format for
48dates and the second one is the default format for date intervals:
49
50.. code-block:: php
51
52 $twig = new Twig_Environment($loader);
53 $twig->getExtension('core')->setDateFormat('d/m/Y', '%d days');
54
55Timezone
56--------
57
58By default, the date is displayed by applying the default timezone (the one
59specified in php.ini or declared in Twig -- see below), but you can override
60it by explicitly specifying a timezone:
61
62.. code-block:: jinja
63
64 {{ post.published_at|date("m/d/Y", "Europe/Paris") }}
65
66If the date is already a DateTime object, and if you want to keep its current
67timezone, pass ``false`` as the timezone value:
68
69.. code-block:: jinja
70
71 {{ post.published_at|date("m/d/Y", false) }}
72
73The default timezone can also be set globally by calling ``setTimezone()``:
74
75.. code-block:: php
76
77 $twig = new Twig_Environment($loader);
78 $twig->getExtension('core')->setTimezone('Europe/Paris');
79
80Arguments
81---------
82
83 * ``format``: The date format
84 * ``timezone``: The date timezone
85
86.. _`strtotime`: http://www.php.net/strtotime
87.. _`DateTime`: http://www.php.net/DateTime
88.. _`DateInterval`: http://www.php.net/DateInterval
diff --git a/vendor/twig/twig/doc/filters/date_modify.rst b/vendor/twig/twig/doc/filters/date_modify.rst
new file mode 100644
index 00000000..6a5c73d6
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/date_modify.rst
@@ -0,0 +1,23 @@
1``date_modify``
2===============
3
4.. versionadded:: 1.9.0
5 The date_modify filter has been added in Twig 1.9.0.
6
7The ``date_modify`` filter modifies a date with a given modifier string:
8
9.. code-block:: jinja
10
11 {{ post.published_at|date_modify("+1 day")|date("m/d/Y") }}
12
13The ``date_modify`` filter accepts strings (it must be in a format supported
14by the `strtotime`_ function) or `DateTime`_ instances. You can easily combine
15it with the :doc:`date<date>` filter for formatting.
16
17Arguments
18---------
19
20 * ``modifier``: The modifier
21
22.. _`strtotime`: http://www.php.net/strtotime
23.. _`DateTime`: http://www.php.net/DateTime
diff --git a/vendor/twig/twig/doc/filters/default.rst b/vendor/twig/twig/doc/filters/default.rst
new file mode 100644
index 00000000..46ed9636
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/default.rst
@@ -0,0 +1,33 @@
1``default``
2===========
3
4The ``default`` filter returns the passed default value if the value is
5undefined or empty, otherwise the value of the variable:
6
7.. code-block:: jinja
8
9 {{ var|default('var is not defined') }}
10
11 {{ var.foo|default('foo item on var is not defined') }}
12
13 {{ var['foo']|default('foo item on var is not defined') }}
14
15 {{ ''|default('passed var is empty') }}
16
17When using the ``default`` filter on an expression that uses variables in some
18method calls, be sure to use the ``default`` filter whenever a variable can be
19undefined:
20
21.. code-block:: jinja
22
23 {{ var.method(foo|default('foo'))|default('foo') }}
24
25.. note::
26
27 Read the documentation for the :doc:`defined<../tests/defined>` and
28 :doc:`empty<../tests/empty>` tests to learn more about their semantics.
29
30Arguments
31---------
32
33 * ``default``: The default value
diff --git a/vendor/twig/twig/doc/filters/escape.rst b/vendor/twig/twig/doc/filters/escape.rst
new file mode 100644
index 00000000..5ade7d74
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/escape.rst
@@ -0,0 +1,93 @@
1``escape``
2==========
3
4.. versionadded:: 1.9.0
5 The ``css``, ``url``, and ``html_attr`` strategies were added in Twig
6 1.9.0.
7
8The ``escape`` filter escapes a string for safe insertion into the final
9output. It supports different escaping strategies depending on the template
10context.
11
12By default, it uses the HTML escaping strategy:
13
14.. code-block:: jinja
15
16 {{ user.username|escape }}
17
18For convenience, the ``e`` filter is defined as an alias:
19
20.. code-block:: jinja
21
22 {{ user.username|e }}
23
24The ``escape`` filter can also be used in other contexts than HTML thanks to
25an optional argument which defines the escaping strategy to use:
26
27.. code-block:: jinja
28
29 {{ user.username|e }}
30 {# is equivalent to #}
31 {{ user.username|e('html') }}
32
33And here is how to escape variables included in JavaScript code:
34
35.. code-block:: jinja
36
37 {{ user.username|escape('js') }}
38 {{ user.username|e('js') }}
39
40The ``escape`` filter supports the following escaping strategies:
41
42* ``html``: escapes a string for the **HTML body** context.
43
44* ``js``: escapes a string for the **JavaScript context**.
45
46* ``css``: escapes a string for the **CSS context**. CSS escaping can be
47 applied to any string being inserted into CSS and escapes everything except
48 alphanumerics.
49
50* ``url``: escapes a string for the **URI or parameter contexts**. This should
51 not be used to escape an entire URI; only a subcomponent being inserted.
52
53* ``html_attr``: escapes a string for the **HTML attribute** context.
54
55.. note::
56
57 Internally, ``escape`` uses the PHP native `htmlspecialchars`_ function
58 for the HTML escaping strategy.
59
60.. caution::
61
62 When using automatic escaping, Twig tries to not double-escape a variable
63 when the automatic escaping strategy is the same as the one applied by the
64 escape filter; but that does not work when using a variable as the
65 escaping strategy:
66
67 .. code-block:: jinja
68
69 {% set strategy = 'html' %}
70
71 {% autoescape 'html' %}
72 {{ var|escape('html') }} {# won't be double-escaped #}
73 {{ var|escape(strategy) }} {# will be double-escaped #}
74 {% endautoescape %}
75
76 When using a variable as the escaping strategy, you should disable
77 automatic escaping:
78
79 .. code-block:: jinja
80
81 {% set strategy = 'html' %}
82
83 {% autoescape 'html' %}
84 {{ var|escape(strategy)|raw }} {# won't be double-escaped #}
85 {% endautoescape %}
86
87Arguments
88---------
89
90 * ``strategy``: The escaping strategy
91 * ``charset``: The string charset
92
93.. _`htmlspecialchars`: http://php.net/htmlspecialchars
diff --git a/vendor/twig/twig/doc/filters/first.rst b/vendor/twig/twig/doc/filters/first.rst
new file mode 100644
index 00000000..4295e833
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/first.rst
@@ -0,0 +1,25 @@
1``first``
2=========
3
4.. versionadded:: 1.12.2
5 The first filter was added in Twig 1.12.2.
6
7The ``first`` filter returns the first "element" of a sequence, a mapping, or
8a string:
9
10.. code-block:: jinja
11
12 {{ [1, 2, 3, 4]|first }}
13 {# outputs 1 #}
14
15 {{ { a: 1, b: 2, c: 3, d: 4 }|first }}
16 {# outputs 1 #}
17
18 {{ '1234'|first }}
19 {# outputs 1 #}
20
21.. note::
22
23 It also works with objects implementing the `Traversable`_ interface.
24
25.. _`Traversable`: http://php.net/manual/en/class.traversable.php
diff --git a/vendor/twig/twig/doc/filters/format.rst b/vendor/twig/twig/doc/filters/format.rst
new file mode 100644
index 00000000..fe55a09e
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/format.rst
@@ -0,0 +1,16 @@
1``format``
2==========
3
4The ``format`` filter formats a given string by replacing the placeholders
5(placeholders follows the `sprintf`_ notation):
6
7.. code-block:: jinja
8
9 {{ "I like %s and %s."|format(foo, "bar") }}
10
11 {# returns I like foo and bar
12 if the foo parameter equals to the foo string. #}
13
14.. _`sprintf`: http://www.php.net/sprintf
15
16.. seealso:: :doc:`replace<replace>`
diff --git a/vendor/twig/twig/doc/filters/index.rst b/vendor/twig/twig/doc/filters/index.rst
new file mode 100644
index 00000000..b0c6b38d
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/index.rst
@@ -0,0 +1,36 @@
1Filters
2=======
3
4.. toctree::
5 :maxdepth: 1
6
7 abs
8 batch
9 capitalize
10 convert_encoding
11 date
12 date_modify
13 default
14 escape
15 first
16 format
17 join
18 json_encode
19 keys
20 last
21 length
22 lower
23 nl2br
24 number_format
25 merge
26 upper
27 raw
28 replace
29 reverse
30 slice
31 sort
32 split
33 striptags
34 title
35 trim
36 url_encode
diff --git a/vendor/twig/twig/doc/filters/join.rst b/vendor/twig/twig/doc/filters/join.rst
new file mode 100644
index 00000000..f4952421
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/join.rst
@@ -0,0 +1,23 @@
1``join``
2========
3
4The ``join`` filter returns a string which is the concatenation of the items
5of a sequence:
6
7.. code-block:: jinja
8
9 {{ [1, 2, 3]|join }}
10 {# returns 123 #}
11
12The separator between elements is an empty string per default, but you can
13define it with the optional first parameter:
14
15.. code-block:: jinja
16
17 {{ [1, 2, 3]|join('|') }}
18 {# returns 1|2|3 #}
19
20Arguments
21---------
22
23 * ``glue``: The separator
diff --git a/vendor/twig/twig/doc/filters/json_encode.rst b/vendor/twig/twig/doc/filters/json_encode.rst
new file mode 100644
index 00000000..a33fef1b
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/json_encode.rst
@@ -0,0 +1,21 @@
1``json_encode``
2===============
3
4The ``json_encode`` filter returns the JSON representation of a string:
5
6.. code-block:: jinja
7
8 {{ data|json_encode() }}
9
10.. note::
11
12 Internally, Twig uses the PHP `json_encode`_ function.
13
14Arguments
15---------
16
17 * ``options``: A bitmask of `json_encode options`_ (``{{
18 data|json_encode(constant(JSON_PRETTY_PRINT)) }}``)
19
20.. _`json_encode`: http://php.net/json_encode
21.. _`json_encode options`: http://www.php.net/manual/en/json.constants.php
diff --git a/vendor/twig/twig/doc/filters/keys.rst b/vendor/twig/twig/doc/filters/keys.rst
new file mode 100644
index 00000000..e4f090c6
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/keys.rst
@@ -0,0 +1,11 @@
1``keys``
2========
3
4The ``keys`` filter returns the keys of an array. It is useful when you want to
5iterate over the keys of an array:
6
7.. code-block:: jinja
8
9 {% for key in array|keys %}
10 ...
11 {% endfor %}
diff --git a/vendor/twig/twig/doc/filters/last.rst b/vendor/twig/twig/doc/filters/last.rst
new file mode 100644
index 00000000..723c0b57
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/last.rst
@@ -0,0 +1,25 @@
1``last``
2========
3
4.. versionadded:: 1.12.2
5 The last filter was added in Twig 1.12.2.
6
7The ``last`` filter returns the last "element" of a sequence, a mapping, or
8a string:
9
10.. code-block:: jinja
11
12 {{ [1, 2, 3, 4]|last }}
13 {# outputs 4 #}
14
15 {{ { a: 1, b: 2, c: 3, d: 4 }|last }}
16 {# outputs 4 #}
17
18 {{ '1234'|last }}
19 {# outputs 4 #}
20
21.. note::
22
23 It also works with objects implementing the `Traversable`_ interface.
24
25.. _`Traversable`: http://php.net/manual/en/class.traversable.php
diff --git a/vendor/twig/twig/doc/filters/length.rst b/vendor/twig/twig/doc/filters/length.rst
new file mode 100644
index 00000000..f79b9bdf
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/length.rst
@@ -0,0 +1,12 @@
1``length``
2==========
3
4The ``length`` filters returns the number of items of a sequence or mapping, or
5the length of a string:
6
7.. code-block:: jinja
8
9 {% if users|length > 10 %}
10 ...
11 {% endif %}
12
diff --git a/vendor/twig/twig/doc/filters/lower.rst b/vendor/twig/twig/doc/filters/lower.rst
new file mode 100644
index 00000000..ef9faa90
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/lower.rst
@@ -0,0 +1,10 @@
1``lower``
2=========
3
4The ``lower`` filter converts a value to lowercase:
5
6.. code-block:: jinja
7
8 {{ 'WELCOME'|lower }}
9
10 {# outputs 'welcome' #}
diff --git a/vendor/twig/twig/doc/filters/merge.rst b/vendor/twig/twig/doc/filters/merge.rst
new file mode 100644
index 00000000..05a2ae7d
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/merge.rst
@@ -0,0 +1,41 @@
1``merge``
2=========
3
4The ``merge`` filter merges an array with another array:
5
6.. code-block:: jinja
7
8 {% set values = [1, 2] %}
9
10 {% set values = values|merge(['apple', 'orange']) %}
11
12 {# values now contains [1, 2, 'apple', 'orange'] #}
13
14New values are added at the end of the existing ones.
15
16The ``merge`` filter also works on hashes:
17
18.. code-block:: jinja
19
20 {% set items = { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'unknown' } %}
21
22 {% set items = items|merge({ 'peugeot': 'car', 'renault': 'car' }) %}
23
24 {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car', 'renault': 'car' } #}
25
26For hashes, the merging process occurs on the keys: if the key does not
27already exist, it is added but if the key already exists, its value is
28overridden.
29
30.. tip::
31
32 If you want to ensure that some values are defined in an array (by given
33 default values), reverse the two elements in the call:
34
35 .. code-block:: jinja
36
37 {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
38
39 {% set items = { 'apple': 'unknown' }|merge(items) %}
40
41 {# items now contains { 'apple': 'fruit', 'orange': 'fruit' } #}
diff --git a/vendor/twig/twig/doc/filters/nl2br.rst b/vendor/twig/twig/doc/filters/nl2br.rst
new file mode 100644
index 00000000..694c6724
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/nl2br.rst
@@ -0,0 +1,22 @@
1``nl2br``
2=========
3
4.. versionadded:: 1.5
5 The nl2br filter was added in Twig 1.5.
6
7The ``nl2br`` filter inserts HTML line breaks before all newlines in a string:
8
9.. code-block:: jinja
10
11 {{ "I like Twig.\nYou will like it too."|nl2br }}
12 {# outputs
13
14 I like Twig.<br />
15 You will like it too.
16
17 #}
18
19.. note::
20
21 The ``nl2br`` filter pre-escapes the input before applying the
22 transformation.
diff --git a/vendor/twig/twig/doc/filters/number_format.rst b/vendor/twig/twig/doc/filters/number_format.rst
new file mode 100644
index 00000000..fedacd9d
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/number_format.rst
@@ -0,0 +1,45 @@
1``number_format``
2=================
3
4.. versionadded:: 1.5
5 The number_format filter was added in Twig 1.5
6
7The ``number_format`` filter formats numbers. It is a wrapper around PHP's
8`number_format`_ function:
9
10.. code-block:: jinja
11
12 {{ 200.35|number_format }}
13
14You can control the number of decimal places, decimal point, and thousands
15separator using the additional arguments:
16
17.. code-block:: jinja
18
19 {{ 9800.333|number_format(2, '.', ',') }}
20
21If no formatting options are provided then Twig will use the default formatting
22options of:
23
24- 0 decimal places.
25- ``.`` as the decimal point.
26- ``,`` as the thousands separator.
27
28These defaults can be easily changed through the core extension:
29
30.. code-block:: php
31
32 $twig = new Twig_Environment($loader);
33 $twig->getExtension('core')->setNumberFormat(3, '.', ',');
34
35The defaults set for ``number_format`` can be over-ridden upon each call using the
36additional parameters.
37
38Arguments
39---------
40
41 * ``decimal``: The number of decimal points to display
42 * ``decimal_point``: The character(s) to use for the decimal point
43 * ``decimal_sep``: The character(s) to use for the thousands separator
44
45.. _`number_format`: http://php.net/number_format
diff --git a/vendor/twig/twig/doc/filters/raw.rst b/vendor/twig/twig/doc/filters/raw.rst
new file mode 100644
index 00000000..434dd246
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/raw.rst
@@ -0,0 +1,12 @@
1``raw``
2=======
3
4The ``raw`` filter marks the value as being "safe", which means that in an
5environment with automatic escaping enabled this variable will not be escaped
6if ``raw`` is the last filter applied to it:
7
8.. code-block:: jinja
9
10 {% autoescape true %}
11 {{ var|raw }} {# var won't be escaped #}
12 {% endautoescape %}
diff --git a/vendor/twig/twig/doc/filters/replace.rst b/vendor/twig/twig/doc/filters/replace.rst
new file mode 100644
index 00000000..e961f23d
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/replace.rst
@@ -0,0 +1,19 @@
1``replace``
2===========
3
4The ``replace`` filter formats a given string by replacing the placeholders
5(placeholders are free-form):
6
7.. code-block:: jinja
8
9 {{ "I like %this% and %that%."|replace({'%this%': foo, '%that%': "bar"}) }}
10
11 {# returns I like foo and bar
12 if the foo parameter equals to the foo string. #}
13
14Arguments
15---------
16
17 * ``replace_pairs``: The placeholder values
18
19.. seealso:: :doc:`format<format>`
diff --git a/vendor/twig/twig/doc/filters/reverse.rst b/vendor/twig/twig/doc/filters/reverse.rst
new file mode 100644
index 00000000..752192b8
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/reverse.rst
@@ -0,0 +1,47 @@
1``reverse``
2===========
3
4.. versionadded:: 1.6
5 Support for strings has been added in Twig 1.6.
6
7The ``reverse`` filter reverses a sequence, a mapping, or a string:
8
9.. code-block:: jinja
10
11 {% for user in users|reverse %}
12 ...
13 {% endfor %}
14
15 {{ '1234'|reverse }}
16
17 {# outputs 4321 #}
18
19.. tip::
20
21 For sequences and mappings, numeric keys are not preserved. To reverse
22 them as well, pass ``true`` as an argument to the ``reverse`` filter:
23
24 .. code-block:: jinja
25
26 {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse %}
27 {{ key }}: {{ value }}
28 {%- endfor %}
29
30 {# output: 0: c 1: b 2: a #}
31
32 {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse(true) %}
33 {{ key }}: {{ value }}
34 {%- endfor %}
35
36 {# output: 3: c 2: b 1: a #}
37
38.. note::
39
40 It also works with objects implementing the `Traversable`_ interface.
41
42Arguments
43---------
44
45 * ``preserve_keys``: Preserve keys when reversing a mapping or a sequence.
46
47.. _`Traversable`: http://php.net/Traversable
diff --git a/vendor/twig/twig/doc/filters/slice.rst b/vendor/twig/twig/doc/filters/slice.rst
new file mode 100644
index 00000000..dbd5db37
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/slice.rst
@@ -0,0 +1,70 @@
1``slice``
2===========
3
4.. versionadded:: 1.6
5 The slice filter was added in Twig 1.6.
6
7The ``slice`` filter extracts a slice of a sequence, a mapping, or a string:
8
9.. code-block:: jinja
10
11 {% for i in [1, 2, 3, 4, 5]|slice(1, 2) %}
12 {# will iterate over 2 and 3 #}
13 {% endfor %}
14
15 {{ '12345'|slice(1, 2) }}
16
17 {# outputs 23 #}
18
19You can use any valid expression for both the start and the length:
20
21.. code-block:: jinja
22
23 {% for i in [1, 2, 3, 4, 5]|slice(start, length) %}
24 {# ... #}
25 {% endfor %}
26
27As syntactic sugar, you can also use the ``[]`` notation:
28
29.. code-block:: jinja
30
31 {% for i in [1, 2, 3, 4, 5][start:length] %}
32 {# ... #}
33 {% endfor %}
34
35 {{ '12345'[1:2] }}
36
37 {# you can omit the first argument -- which is the same as 0 #}
38 {{ '12345'[:2] }} {# will display "12" #}
39
40 {# you can omit the last argument -- which will select everything till the end #}
41 {{ '12345'[2:] }} {# will display "345" #}
42
43The ``slice`` filter works as the `array_slice`_ PHP function for arrays and
44`substr`_ for strings.
45
46If the start is non-negative, the sequence will start at that start in the
47variable. If start is negative, the sequence will start that far from the end
48of the variable.
49
50If length is given and is positive, then the sequence will have up to that
51many elements in it. If the variable is shorter than the length, then only the
52available variable elements will be present. If length is given and is
53negative then the sequence will stop that many elements from the end of the
54variable. If it is omitted, then the sequence will have everything from offset
55up until the end of the variable.
56
57.. note::
58
59 It also works with objects implementing the `Traversable`_ interface.
60
61Arguments
62---------
63
64 * ``start``: The start of the slice
65 * ``length``: The size of the slice
66 * ``preserve_keys``: Whether to preserve key or not (when the input is an array)
67
68.. _`Traversable`: http://php.net/manual/en/class.traversable.php
69.. _`array_slice`: http://php.net/array_slice
70.. _`substr`: http://php.net/substr
diff --git a/vendor/twig/twig/doc/filters/sort.rst b/vendor/twig/twig/doc/filters/sort.rst
new file mode 100644
index 00000000..33311528
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/sort.rst
@@ -0,0 +1,17 @@
1``sort``
2========
3
4The ``sort`` filter sorts an array:
5
6.. code-block:: jinja
7
8 {% for user in users|sort %}
9 ...
10 {% endfor %}
11
12.. note::
13
14 Internally, Twig uses the PHP `asort`_ function to maintain index
15 association.
16
17.. _`asort`: http://php.net/asort
diff --git a/vendor/twig/twig/doc/filters/split.rst b/vendor/twig/twig/doc/filters/split.rst
new file mode 100644
index 00000000..7cd2ca5b
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/split.rst
@@ -0,0 +1,53 @@
1``split``
2=========
3
4.. versionadded:: 1.10.3
5 The split filter was added in Twig 1.10.3.
6
7The ``split`` filter splits a string by the given delimiter and returns a list
8of strings:
9
10.. code-block:: jinja
11
12 {{ "one,two,three"|split(',') }}
13 {# returns ['one', 'two', 'three'] #}
14
15You can also pass a ``limit`` argument:
16
17 * If ``limit`` is positive, the returned array will contain a maximum of
18 limit elements with the last element containing the rest of string;
19
20 * If ``limit`` is negative, all components except the last -limit are
21 returned;
22
23 * If ``limit`` is zero, then this is treated as 1.
24
25.. code-block:: jinja
26
27 {{ "one,two,three,four,five"|split(',', 3) }}
28 {# returns ['one', 'two', 'three,four,five'] #}
29
30If the ``delimiter`` is an empty string, then value will be split by equal
31chunks. Length is set by the ``limit`` argument (one character by default).
32
33.. code-block:: jinja
34
35 {{ "123"|split('') }}
36 {# returns ['1', '2', '3'] #}
37
38 {{ "aabbcc"|split('', 2) }}
39 {# returns ['aa', 'bb', 'cc'] #}
40
41.. note::
42
43 Internally, Twig uses the PHP `explode`_ or `str_split`_ (if delimiter is
44 empty) functions for string splitting.
45
46Arguments
47---------
48
49 * ``delimiter``: The delimiter
50 * ``limit``: The limit argument
51
52.. _`explode`: http://php.net/explode
53.. _`str_split`: http://php.net/str_split
diff --git a/vendor/twig/twig/doc/filters/striptags.rst b/vendor/twig/twig/doc/filters/striptags.rst
new file mode 100644
index 00000000..72c6f252
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/striptags.rst
@@ -0,0 +1,15 @@
1``striptags``
2=============
3
4The ``striptags`` filter strips SGML/XML tags and replace adjacent whitespace
5by one space:
6
7.. code-block:: jinja
8
9 {{ some_html|striptags }}
10
11.. note::
12
13 Internally, Twig uses the PHP `strip_tags`_ function.
14
15.. _`strip_tags`: http://php.net/strip_tags
diff --git a/vendor/twig/twig/doc/filters/title.rst b/vendor/twig/twig/doc/filters/title.rst
new file mode 100644
index 00000000..c5a318e8
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/title.rst
@@ -0,0 +1,11 @@
1``title``
2=========
3
4The ``title`` filter returns a titlecased version of the value. Words will
5start with uppercase letters, all remaining characters are lowercase:
6
7.. code-block:: jinja
8
9 {{ 'my first car'|title }}
10
11 {# outputs 'My First Car' #}
diff --git a/vendor/twig/twig/doc/filters/trim.rst b/vendor/twig/twig/doc/filters/trim.rst
new file mode 100644
index 00000000..f38afd55
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/trim.rst
@@ -0,0 +1,29 @@
1``trim``
2========
3
4.. versionadded:: 1.6.2
5 The trim filter was added in Twig 1.6.2.
6
7The ``trim`` filter strips whitespace (or other characters) from the beginning
8and end of a string:
9
10.. code-block:: jinja
11
12 {{ ' I like Twig. '|trim }}
13
14 {# outputs 'I like Twig.' #}
15
16 {{ ' I like Twig.'|trim('.') }}
17
18 {# outputs ' I like Twig' #}
19
20.. note::
21
22 Internally, Twig uses the PHP `trim`_ function.
23
24Arguments
25---------
26
27 * ``character_mask``: The characters to strip
28
29.. _`trim`: http://php.net/trim
diff --git a/vendor/twig/twig/doc/filters/upper.rst b/vendor/twig/twig/doc/filters/upper.rst
new file mode 100644
index 00000000..561cebe3
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/upper.rst
@@ -0,0 +1,10 @@
1``upper``
2=========
3
4The ``upper`` filter converts a value to uppercase:
5
6.. code-block:: jinja
7
8 {{ 'welcome'|upper }}
9
10 {# outputs 'WELCOME' #}
diff --git a/vendor/twig/twig/doc/filters/url_encode.rst b/vendor/twig/twig/doc/filters/url_encode.rst
new file mode 100644
index 00000000..b4f9a6ca
--- /dev/null
+++ b/vendor/twig/twig/doc/filters/url_encode.rst
@@ -0,0 +1,28 @@
1``url_encode``
2==============
3
4.. versionadded:: 1.12.3
5 Support for encoding an array as query string was added in Twig 1.12.3.
6
7The ``url_encode`` filter percent encodes a given string as URL segment
8or an array as query string:
9
10.. code-block:: jinja
11
12 {{ "path-seg*ment"|url_encode }}
13 {# outputs "path-seg%2Ament" #}
14
15 {{ "string with spaces"|url_encode(true) }}
16 {# outputs "string%20with%20spaces" #}
17
18 {{ {'param': 'value', 'foo': 'bar'}|url_encode }}
19 {# outputs "param=value&foo=bar" #}
20
21.. note::
22
23 Internally, Twig uses the PHP `urlencode`_ (or `rawurlencode`_ if you pass
24 ``true`` as the first parameter) or the `http_build_query`_ function.
25
26.. _`urlencode`: http://php.net/urlencode
27.. _`rawurlencode`: http://php.net/rawurlencode
28.. _`http_build_query`: http://php.net/http_build_query
diff --git a/vendor/twig/twig/doc/functions/attribute.rst b/vendor/twig/twig/doc/functions/attribute.rst
new file mode 100644
index 00000000..3051bdaa
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/attribute.rst
@@ -0,0 +1,18 @@
1``attribute``
2=============
3
4.. versionadded:: 1.2
5 The ``attribute`` function was added in Twig 1.2.
6
7``attribute`` can be used to access a "dynamic" attribute of a variable:
8
9.. code-block:: jinja
10
11 {{ attribute(object, method) }}
12 {{ attribute(object, method, arguments) }}
13 {{ attribute(array, item) }}
14
15.. note::
16
17 The resolution algorithm is the same as the one used for the ``.``
18 notation, except that the item can be any valid expression.
diff --git a/vendor/twig/twig/doc/functions/block.rst b/vendor/twig/twig/doc/functions/block.rst
new file mode 100644
index 00000000..fd571efb
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/block.rst
@@ -0,0 +1,15 @@
1``block``
2=========
3
4When a template uses inheritance and if you want to print a block multiple
5times, use the ``block`` function:
6
7.. code-block:: jinja
8
9 <title>{% block title %}{% endblock %}</title>
10
11 <h1>{{ block('title') }}</h1>
12
13 {% block body %}{% endblock %}
14
15.. seealso:: :doc:`extends<../tags/extends>`, :doc:`parent<../functions/parent>`
diff --git a/vendor/twig/twig/doc/functions/constant.rst b/vendor/twig/twig/doc/functions/constant.rst
new file mode 100644
index 00000000..bea0e9fc
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/constant.rst
@@ -0,0 +1,18 @@
1``constant``
2============
3
4.. versionadded: 1.12.1
5 constant now accepts object instances as the second argument.
6
7``constant`` returns the constant value for a given string:
8
9.. code-block:: jinja
10
11 {{ some_date|date(constant('DATE_W3C')) }}
12 {{ constant('Namespace\\Classname::CONSTANT_NAME') }}
13
14As of 1.12.1 you can read constants from object instances as well:
15
16.. code-block:: jinja
17
18 {{ constant('RSS', date) }}
diff --git a/vendor/twig/twig/doc/functions/cycle.rst b/vendor/twig/twig/doc/functions/cycle.rst
new file mode 100644
index 00000000..0015cae1
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/cycle.rst
@@ -0,0 +1,25 @@
1``cycle``
2=========
3
4The ``cycle`` function cycles on an array of values:
5
6.. code-block:: jinja
7
8 {% for i in 0..10 %}
9 {{ cycle(['odd', 'even'], i) }}
10 {% endfor %}
11
12The array can contain any number of values:
13
14.. code-block:: jinja
15
16 {% set fruits = ['apple', 'orange', 'citrus'] %}
17
18 {% for i in 0..10 %}
19 {{ cycle(fruits, i) }}
20 {% endfor %}
21
22Arguments
23---------
24
25 * ``position``: The cycle position
diff --git a/vendor/twig/twig/doc/functions/date.rst b/vendor/twig/twig/doc/functions/date.rst
new file mode 100644
index 00000000..f1c94819
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/date.rst
@@ -0,0 +1,52 @@
1``date``
2========
3
4.. versionadded:: 1.6
5 The date function has been added in Twig 1.6.
6
7.. versionadded:: 1.6.1
8 The default timezone support has been added in Twig 1.6.1.
9
10Converts an argument to a date to allow date comparison:
11
12.. code-block:: jinja
13
14 {% if date(user.created_at) < date('-2days') %}
15 {# do something #}
16 {% endif %}
17
18The argument must be in a format supported by the `date`_ function.
19
20You can pass a timezone as the second argument:
21
22.. code-block:: jinja
23
24 {% if date(user.created_at) < date('-2days', 'Europe/Paris') %}
25 {# do something #}
26 {% endif %}
27
28If no argument is passed, the function returns the current date:
29
30.. code-block:: jinja
31
32 {% if date(user.created_at) < date() %}
33 {# always! #}
34 {% endif %}
35
36.. note::
37
38 You can set the default timezone globally by calling ``setTimezone()`` on
39 the ``core`` extension instance:
40
41 .. code-block:: php
42
43 $twig = new Twig_Environment($loader);
44 $twig->getExtension('core')->setTimezone('Europe/Paris');
45
46Arguments
47---------
48
49 * ``date``: The date
50 * ``timezone``: The timezone
51
52.. _`date`: http://www.php.net/date
diff --git a/vendor/twig/twig/doc/functions/dump.rst b/vendor/twig/twig/doc/functions/dump.rst
new file mode 100644
index 00000000..1500b0f4
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/dump.rst
@@ -0,0 +1,69 @@
1``dump``
2========
3
4.. versionadded:: 1.5
5 The dump function was added in Twig 1.5.
6
7The ``dump`` function dumps information about a template variable. This is
8mostly useful to debug a template that does not behave as expected by
9introspecting its variables:
10
11.. code-block:: jinja
12
13 {{ dump(user) }}
14
15.. note::
16
17 The ``dump`` function is not available by default. You must add the
18 ``Twig_Extension_Debug`` extension explicitly when creating your Twig
19 environment::
20
21 $twig = new Twig_Environment($loader, array(
22 'debug' => true,
23 // ...
24 ));
25 $twig->addExtension(new Twig_Extension_Debug());
26
27 Even when enabled, the ``dump`` function won't display anything if the
28 ``debug`` option on the environment is not enabled (to avoid leaking debug
29 information on a production server).
30
31In an HTML context, wrap the output with a ``pre`` tag to make it easier to
32read:
33
34.. code-block:: jinja
35
36 <pre>
37 {{ dump(user) }}
38 </pre>
39
40.. tip::
41
42 Using a ``pre`` tag is not needed when `XDebug`_ is enabled and
43 ``html_errors`` is ``on``; as a bonus, the output is also nicer with
44 XDebug enabled.
45
46You can debug several variables by passing them as additional arguments:
47
48.. code-block:: jinja
49
50 {{ dump(user, categories) }}
51
52If you don't pass any value, all variables from the current context are
53dumped:
54
55.. code-block:: jinja
56
57 {{ dump() }}
58
59.. note::
60
61 Internally, Twig uses the PHP `var_dump`_ function.
62
63Arguments
64---------
65
66 * ``context``: The context to dump
67
68.. _`XDebug`: http://xdebug.org/docs/display
69.. _`var_dump`: http://php.net/var_dump
diff --git a/vendor/twig/twig/doc/functions/include.rst b/vendor/twig/twig/doc/functions/include.rst
new file mode 100644
index 00000000..eaddfe61
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/include.rst
@@ -0,0 +1,80 @@
1``include``
2===========
3
4.. versionadded:: 1.12
5 The include function was added in Twig 1.12.
6
7The ``include`` function returns the rendered content of a template:
8
9.. code-block:: jinja
10
11 {{ include('template.html') }}
12 {{ include(some_var) }}
13
14Included templates have access to the variables of the active context.
15
16If you are using the filesystem loader, the templates are looked for in the
17paths defined by it.
18
19The context is passed by default to the template but you can also pass
20additional variables:
21
22.. code-block:: jinja
23
24 {# template.html will have access to the variables from the current context and the additional ones provided #}
25 {{ include('template.html', {foo: 'bar'}) }}
26
27You can disable access to the context by setting ``with_context`` to
28``false``:
29
30.. code-block:: jinja
31
32 {# only the foo variable will be accessible #}
33 {{ include('template.html', {foo: 'bar'}, with_context = false) }}
34
35.. code-block:: jinja
36
37 {# no variables will be accessible #}
38 {{ include('template.html', with_context = false) }}
39
40And if the expression evaluates to a ``Twig_Template`` object, Twig will use it
41directly::
42
43 // {{ include(template) }}
44
45 $template = $twig->loadTemplate('some_template.twig');
46
47 $twig->loadTemplate('template.twig')->display(array('template' => $template));
48
49When you set the ``ignore_missing`` flag, Twig will return an empty string if
50the template does not exist:
51
52.. code-block:: jinja
53
54 {{ include('sidebar.html', ignore_missing = true) }}
55
56You can also provide a list of templates that are checked for existence before
57inclusion. The first template that exists will be rendered:
58
59.. code-block:: jinja
60
61 {{ include(['page_detailed.html', 'page.html']) }}
62
63If ``ignore_missing`` is set, it will fall back to rendering nothing if none
64of the templates exist, otherwise it will throw an exception.
65
66When including a template created by an end user, you should consider
67sandboxing it:
68
69.. code-block:: jinja
70
71 {{ include('page.html', sandboxed = true) }}
72
73Arguments
74---------
75
76 * ``template``: The template to render
77 * ``variables``: The variables to pass to the template
78 * ``with_context``: Whether to pass the current context variables or not
79 * ``ignore_missing``: Whether to ignore missing templates or not
80 * ``sandboxed``: Whether to sandbox the template or not
diff --git a/vendor/twig/twig/doc/functions/index.rst b/vendor/twig/twig/doc/functions/index.rst
new file mode 100644
index 00000000..8650cbdb
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/index.rst
@@ -0,0 +1,17 @@
1Functions
2=========
3
4.. toctree::
5 :maxdepth: 1
6
7 attribute
8 block
9 constant
10 cycle
11 date
12 dump
13 include
14 parent
15 random
16 range
17 template_from_string
diff --git a/vendor/twig/twig/doc/functions/parent.rst b/vendor/twig/twig/doc/functions/parent.rst
new file mode 100644
index 00000000..f5bd2001
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/parent.rst
@@ -0,0 +1,20 @@
1``parent``
2==========
3
4When a template uses inheritance, it's possible to render the contents of the
5parent block when overriding a block by using the ``parent`` function:
6
7.. code-block:: jinja
8
9 {% extends "base.html" %}
10
11 {% block sidebar %}
12 <h3>Table Of Contents</h3>
13 ...
14 {{ parent() }}
15 {% endblock %}
16
17The ``parent()`` call will return the content of the ``sidebar`` block as
18defined in the ``base.html`` template.
19
20.. seealso:: :doc:`extends<../tags/extends>`, :doc:`block<../functions/block>`, :doc:`block<../tags/block>`
diff --git a/vendor/twig/twig/doc/functions/random.rst b/vendor/twig/twig/doc/functions/random.rst
new file mode 100644
index 00000000..a5a916bb
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/random.rst
@@ -0,0 +1,29 @@
1``random``
2==========
3
4.. versionadded:: 1.5
5 The random function was added in Twig 1.5.
6
7.. versionadded:: 1.6
8 String and integer handling was added in Twig 1.6.
9
10The ``random`` function returns a random value depending on the supplied
11parameter type:
12
13* a random item from a sequence;
14* a random character from a string;
15* a random integer between 0 and the integer parameter (inclusive).
16
17.. code-block:: jinja
18
19 {{ random(['apple', 'orange', 'citrus']) }} {# example output: orange #}
20 {{ random('ABC') }} {# example output: C #}
21 {{ random() }} {# example output: 15386094 (works as native PHP `mt_rand`_ function) #}
22 {{ random(5) }} {# example output: 3 #}
23
24Arguments
25---------
26
27 * ``values``: The values
28
29.. _`mt_rand`: http://php.net/mt_rand
diff --git a/vendor/twig/twig/doc/functions/range.rst b/vendor/twig/twig/doc/functions/range.rst
new file mode 100644
index 00000000..b1fa5471
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/range.rst
@@ -0,0 +1,45 @@
1``range``
2=========
3
4Returns a list containing an arithmetic progression of integers:
5
6.. code-block:: jinja
7
8 {% for i in range(0, 3) %}
9 {{ i }},
10 {% endfor %}
11
12 {# returns 0, 1, 2, 3 #}
13
14When step is given (as the third parameter), it specifies the increment (or
15decrement):
16
17.. code-block:: jinja
18
19 {% for i in range(0, 6, 2) %}
20 {{ i }},
21 {% endfor %}
22
23 {# returns 0, 2, 4, 6 #}
24
25The Twig built-in ``..`` operator is just syntactic sugar for the ``range``
26function (with a step of 1):
27
28.. code-block:: jinja
29
30 {% for i in 0..3 %}
31 {{ i }},
32 {% endfor %}
33
34.. tip::
35
36 The ``range`` function works as the native PHP `range`_ function.
37
38Arguments
39---------
40
41 * ``low``: The first value of the sequence.
42 * ``high``: The highest possible value of the sequence.
43 * ``step``: The increment between elements of the sequence.
44
45.. _`range`: http://php.net/range
diff --git a/vendor/twig/twig/doc/functions/template_from_string.rst b/vendor/twig/twig/doc/functions/template_from_string.rst
new file mode 100644
index 00000000..bbb06d86
--- /dev/null
+++ b/vendor/twig/twig/doc/functions/template_from_string.rst
@@ -0,0 +1,32 @@
1``template_from_string``
2========================
3
4.. versionadded:: 1.11
5 The template_from_string function was added in Twig 1.11.
6
7The ``template_from_string`` function loads a template from a string:
8
9.. code-block:: jinja
10
11 {{ include(template_from_string("Hello {{ name }}") }}
12 {{ include(template_from_string(page.template)) }}
13
14.. note::
15
16 The ``template_from_string`` function is not available by default. You
17 must add the ``Twig_Extension_StringLoader`` extension explicitly when
18 creating your Twig environment::
19
20 $twig = new Twig_Environment(...);
21 $twig->addExtension(new Twig_Extension_StringLoader());
22
23.. note::
24
25 Even if you will probably always use the ``template_from_string`` function
26 with the ``include`` function, you can use it with any tag or function that
27 takes a template as an argument (like the ``embed`` or ``extends`` tags).
28
29Arguments
30---------
31
32 * ``template``: The template
diff --git a/vendor/twig/twig/doc/index.rst b/vendor/twig/twig/doc/index.rst
new file mode 100644
index 00000000..3e5166c6
--- /dev/null
+++ b/vendor/twig/twig/doc/index.rst
@@ -0,0 +1,18 @@
1Twig
2====
3
4.. toctree::
5 :maxdepth: 2
6
7 intro
8 templates
9 api
10 advanced
11 internals
12 recipes
13 coding_standards
14 tags/index
15 filters/index
16 functions/index
17 tests/index
18 deprecated
diff --git a/vendor/twig/twig/doc/internals.rst b/vendor/twig/twig/doc/internals.rst
new file mode 100644
index 00000000..79a3c8d5
--- /dev/null
+++ b/vendor/twig/twig/doc/internals.rst
@@ -0,0 +1,140 @@
1Twig Internals
2==============
3
4Twig is very extensible and you can easily hack it. Keep in mind that you
5should probably try to create an extension before hacking the core, as most
6features and enhancements can be done with extensions. This chapter is also
7useful for people who want to understand how Twig works under the hood.
8
9How Twig works?
10---------------
11
12The rendering of a Twig template can be summarized into four key steps:
13
14* **Load** the template: If the template is already compiled, load it and go
15 to the *evaluation* step, otherwise:
16
17 * First, the **lexer** tokenizes the template source code into small pieces
18 for easier processing;
19 * Then, the **parser** converts the token stream into a meaningful tree
20 of nodes (the Abstract Syntax Tree);
21 * Eventually, the *compiler* transforms the AST into PHP code;
22
23* **Evaluate** the template: It basically means calling the ``display()``
24 method of the compiled template and passing it the context.
25
26The Lexer
27---------
28
29The lexer tokenizes a template source code into a token stream (each token is
30an instance of ``Twig_Token``, and the stream is an instance of
31``Twig_TokenStream``). The default lexer recognizes 13 different token types:
32
33* ``Twig_Token::BLOCK_START_TYPE``, ``Twig_Token::BLOCK_END_TYPE``: Delimiters for blocks (``{% %}``)
34* ``Twig_Token::VAR_START_TYPE``, ``Twig_Token::VAR_END_TYPE``: Delimiters for variables (``{{ }}``)
35* ``Twig_Token::TEXT_TYPE``: A text outside an expression;
36* ``Twig_Token::NAME_TYPE``: A name in an expression;
37* ``Twig_Token::NUMBER_TYPE``: A number in an expression;
38* ``Twig_Token::STRING_TYPE``: A string in an expression;
39* ``Twig_Token::OPERATOR_TYPE``: An operator;
40* ``Twig_Token::PUNCTUATION_TYPE``: A punctuation sign;
41* ``Twig_Token::INTERPOLATION_START_TYPE``, ``Twig_Token::INTERPOLATION_END_TYPE`` (as of Twig 1.5): Delimiters for string interpolation;
42* ``Twig_Token::EOF_TYPE``: Ends of template.
43
44You can manually convert a source code into a token stream by calling the
45``tokenize()`` of an environment::
46
47 $stream = $twig->tokenize($source, $identifier);
48
49As the stream has a ``__toString()`` method, you can have a textual
50representation of it by echoing the object::
51
52 echo $stream."\n";
53
54Here is the output for the ``Hello {{ name }}`` template:
55
56.. code-block:: text
57
58 TEXT_TYPE(Hello )
59 VAR_START_TYPE()
60 NAME_TYPE(name)
61 VAR_END_TYPE()
62 EOF_TYPE()
63
64.. note::
65
66 You can change the default lexer use by Twig (``Twig_Lexer``) by calling
67 the ``setLexer()`` method::
68
69 $twig->setLexer($lexer);
70
71The Parser
72----------
73
74The parser converts the token stream into an AST (Abstract Syntax Tree), or a
75node tree (an instance of ``Twig_Node_Module``). The core extension defines
76the basic nodes like: ``for``, ``if``, ... and the expression nodes.
77
78You can manually convert a token stream into a node tree by calling the
79``parse()`` method of an environment::
80
81 $nodes = $twig->parse($stream);
82
83Echoing the node object gives you a nice representation of the tree::
84
85 echo $nodes."\n";
86
87Here is the output for the ``Hello {{ name }}`` template:
88
89.. code-block:: text
90
91 Twig_Node_Module(
92 Twig_Node_Text(Hello )
93 Twig_Node_Print(
94 Twig_Node_Expression_Name(name)
95 )
96 )
97
98.. note::
99
100 The default parser (``Twig_TokenParser``) can be also changed by calling the
101 ``setParser()`` method::
102
103 $twig->setParser($parser);
104
105The Compiler
106------------
107
108The last step is done by the compiler. It takes a node tree as an input and
109generates PHP code usable for runtime execution of the template.
110
111You can call the compiler by hand with the ``compile()`` method of an
112environment::
113
114 $php = $twig->compile($nodes);
115
116The ``compile()`` method returns the PHP source code representing the node.
117
118The generated template for a ``Hello {{ name }}`` template reads as follows
119(the actual output can differ depending on the version of Twig you are
120using)::
121
122 /* Hello {{ name }} */
123 class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Twig_Template
124 {
125 protected function doDisplay(array $context, array $blocks = array())
126 {
127 // line 1
128 echo "Hello ";
129 echo twig_escape_filter($this->env, $this->getContext($context, "name"), "ndex", null, true);
130 }
131
132 // some more code
133 }
134
135.. note::
136
137 As for the lexer and the parser, the default compiler (``Twig_Compiler``) can
138 be changed by calling the ``setCompiler()`` method::
139
140 $twig->setCompiler($compiler);
diff --git a/vendor/twig/twig/doc/intro.rst b/vendor/twig/twig/doc/intro.rst
new file mode 100644
index 00000000..bdcdb8a0
--- /dev/null
+++ b/vendor/twig/twig/doc/intro.rst
@@ -0,0 +1,164 @@
1Introduction
2============
3
4This is the documentation for Twig, the flexible, fast, and secure template
5engine for PHP.
6
7If you have any exposure to other text-based template languages, such as
8Smarty, Django, or Jinja, you should feel right at home with Twig. It's both
9designer and developer friendly by sticking to PHP's principles and adding
10functionality useful for templating environments.
11
12The key-features are...
13
14* *Fast*: Twig compiles templates down to plain optimized PHP code. The
15 overhead compared to regular PHP code was reduced to the very minimum.
16
17* *Secure*: Twig has a sandbox mode to evaluate untrusted template code. This
18 allows Twig to be used as a template language for applications where users
19 may modify the template design.
20
21* *Flexible*: Twig is powered by a flexible lexer and parser. This allows the
22 developer to define its own custom tags and filters, and create its own DSL.
23
24Prerequisites
25-------------
26
27Twig needs at least **PHP 5.2.4** to run.
28
29Installation
30------------
31
32You have multiple ways to install Twig.
33
34Installing via Composer (recommended)
35~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36
371. Install composer in your project:
38
39.. code-block:: bash
40
41 curl -s http://getcomposer.org/installer | php
42
432. Create a ``composer.json`` file in your project root:
44
45.. code-block:: javascript
46
47 {
48 "require": {
49 "twig/twig": "1.*"
50 }
51 }
52
533. Install via composer
54
55.. code-block:: bash
56
57 php composer.phar install
58
59.. note::
60 If you want to learn more about Composer, the ``composer.json`` file syntax
61 and its usage, you can read the `online documentation`_.
62
63Installing from the tarball release
64~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
65
661. Download the most recent tarball from the `download page`_
672. Unpack the tarball
683. Move the files somewhere in your project
69
70Installing the development version
71~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
72
731. Install Git
742. ``git clone git://github.com/fabpot/Twig.git``
75
76Installing the PEAR package
77~~~~~~~~~~~~~~~~~~~~~~~~~~~
78
791. Install PEAR
802. ``pear channel-discover pear.twig-project.org``
813. ``pear install twig/Twig`` (or ``pear install twig/Twig-beta``)
82
83
84Installing the C extension
85~~~~~~~~~~~~~~~~~~~~~~~~~~
86
87.. versionadded:: 1.4
88 The C extension was added in Twig 1.4.
89
90Twig comes with a C extension that enhances the performance of the Twig
91runtime engine. You can install it like any other PHP extension:
92
93.. code-block:: bash
94
95 $ cd ext/twig
96 $ phpize
97 $ ./configure
98 $ make
99 $ make install
100
101Finally, enable the extension in your ``php.ini`` configuration file:
102
103.. code-block:: ini
104
105 extension=twig.so
106
107And from now on, Twig will automatically compile your templates to take
108advantage of the C extension. Note that this extension does not replace the
109PHP code but only provides an optimized version of the
110``Twig_Template::getAttribute()`` method.
111
112.. tip::
113
114 On Windows, you can also simply download and install a `pre-built DLL`_.
115
116Basic API Usage
117---------------
118
119This section gives you a brief introduction to the PHP API for Twig.
120
121The first step to use Twig is to register its autoloader::
122
123 require_once '/path/to/lib/Twig/Autoloader.php';
124 Twig_Autoloader::register();
125
126Replace the ``/path/to/lib/`` path with the path you used for Twig
127installation.
128
129If you have installed Twig via Composer you can take advantage of Composer's
130autoload mechanism by replacing the previous snippet for::
131
132 require_once '/path/to/vendor/autoload.php';
133
134.. note::
135
136 Twig follows the PEAR convention names for its classes, which means you
137 can easily integrate Twig classes loading in your own autoloader.
138
139.. code-block:: php
140
141 $loader = new Twig_Loader_String();
142 $twig = new Twig_Environment($loader);
143
144 echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
145
146Twig uses a loader (``Twig_Loader_String``) to locate templates, and an
147environment (``Twig_Environment``) to store the configuration.
148
149The ``render()`` method loads the template passed as a first argument and
150renders it with the variables passed as a second argument.
151
152As templates are generally stored on the filesystem, Twig also comes with a
153filesystem loader::
154
155 $loader = new Twig_Loader_Filesystem('/path/to/templates');
156 $twig = new Twig_Environment($loader, array(
157 'cache' => '/path/to/compilation_cache',
158 ));
159
160 echo $twig->render('index.html', array('name' => 'Fabien'));
161
162.. _`download page`: https://github.com/fabpot/Twig/tags
163.. _`online documentation`: http://getcomposer.org/doc
164.. _`pre-built DLL`: https://github.com/stealth35/stealth35.github.com/downloads
diff --git a/vendor/twig/twig/doc/recipes.rst b/vendor/twig/twig/doc/recipes.rst
new file mode 100644
index 00000000..dfcc9205
--- /dev/null
+++ b/vendor/twig/twig/doc/recipes.rst
@@ -0,0 +1,475 @@
1Recipes
2=======
3
4Making a Layout conditional
5---------------------------
6
7Working with Ajax means that the same content is sometimes displayed as is,
8and sometimes decorated with a layout. As Twig layout template names can be
9any valid expression, you can pass a variable that evaluates to ``true`` when
10the request is made via Ajax and choose the layout accordingly:
11
12.. code-block:: jinja
13
14 {% extends request.ajax ? "base_ajax.html" : "base.html" %}
15
16 {% block content %}
17 This is the content to be displayed.
18 {% endblock %}
19
20Making an Include dynamic
21-------------------------
22
23When including a template, its name does not need to be a string. For
24instance, the name can depend on the value of a variable:
25
26.. code-block:: jinja
27
28 {% include var ~ '_foo.html' %}
29
30If ``var`` evaluates to ``index``, the ``index_foo.html`` template will be
31rendered.
32
33As a matter of fact, the template name can be any valid expression, such as
34the following:
35
36.. code-block:: jinja
37
38 {% include var|default('index') ~ '_foo.html' %}
39
40Overriding a Template that also extends itself
41----------------------------------------------
42
43A template can be customized in two different ways:
44
45* *Inheritance*: A template *extends* a parent template and overrides some
46 blocks;
47
48* *Replacement*: If you use the filesystem loader, Twig loads the first
49 template it finds in a list of configured directories; a template found in a
50 directory *replaces* another one from a directory further in the list.
51
52But how do you combine both: *replace* a template that also extends itself
53(aka a template in a directory further in the list)?
54
55Let's say that your templates are loaded from both ``.../templates/mysite``
56and ``.../templates/default`` in this order. The ``page.twig`` template,
57stored in ``.../templates/default`` reads as follows:
58
59.. code-block:: jinja
60
61 {# page.twig #}
62 {% extends "layout.twig" %}
63
64 {% block content %}
65 {% endblock %}
66
67You can replace this template by putting a file with the same name in
68``.../templates/mysite``. And if you want to extend the original template, you
69might be tempted to write the following:
70
71.. code-block:: jinja
72
73 {# page.twig in .../templates/mysite #}
74 {% extends "page.twig" %} {# from .../templates/default #}
75
76Of course, this will not work as Twig will always load the template from
77``.../templates/mysite``.
78
79It turns out it is possible to get this to work, by adding a directory right
80at the end of your template directories, which is the parent of all of the
81other directories: ``.../templates`` in our case. This has the effect of
82making every template file within our system uniquely addressable. Most of the
83time you will use the "normal" paths, but in the special case of wanting to
84extend a template with an overriding version of itself we can reference its
85parent's full, unambiguous template path in the extends tag:
86
87.. code-block:: jinja
88
89 {# page.twig in .../templates/mysite #}
90 {% extends "default/page.twig" %} {# from .../templates #}
91
92.. note::
93
94 This recipe was inspired by the following Django wiki page:
95 http://code.djangoproject.com/wiki/ExtendingTemplates
96
97Customizing the Syntax
98----------------------
99
100Twig allows some syntax customization for the block delimiters. It's not
101recommended to use this feature as templates will be tied with your custom
102syntax. But for specific projects, it can make sense to change the defaults.
103
104To change the block delimiters, you need to create your own lexer object::
105
106 $twig = new Twig_Environment();
107
108 $lexer = new Twig_Lexer($twig, array(
109 'tag_comment' => array('{#', '#}'),
110 'tag_block' => array('{%', '%}'),
111 'tag_variable' => array('{{', '}}'),
112 'interpolation' => array('#{', '}'),
113 ));
114 $twig->setLexer($lexer);
115
116Here are some configuration example that simulates some other template engines
117syntax::
118
119 // Ruby erb syntax
120 $lexer = new Twig_Lexer($twig, array(
121 'tag_comment' => array('<%#', '%>'),
122 'tag_block' => array('<%', '%>'),
123 'tag_variable' => array('<%=', '%>'),
124 ));
125
126 // SGML Comment Syntax
127 $lexer = new Twig_Lexer($twig, array(
128 'tag_comment' => array('<!--#', '-->'),
129 'tag_block' => array('<!--', '-->'),
130 'tag_variable' => array('${', '}'),
131 ));
132
133 // Smarty like
134 $lexer = new Twig_Lexer($twig, array(
135 'tag_comment' => array('{*', '*}'),
136 'tag_block' => array('{', '}'),
137 'tag_variable' => array('{$', '}'),
138 ));
139
140Using dynamic Object Properties
141-------------------------------
142
143When Twig encounters a variable like ``article.title``, it tries to find a
144``title`` public property in the ``article`` object.
145
146It also works if the property does not exist but is rather defined dynamically
147thanks to the magic ``__get()`` method; you just need to also implement the
148``__isset()`` magic method like shown in the following snippet of code::
149
150 class Article
151 {
152 public function __get($name)
153 {
154 if ('title' == $name) {
155 return 'The title';
156 }
157
158 // throw some kind of error
159 }
160
161 public function __isset($name)
162 {
163 if ('title' == $name) {
164 return true;
165 }
166
167 return false;
168 }
169 }
170
171Accessing the parent Context in Nested Loops
172--------------------------------------------
173
174Sometimes, when using nested loops, you need to access the parent context. The
175parent context is always accessible via the ``loop.parent`` variable. For
176instance, if you have the following template data::
177
178 $data = array(
179 'topics' => array(
180 'topic1' => array('Message 1 of topic 1', 'Message 2 of topic 1'),
181 'topic2' => array('Message 1 of topic 2', 'Message 2 of topic 2'),
182 ),
183 );
184
185And the following template to display all messages in all topics:
186
187.. code-block:: jinja
188
189 {% for topic, messages in topics %}
190 * {{ loop.index }}: {{ topic }}
191 {% for message in messages %}
192 - {{ loop.parent.loop.index }}.{{ loop.index }}: {{ message }}
193 {% endfor %}
194 {% endfor %}
195
196The output will be similar to:
197
198.. code-block:: text
199
200 * 1: topic1
201 - 1.1: The message 1 of topic 1
202 - 1.2: The message 2 of topic 1
203 * 2: topic2
204 - 2.1: The message 1 of topic 2
205 - 2.2: The message 2 of topic 2
206
207In the inner loop, the ``loop.parent`` variable is used to access the outer
208context. So, the index of the current ``topic`` defined in the outer for loop
209is accessible via the ``loop.parent.loop.index`` variable.
210
211Defining undefined Functions and Filters on the Fly
212---------------------------------------------------
213
214When a function (or a filter) is not defined, Twig defaults to throw a
215``Twig_Error_Syntax`` exception. However, it can also call a `callback`_ (any
216valid PHP callable) which should return a function (or a filter).
217
218For filters, register callbacks with ``registerUndefinedFilterCallback()``.
219For functions, use ``registerUndefinedFunctionCallback()``::
220
221 // auto-register all native PHP functions as Twig functions
222 // don't try this at home as it's not secure at all!
223 $twig->registerUndefinedFunctionCallback(function ($name) {
224 if (function_exists($name)) {
225 return new Twig_Function_Function($name);
226 }
227
228 return false;
229 });
230
231If the callable is not able to return a valid function (or filter), it must
232return ``false``.
233
234If you register more than one callback, Twig will call them in turn until one
235does not return ``false``.
236
237.. tip::
238
239 As the resolution of functions and filters is done during compilation,
240 there is no overhead when registering these callbacks.
241
242Validating the Template Syntax
243------------------------------
244
245When template code is providing by a third-party (through a web interface for
246instance), it might be interesting to validate the template syntax before
247saving it. If the template code is stored in a `$template` variable, here is
248how you can do it::
249
250 try {
251 $twig->parse($twig->tokenize($template));
252
253 // the $template is valid
254 } catch (Twig_Error_Syntax $e) {
255 // $template contains one or more syntax errors
256 }
257
258If you iterate over a set of files, you can pass the filename to the
259``tokenize()`` method to get the filename in the exception message::
260
261 foreach ($files as $file) {
262 try {
263 $twig->parse($twig->tokenize($template, $file));
264
265 // the $template is valid
266 } catch (Twig_Error_Syntax $e) {
267 // $template contains one or more syntax errors
268 }
269 }
270
271.. note::
272
273 This method won't catch any sandbox policy violations because the policy
274 is enforced during template rendering (as Twig needs the context for some
275 checks like allowed methods on objects).
276
277Refreshing modified Templates when APC is enabled and apc.stat = 0
278------------------------------------------------------------------
279
280When using APC with ``apc.stat`` set to ``0`` and Twig cache enabled, clearing
281the template cache won't update the APC cache. To get around this, one can
282extend ``Twig_Environment`` and force the update of the APC cache when Twig
283rewrites the cache::
284
285 class Twig_Environment_APC extends Twig_Environment
286 {
287 protected function writeCacheFile($file, $content)
288 {
289 parent::writeCacheFile($file, $content);
290
291 // Compile cached file into bytecode cache
292 apc_compile_file($file);
293 }
294 }
295
296Reusing a stateful Node Visitor
297-------------------------------
298
299When attaching a visitor to a ``Twig_Environment`` instance, Twig uses it to
300visit *all* templates it compiles. If you need to keep some state information
301around, you probably want to reset it when visiting a new template.
302
303This can be easily achieved with the following code::
304
305 protected $someTemplateState = array();
306
307 public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
308 {
309 if ($node instanceof Twig_Node_Module) {
310 // reset the state as we are entering a new template
311 $this->someTemplateState = array();
312 }
313
314 // ...
315
316 return $node;
317 }
318
319Using the Template name to set the default Escaping Strategy
320------------------------------------------------------------
321
322.. versionadded:: 1.8
323 This recipe requires Twig 1.8 or later.
324
325The ``autoescape`` option determines the default escaping strategy to use when
326no escaping is applied on a variable. When Twig is used to mostly generate
327HTML files, you can set it to ``html`` and explicitly change it to ``js`` when
328you have some dynamic JavaScript files thanks to the ``autoescape`` tag:
329
330.. code-block:: jinja
331
332 {% autoescape 'js' %}
333 ... some JS ...
334 {% endautoescape %}
335
336But if you have many HTML and JS files, and if your template names follow some
337conventions, you can instead determine the default escaping strategy to use
338based on the template name. Let's say that your template names always ends
339with ``.html`` for HTML files, ``.js`` for JavaScript ones, and ``.css`` for
340stylesheets, here is how you can configure Twig::
341
342 class TwigEscapingGuesser
343 {
344 function guess($filename)
345 {
346 // get the format
347 $format = substr($filename, strrpos($filename, '.') + 1);
348
349 switch ($format) {
350 case 'js':
351 return 'js';
352 case 'css':
353 return 'css';
354 case 'html':
355 default:
356 return 'html';
357 }
358 }
359 }
360
361 $loader = new Twig_Loader_Filesystem('/path/to/templates');
362 $twig = new Twig_Environment($loader, array(
363 'autoescape' => array(new TwigEscapingGuesser(), 'guess'),
364 ));
365
366This dynamic strategy does not incur any overhead at runtime as auto-escaping
367is done at compilation time.
368
369Using a Database to store Templates
370-----------------------------------
371
372If you are developing a CMS, templates are usually stored in a database. This
373recipe gives you a simple PDO template loader you can use as a starting point
374for your own.
375
376First, let's create a temporary in-memory SQLite3 database to work with::
377
378 $dbh = new PDO('sqlite::memory:');
379 $dbh->exec('CREATE TABLE templates (name STRING, source STRING, last_modified INTEGER)');
380 $base = '{% block content %}{% endblock %}';
381 $index = '
382 {% extends "base.twig" %}
383 {% block content %}Hello {{ name }}{% endblock %}
384 ';
385 $now = time();
386 $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('base.twig', '$base', $now)");
387 $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('index.twig', '$index', $now)");
388
389We have created a simple ``templates`` table that hosts two templates:
390``base.twig`` and ``index.twig``.
391
392Now, let's define a loader able to use this database::
393
394 class DatabaseTwigLoader implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
395 {
396 protected $dbh;
397
398 public function __construct(PDO $dbh)
399 {
400 $this->dbh = $dbh;
401 }
402
403 public function getSource($name)
404 {
405 if (false === $source = $this->getValue('source', $name)) {
406 throw new Twig_Error_Loader(sprintf('Template "%s" does not exist.', $name));
407 }
408
409 return $source;
410 }
411
412 // Twig_ExistsLoaderInterface as of Twig 1.11
413 public function exists($name)
414 {
415 return $name === $this->getValue('name', $name);
416 }
417
418 public function getCacheKey($name)
419 {
420 return $name;
421 }
422
423 public function isFresh($name, $time)
424 {
425 if (false === $lastModified = $this->getValue('last_modified', $name)) {
426 return false;
427 }
428
429 return $lastModified <= $time;
430 }
431
432 protected function getValue($column, $name)
433 {
434 $sth = $this->dbh->prepare('SELECT '.$column.' FROM templates WHERE name = :name');
435 $sth->execute(array(':name' => (string) $name));
436
437 return $sth->fetchColumn();
438 }
439 }
440
441Finally, here is an example on how you can use it::
442
443 $loader = new DatabaseTwigLoader($dbh);
444 $twig = new Twig_Environment($loader);
445
446 echo $twig->render('index.twig', array('name' => 'Fabien'));
447
448Using different Template Sources
449--------------------------------
450
451This recipe is the continuation of the previous one. Even if you store the
452contributed templates in a database, you might want to keep the original/base
453templates on the filesystem. When templates can be loaded from different
454sources, you need to use the ``Twig_Loader_Chain`` loader.
455
456As you can see in the previous recipe, we reference the template in the exact
457same way as we would have done it with a regular filesystem loader. This is
458the key to be able to mix and match templates coming from the database, the
459filesystem, or any other loader for that matter: the template name should be a
460logical name, and not the path from the filesystem::
461
462 $loader1 = new DatabaseTwigLoader($dbh);
463 $loader2 = new Twig_Loader_Array(array(
464 'base.twig' => '{% block content %}{% endblock %}',
465 ));
466 $loader = new Twig_Loader_Chain(array($loader1, $loader2));
467
468 $twig = new Twig_Environment($loader);
469
470 echo $twig->render('index.twig', array('name' => 'Fabien'));
471
472Now that the ``base.twig`` templates is defined in an array loader, you can
473remove it from the database, and everything else will still work as before.
474
475.. _callback: http://www.php.net/manual/en/function.is-callable.php
diff --git a/vendor/twig/twig/doc/tags/autoescape.rst b/vendor/twig/twig/doc/tags/autoescape.rst
new file mode 100644
index 00000000..c5ff0c2c
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/autoescape.rst
@@ -0,0 +1,71 @@
1``autoescape``
2==============
3
4Whether automatic escaping is enabled or not, you can mark a section of a
5template to be escaped or not by using the ``autoescape`` tag:
6
7.. code-block:: jinja
8
9 {# The following syntax works as of Twig 1.8 -- see the note below for previous versions #}
10
11 {% autoescape %}
12 Everything will be automatically escaped in this block
13 using the HTML strategy
14 {% endautoescape %}
15
16 {% autoescape 'html' %}
17 Everything will be automatically escaped in this block
18 using the HTML strategy
19 {% endautoescape %}
20
21 {% autoescape 'js' %}
22 Everything will be automatically escaped in this block
23 using the js escaping strategy
24 {% endautoescape %}
25
26 {% autoescape false %}
27 Everything will be outputted as is in this block
28 {% endautoescape %}
29
30.. note::
31
32 Before Twig 1.8, the syntax was different:
33
34 .. code-block:: jinja
35
36 {% autoescape true %}
37 Everything will be automatically escaped in this block
38 using the HTML strategy
39 {% endautoescape %}
40
41 {% autoescape false %}
42 Everything will be outputted as is in this block
43 {% endautoescape %}
44
45 {% autoescape true js %}
46 Everything will be automatically escaped in this block
47 using the js escaping strategy
48 {% endautoescape %}
49
50When automatic escaping is enabled everything is escaped by default except for
51values explicitly marked as safe. Those can be marked in the template by using
52the :doc:`raw<../filters/raw>` filter:
53
54.. code-block:: jinja
55
56 {% autoescape %}
57 {{ safe_value|raw }}
58 {% endautoescape %}
59
60Functions returning template data (like :doc:`macros<macro>` and
61:doc:`parent<../functions/parent>`) always return safe markup.
62
63.. note::
64
65 Twig is smart enough to not escape an already escaped value by the
66 :doc:`escape<../filters/escape>` filter.
67
68.. note::
69
70 The chapter :doc:`Twig for Developers<../api>` gives more information
71 about when and how automatic escaping is applied.
diff --git a/vendor/twig/twig/doc/tags/block.rst b/vendor/twig/twig/doc/tags/block.rst
new file mode 100644
index 00000000..e3804823
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/block.rst
@@ -0,0 +1,11 @@
1``block``
2=========
3
4Blocks are used for inheritance and act as placeholders and replacements at
5the same time. They are documented in detail in the documentation for the
6:doc:`extends<../tags/extends>` tag.
7
8Block names should consist of alphanumeric characters, and underscores. Dashes
9are not permitted.
10
11.. seealso:: :doc:`block<../functions/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>`, :doc:`extends<../tags/extends>`
diff --git a/vendor/twig/twig/doc/tags/do.rst b/vendor/twig/twig/doc/tags/do.rst
new file mode 100644
index 00000000..eca63d0a
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/do.rst
@@ -0,0 +1,12 @@
1``do``
2======
3
4.. versionadded:: 1.5
5 The do tag was added in Twig 1.5.
6
7The ``do`` tag works exactly like the regular variable expression (``{{ ...
8}}``) just that it doesn't print anything:
9
10.. code-block:: jinja
11
12 {% do 1 + 2 %}
diff --git a/vendor/twig/twig/doc/tags/embed.rst b/vendor/twig/twig/doc/tags/embed.rst
new file mode 100644
index 00000000..5a6a0299
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/embed.rst
@@ -0,0 +1,178 @@
1``embed``
2=========
3
4.. versionadded:: 1.8
5 The ``embed`` tag was added in Twig 1.8.
6
7The ``embed`` tag combines the behaviour of :doc:`include<include>` and
8:doc:`extends<extends>`.
9It allows you to include another template's contents, just like ``include``
10does. But it also allows you to override any block defined inside the
11included template, like when extending a template.
12
13Think of an embedded template as a "micro layout skeleton".
14
15.. code-block:: jinja
16
17 {% embed "teasers_skeleton.twig" %}
18 {# These blocks are defined in "teasers_skeleton.twig" #}
19 {# and we override them right here: #}
20 {% block left_teaser %}
21 Some content for the left teaser box
22 {% endblock %}
23 {% block right_teaser %}
24 Some content for the right teaser box
25 {% endblock %}
26 {% endembed %}
27
28The ``embed`` tag takes the idea of template inheritance to the level of
29content fragments. While template inheritance allows for "document skeletons",
30which are filled with life by child templates, the ``embed`` tag allows you to
31create "skeletons" for smaller units of content and re-use and fill them
32anywhere you like.
33
34Since the use case may not be obvious, let's look at a simplified example.
35Imagine a base template shared by multiple HTML pages, defining a single block
36named "content":
37
38.. code-block:: text
39
40 ┌─── page layout ─────────────────────┐
41 │ │
42 │ ┌── block "content" ──┐ │
43 │ │ │ │
44 │ │ │ │
45 │ │ (child template to │ │
46 │ │ put content here) │ │
47 │ │ │ │
48 │ │ │ │
49 │ └─────────────────────┘ │
50 │ │
51 └─────────────────────────────────────┘
52
53Some pages ("foo" and "bar") share the same content structure -
54two vertically stacked boxes:
55
56.. code-block:: text
57
58 ┌─── page layout ─────────────────────┐
59 │ │
60 │ ┌── block "content" ──┐ │
61 │ │ ┌─ block "top" ───┐ │ │
62 │ │ │ │ │ │
63 │ │ └─────────────────┘ │ │
64 │ │ ┌─ block "bottom" ┐ │ │
65 │ │ │ │ │ │
66 │ │ └─────────────────┘ │ │
67 │ └─────────────────────┘ │
68 │ │
69 └─────────────────────────────────────┘
70
71While other pages ("boom" and "baz") share a different content structure -
72two boxes side by side:
73
74.. code-block:: text
75
76 ┌─── page layout ─────────────────────┐
77 │ │
78 │ ┌── block "content" ──┐ │
79 │ │ │ │
80 │ │ ┌ block ┐ ┌ block ┐ │ │
81 │ │ │"left" │ │"right"│ │ │
82 │ │ │ │ │ │ │ │
83 │ │ │ │ │ │ │ │
84 │ │ └───────┘ └───────┘ │ │
85 │ └─────────────────────┘ │
86 │ │
87 └─────────────────────────────────────┘
88
89Without the ``embed`` tag, you have two ways to design your templates:
90
91 * Create two "intermediate" base templates that extend the master layout
92 template: one with vertically stacked boxes to be used by the "foo" and
93 "bar" pages and another one with side-by-side boxes for the "boom" and
94 "baz" pages.
95
96 * Embed the markup for the top/bottom and left/right boxes into each page
97 template directly.
98
99These two solutions do not scale well because they each have a major drawback:
100
101 * The first solution may indeed work for this simplified example. But imagine
102 we add a sidebar, which may again contain different, recurring structures
103 of content. Now we would need to create intermediate base templates for
104 all occurring combinations of content structure and sidebar structure...
105 and so on.
106
107 * The second solution involves duplication of common code with all its negative
108 consequences: any change involves finding and editing all affected copies
109 of the structure, correctness has to be verified for each copy, copies may
110 go out of sync by careless modifications etc.
111
112In such a situation, the ``embed`` tag comes in handy. The common layout
113code can live in a single base template, and the two different content structures,
114let's call them "micro layouts" go into separate templates which are embedded
115as necessary:
116
117Page template ``foo.twig``:
118
119.. code-block:: jinja
120
121 {% extends "layout_skeleton.twig" %}
122
123 {% block content %}
124 {% embed "vertical_boxes_skeleton.twig" %}
125 {% block top %}
126 Some content for the top box
127 {% endblock %}
128
129 {% block bottom %}
130 Some content for the bottom box
131 {% endblock %}
132 {% endembed %}
133 {% endblock %}
134
135And here is the code for ``vertical_boxes_skeleton.twig``:
136
137.. code-block:: html+jinja
138
139 <div class="top_box">
140 {% block top %}
141 Top box default content
142 {% endblock %}
143 </div>
144
145 <div class="bottom_box">
146 {% block bottom %}
147 Bottom box default content
148 {% endblock %}
149 </div>
150
151The goal of the ``vertical_boxes_skeleton.twig`` template being to factor
152out the HTML markup for the boxes.
153
154The ``embed`` tag takes the exact same arguments as the ``include`` tag:
155
156.. code-block:: jinja
157
158 {% embed "base" with {'foo': 'bar'} %}
159 ...
160 {% endembed %}
161
162 {% embed "base" with {'foo': 'bar'} only %}
163 ...
164 {% endembed %}
165
166 {% embed "base" ignore missing %}
167 ...
168 {% endembed %}
169
170.. warning::
171
172 As embedded templates do not have "names", auto-escaping strategies based
173 on the template "filename" won't work as expected if you change the
174 context (for instance, if you embed a CSS/JavaScript template into an HTML
175 one). In that case, explicitly set the default auto-escaping strategy with
176 the ``autoescape`` tag.
177
178.. seealso:: :doc:`include<../tags/include>`
diff --git a/vendor/twig/twig/doc/tags/extends.rst b/vendor/twig/twig/doc/tags/extends.rst
new file mode 100644
index 00000000..f995a5dc
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/extends.rst
@@ -0,0 +1,268 @@
1``extends``
2===========
3
4The ``extends`` tag can be used to extend a template from another one.
5
6.. note::
7
8 Like PHP, Twig does not support multiple inheritance. So you can only have
9 one extends tag called per rendering. However, Twig supports horizontal
10 :doc:`reuse<use>`.
11
12Let's define a base template, ``base.html``, which defines a simple HTML
13skeleton document:
14
15.. code-block:: html+jinja
16
17 <!DOCTYPE html>
18 <html>
19 <head>
20 {% block head %}
21 <link rel="stylesheet" href="style.css" />
22 <title>{% block title %}{% endblock %} - My Webpage</title>
23 {% endblock %}
24 </head>
25 <body>
26 <div id="content">{% block content %}{% endblock %}</div>
27 <div id="footer">
28 {% block footer %}
29 &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
30 {% endblock %}
31 </div>
32 </body>
33 </html>
34
35In this example, the :doc:`block<block>` tags define four blocks that child
36templates can fill in.
37
38All the ``block`` tag does is to tell the template engine that a child
39template may override those portions of the template.
40
41Child Template
42--------------
43
44A child template might look like this:
45
46.. code-block:: jinja
47
48 {% extends "base.html" %}
49
50 {% block title %}Index{% endblock %}
51 {% block head %}
52 {{ parent() }}
53 <style type="text/css">
54 .important { color: #336699; }
55 </style>
56 {% endblock %}
57 {% block content %}
58 <h1>Index</h1>
59 <p class="important">
60 Welcome on my awesome homepage.
61 </p>
62 {% endblock %}
63
64The ``extends`` tag is the key here. It tells the template engine that this
65template "extends" another template. When the template system evaluates this
66template, first it locates the parent. The extends tag should be the first tag
67in the template.
68
69Note that since the child template doesn't define the ``footer`` block, the
70value from the parent template is used instead.
71
72You can't define multiple ``block`` tags with the same name in the same
73template. This limitation exists because a block tag works in "both"
74directions. That is, a block tag doesn't just provide a hole to fill - it also
75defines the content that fills the hole in the *parent*. If there were two
76similarly-named ``block`` tags in a template, that template's parent wouldn't
77know which one of the blocks' content to use.
78
79If you want to print a block multiple times you can however use the
80``block`` function:
81
82.. code-block:: jinja
83
84 <title>{% block title %}{% endblock %}</title>
85 <h1>{{ block('title') }}</h1>
86 {% block body %}{% endblock %}
87
88Parent Blocks
89-------------
90
91It's possible to render the contents of the parent block by using the
92:doc:`parent<../functions/parent>` function. This gives back the results of
93the parent block:
94
95.. code-block:: jinja
96
97 {% block sidebar %}
98 <h3>Table Of Contents</h3>
99 ...
100 {{ parent() }}
101 {% endblock %}
102
103Named Block End-Tags
104--------------------
105
106Twig allows you to put the name of the block after the end tag for better
107readability:
108
109.. code-block:: jinja
110
111 {% block sidebar %}
112 {% block inner_sidebar %}
113 ...
114 {% endblock inner_sidebar %}
115 {% endblock sidebar %}
116
117Of course, the name after the ``endblock`` word must match the block name.
118
119Block Nesting and Scope
120-----------------------
121
122Blocks can be nested for more complex layouts. Per default, blocks have access
123to variables from outer scopes:
124
125.. code-block:: jinja
126
127 {% for item in seq %}
128 <li>{% block loop_item %}{{ item }}{% endblock %}</li>
129 {% endfor %}
130
131Block Shortcuts
132---------------
133
134For blocks with few content, it's possible to use a shortcut syntax. The
135following constructs do the same:
136
137.. code-block:: jinja
138
139 {% block title %}
140 {{ page_title|title }}
141 {% endblock %}
142
143.. code-block:: jinja
144
145 {% block title page_title|title %}
146
147Dynamic Inheritance
148-------------------
149
150Twig supports dynamic inheritance by using a variable as the base template:
151
152.. code-block:: jinja
153
154 {% extends some_var %}
155
156If the variable evaluates to a ``Twig_Template`` object, Twig will use it as
157the parent template::
158
159 // {% extends layout %}
160
161 $layout = $twig->loadTemplate('some_layout_template.twig');
162
163 $twig->display('template.twig', array('layout' => $layout));
164
165.. versionadded:: 1.2
166 The possibility to pass an array of templates has been added in Twig 1.2.
167
168You can also provide a list of templates that are checked for existence. The
169first template that exists will be used as a parent:
170
171.. code-block:: jinja
172
173 {% extends ['layout.html', 'base_layout.html'] %}
174
175Conditional Inheritance
176-----------------------
177
178As the template name for the parent can be any valid Twig expression, it's
179possible to make the inheritance mechanism conditional:
180
181.. code-block:: jinja
182
183 {% extends standalone ? "minimum.html" : "base.html" %}
184
185In this example, the template will extend the "minimum.html" layout template
186if the ``standalone`` variable evaluates to ``true``, and "base.html"
187otherwise.
188
189How blocks work?
190----------------
191
192A block provides a way to change how a certain part of a template is rendered
193but it does not interfere in any way with the logic around it.
194
195Let's take the following example to illustrate how a block work and more
196importantly, how it does not work:
197
198.. code-block:: jinja
199
200 {# base.twig #}
201
202 {% for post in posts %}
203 {% block post %}
204 <h1>{{ post.title }}</h1>
205 <p>{{ post.body }}</p>
206 {% endblock %}
207 {% endfor %}
208
209If you render this template, the result would be exactly the same with or
210without the ``block`` tag. The ``block`` inside the ``for`` loop is just a way
211to make it overridable by a child template:
212
213.. code-block:: jinja
214
215 {# child.twig #}
216
217 {% extends "base.twig" %}
218
219 {% block post %}
220 <article>
221 <header>{{ post.title }}</header>
222 <section>{{ post.text }}</section>
223 </article>
224 {% endblock %}
225
226Now, when rendering the child template, the loop is going to use the block
227defined in the child template instead of the one defined in the base one; the
228executed template is then equivalent to the following one:
229
230.. code-block:: jinja
231
232 {% for post in posts %}
233 <article>
234 <header>{{ post.title }}</header>
235 <section>{{ post.text }}</section>
236 </article>
237 {% endfor %}
238
239Let's take another example: a block included within an ``if`` statement:
240
241.. code-block:: jinja
242
243 {% if posts is empty %}
244 {% block head %}
245 {{ parent() }}
246
247 <meta name="robots" content="noindex, follow">
248 {% endblock head %}
249 {% endif %}
250
251Contrary to what you might think, this template does not define a block
252conditionally; it just makes overridable by a child template the output of
253what will be rendered when the condition is ``true``.
254
255If you want the output to be displayed conditionally, use the following
256instead:
257
258.. code-block:: jinja
259
260 {% block head %}
261 {{ parent() }}
262
263 {% if posts is empty %}
264 <meta name="robots" content="noindex, follow">
265 {% endif %}
266 {% endblock head %}
267
268.. seealso:: :doc:`block<../functions/block>`, :doc:`block<../tags/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>`
diff --git a/vendor/twig/twig/doc/tags/filter.rst b/vendor/twig/twig/doc/tags/filter.rst
new file mode 100644
index 00000000..82ca5c62
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/filter.rst
@@ -0,0 +1,21 @@
1``filter``
2==========
3
4Filter sections allow you to apply regular Twig filters on a block of template
5data. Just wrap the code in the special ``filter`` section:
6
7.. code-block:: jinja
8
9 {% filter upper %}
10 This text becomes uppercase
11 {% endfilter %}
12
13You can also chain filters:
14
15.. code-block:: jinja
16
17 {% filter lower|escape %}
18 <strong>SOME TEXT</strong>
19 {% endfilter %}
20
21 {# outputs "&lt;strong&gt;some text&lt;/strong&gt;" #}
diff --git a/vendor/twig/twig/doc/tags/flush.rst b/vendor/twig/twig/doc/tags/flush.rst
new file mode 100644
index 00000000..55ef593a
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/flush.rst
@@ -0,0 +1,17 @@
1``flush``
2=========
3
4.. versionadded:: 1.5
5 The flush tag was added in Twig 1.5.
6
7The ``flush`` tag tells Twig to flush the output buffer:
8
9.. code-block:: jinja
10
11 {% flush %}
12
13.. note::
14
15 Internally, Twig uses the PHP `flush`_ function.
16
17.. _`flush`: http://php.net/flush
diff --git a/vendor/twig/twig/doc/tags/for.rst b/vendor/twig/twig/doc/tags/for.rst
new file mode 100644
index 00000000..0673b551
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/for.rst
@@ -0,0 +1,172 @@
1``for``
2=======
3
4Loop over each item in a sequence. For example, to display a list of users
5provided in a variable called ``users``:
6
7.. code-block:: jinja
8
9 <h1>Members</h1>
10 <ul>
11 {% for user in users %}
12 <li>{{ user.username|e }}</li>
13 {% endfor %}
14 </ul>
15
16.. note::
17
18 A sequence can be either an array or an object implementing the
19 ``Traversable`` interface.
20
21If you do need to iterate over a sequence of numbers, you can use the ``..``
22operator:
23
24.. code-block:: jinja
25
26 {% for i in 0..10 %}
27 * {{ i }}
28 {% endfor %}
29
30The above snippet of code would print all numbers from 0 to 10.
31
32It can be also useful with letters:
33
34.. code-block:: jinja
35
36 {% for letter in 'a'..'z' %}
37 * {{ letter }}
38 {% endfor %}
39
40The ``..`` operator can take any expression at both sides:
41
42.. code-block:: jinja
43
44 {% for letter in 'a'|upper..'z'|upper %}
45 * {{ letter }}
46 {% endfor %}
47
48.. tip:
49
50 If you need a step different from 1, you can use the ``range`` function
51 instead.
52
53The `loop` variable
54-------------------
55
56Inside of a ``for`` loop block you can access some special variables:
57
58===================== =============================================================
59Variable Description
60===================== =============================================================
61``loop.index`` The current iteration of the loop. (1 indexed)
62``loop.index0`` The current iteration of the loop. (0 indexed)
63``loop.revindex`` The number of iterations from the end of the loop (1 indexed)
64``loop.revindex0`` The number of iterations from the end of the loop (0 indexed)
65``loop.first`` True if first iteration
66``loop.last`` True if last iteration
67``loop.length`` The number of items in the sequence
68``loop.parent`` The parent context
69===================== =============================================================
70
71.. code-block:: jinja
72
73 {% for user in users %}
74 {{ loop.index }} - {{ user.username }}
75 {% endfor %}
76
77.. note::
78
79 The ``loop.length``, ``loop.revindex``, ``loop.revindex0``, and
80 ``loop.last`` variables are only available for PHP arrays, or objects that
81 implement the ``Countable`` interface. They are also not available when
82 looping with a condition.
83
84.. versionadded:: 1.2
85 The ``if`` modifier support has been added in Twig 1.2.
86
87Adding a condition
88------------------
89
90Unlike in PHP, it's not possible to ``break`` or ``continue`` in a loop. You
91can however filter the sequence during iteration which allows you to skip
92items. The following example skips all the users which are not active:
93
94.. code-block:: jinja
95
96 <ul>
97 {% for user in users if user.active %}
98 <li>{{ user.username|e }}</li>
99 {% endfor %}
100 </ul>
101
102The advantage is that the special loop variable will count correctly thus not
103counting the users not iterated over. Keep in mind that properties like
104``loop.last`` will not be defined when using loop conditions.
105
106.. note::
107
108 Using the ``loop`` variable within the condition is not recommended as it
109 will probably not be doing what you expect it to. For instance, adding a
110 condition like ``loop.index > 4`` won't work as the index is only
111 incremented when the condition is true (so the condition will never
112 match).
113
114The `else` Clause
115-----------------
116
117If no iteration took place because the sequence was empty, you can render a
118replacement block by using ``else``:
119
120.. code-block:: jinja
121
122 <ul>
123 {% for user in users %}
124 <li>{{ user.username|e }}</li>
125 {% else %}
126 <li><em>no user found</em></li>
127 {% endfor %}
128 </ul>
129
130Iterating over Keys
131-------------------
132
133By default, a loop iterates over the values of the sequence. You can iterate
134on keys by using the ``keys`` filter:
135
136.. code-block:: jinja
137
138 <h1>Members</h1>
139 <ul>
140 {% for key in users|keys %}
141 <li>{{ key }}</li>
142 {% endfor %}
143 </ul>
144
145Iterating over Keys and Values
146------------------------------
147
148You can also access both keys and values:
149
150.. code-block:: jinja
151
152 <h1>Members</h1>
153 <ul>
154 {% for key, user in users %}
155 <li>{{ key }}: {{ user.username|e }}</li>
156 {% endfor %}
157 </ul>
158
159Iterating over a Subset
160-----------------------
161
162You might want to iterate over a subset of values. This can be achieved using
163the :doc:`slice <../filters/slice>` filter:
164
165.. code-block:: jinja
166
167 <h1>Top Ten Members</h1>
168 <ul>
169 {% for user in users|slice(0, 10) %}
170 <li>{{ user.username|e }}</li>
171 {% endfor %}
172 </ul>
diff --git a/vendor/twig/twig/doc/tags/from.rst b/vendor/twig/twig/doc/tags/from.rst
new file mode 100644
index 00000000..5337a235
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/from.rst
@@ -0,0 +1,8 @@
1``from``
2========
3
4The ``from`` tags import :doc:`macro<../tags/macro>` names into the current
5namespace. The tag is documented in detail in the documentation for the
6:doc:`import<../tags/import>` tag.
7
8.. seealso:: :doc:`macro<../tags/macro>`, :doc:`import<../tags/import>`
diff --git a/vendor/twig/twig/doc/tags/if.rst b/vendor/twig/twig/doc/tags/if.rst
new file mode 100644
index 00000000..d7a1451c
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/if.rst
@@ -0,0 +1,43 @@
1``if``
2======
3
4The ``if`` statement in Twig is comparable with the if statements of PHP.
5
6In the simplest form you can use it to test if an expression evaluates to
7``true``:
8
9.. code-block:: jinja
10
11 {% if online == false %}
12 <p>Our website is in maintenance mode. Please, come back later.</p>
13 {% endif %}
14
15You can also test if an array is not empty:
16
17.. code-block:: jinja
18
19 {% if users %}
20 <ul>
21 {% for user in users %}
22 <li>{{ user.username|e }}</li>
23 {% endfor %}
24 </ul>
25 {% endif %}
26
27.. note::
28
29 If you want to test if the variable is defined, use ``if users is
30 defined`` instead.
31
32For multiple branches ``elseif`` and ``else`` can be used like in PHP. You can use
33more complex ``expressions`` there too:
34
35.. code-block:: jinja
36
37 {% if kenny.sick %}
38 Kenny is sick.
39 {% elseif kenny.dead %}
40 You killed Kenny! You bastard!!!
41 {% else %}
42 Kenny looks okay --- so far
43 {% endif %}
diff --git a/vendor/twig/twig/doc/tags/import.rst b/vendor/twig/twig/doc/tags/import.rst
new file mode 100644
index 00000000..f6bf718e
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/import.rst
@@ -0,0 +1,57 @@
1``import``
2==========
3
4Twig supports putting often used code into :doc:`macros<../tags/macro>`. These
5macros can go into different templates and get imported from there.
6
7There are two ways to import templates. You can import the complete template
8into a variable or request specific macros from it.
9
10Imagine we have a helper module that renders forms (called ``forms.html``):
11
12.. code-block:: jinja
13
14 {% macro input(name, value, type, size) %}
15 <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
16 {% endmacro %}
17
18 {% macro textarea(name, value, rows) %}
19 <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
20 {% endmacro %}
21
22The easiest and most flexible is importing the whole module into a variable.
23That way you can access the attributes:
24
25.. code-block:: jinja
26
27 {% import 'forms.html' as forms %}
28
29 <dl>
30 <dt>Username</dt>
31 <dd>{{ forms.input('username') }}</dd>
32 <dt>Password</dt>
33 <dd>{{ forms.input('password', null, 'password') }}</dd>
34 </dl>
35 <p>{{ forms.textarea('comment') }}</p>
36
37Alternatively you can import names from the template into the current
38namespace:
39
40.. code-block:: jinja
41
42 {% from 'forms.html' import input as input_field, textarea %}
43
44 <dl>
45 <dt>Username</dt>
46 <dd>{{ input_field('username') }}</dd>
47 <dt>Password</dt>
48 <dd>{{ input_field('password', '', 'password') }}</dd>
49 </dl>
50 <p>{{ textarea('comment') }}</p>
51
52.. tip::
53
54 To import macros from the current file, use the special ``_self`` variable
55 for the source.
56
57.. seealso:: :doc:`macro<../tags/macro>`, :doc:`from<../tags/from>`
diff --git a/vendor/twig/twig/doc/tags/include.rst b/vendor/twig/twig/doc/tags/include.rst
new file mode 100644
index 00000000..10b262de
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/include.rst
@@ -0,0 +1,86 @@
1``include``
2===========
3
4The ``include`` statement includes a template and return the rendered content
5of that file into the current namespace:
6
7.. code-block:: jinja
8
9 {% include 'header.html' %}
10 Body
11 {% include 'footer.html' %}
12
13Included templates have access to the variables of the active context.
14
15If you are using the filesystem loader, the templates are looked for in the
16paths defined by it.
17
18You can add additional variables by passing them after the ``with`` keyword:
19
20.. code-block:: jinja
21
22 {# template.html will have access to the variables from the current context and the additional ones provided #}
23 {% include 'template.html' with {'foo': 'bar'} %}
24
25 {% set vars = {'foo': 'bar'} %}
26 {% include 'template.html' with vars %}
27
28You can disable access to the context by appending the ``only`` keyword:
29
30.. code-block:: jinja
31
32 {# only the foo variable will be accessible #}
33 {% include 'template.html' with {'foo': 'bar'} only %}
34
35.. code-block:: jinja
36
37 {# no variables will be accessible #}
38 {% include 'template.html' only %}
39
40.. tip::
41
42 When including a template created by an end user, you should consider
43 sandboxing it. More information in the :doc:`Twig for Developers<../api>`
44 chapter and in the :doc:`sandbox<../tags/sandbox>` tag documentation.
45
46The template name can be any valid Twig expression:
47
48.. code-block:: jinja
49
50 {% include some_var %}
51 {% include ajax ? 'ajax.html' : 'not_ajax.html' %}
52
53And if the expression evaluates to a ``Twig_Template`` object, Twig will use it
54directly::
55
56 // {% include template %}
57
58 $template = $twig->loadTemplate('some_template.twig');
59
60 $twig->loadTemplate('template.twig')->display(array('template' => $template));
61
62.. versionadded:: 1.2
63 The ``ignore missing`` feature has been added in Twig 1.2.
64
65You can mark an include with ``ignore missing`` in which case Twig will ignore
66the statement if the template to be included does not exist. It has to be
67placed just after the template name. Here some valid examples:
68
69.. code-block:: jinja
70
71 {% include 'sidebar.html' ignore missing %}
72 {% include 'sidebar.html' ignore missing with {'foo': 'bar'} %}
73 {% include 'sidebar.html' ignore missing only %}
74
75.. versionadded:: 1.2
76 The possibility to pass an array of templates has been added in Twig 1.2.
77
78You can also provide a list of templates that are checked for existence before
79inclusion. The first template that exists will be included:
80
81.. code-block:: jinja
82
83 {% include ['page_detailed.html', 'page.html'] %}
84
85If ``ignore missing`` is given, it will fall back to rendering nothing if none
86of the templates exist, otherwise it will throw an exception.
diff --git a/vendor/twig/twig/doc/tags/index.rst b/vendor/twig/twig/doc/tags/index.rst
new file mode 100644
index 00000000..64e88644
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/index.rst
@@ -0,0 +1,24 @@
1Tags
2====
3
4.. toctree::
5 :maxdepth: 1
6
7 autoescape
8 block
9 filter
10 do
11 embed
12 extends
13 flush
14 for
15 from
16 if
17 import
18 include
19 macro
20 sandbox
21 set
22 spaceless
23 use
24 verbatim
diff --git a/vendor/twig/twig/doc/tags/macro.rst b/vendor/twig/twig/doc/tags/macro.rst
new file mode 100644
index 00000000..11c115a0
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/macro.rst
@@ -0,0 +1,83 @@
1``macro``
2=========
3
4Macros are comparable with functions in regular programming languages. They
5are useful to put often used HTML idioms into reusable elements to not repeat
6yourself.
7
8Here is a small example of a macro that renders a form element:
9
10.. code-block:: jinja
11
12 {% macro input(name, value, type, size) %}
13 <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
14 {% endmacro %}
15
16Macros differs from native PHP functions in a few ways:
17
18* Default argument values are defined by using the ``default`` filter in the
19 macro body;
20
21* Arguments of a macro are always optional.
22
23But as with PHP functions, macros don't have access to the current template
24variables.
25
26.. tip::
27
28 You can pass the whole context as an argument by using the special
29 ``_context`` variable.
30
31Macros can be defined in any template, and need to be "imported" before being
32used (see the documentation for the :doc:`import<../tags/import>` tag for more
33information):
34
35.. code-block:: jinja
36
37 {% import "forms.html" as forms %}
38
39The above ``import`` call imports the "forms.html" file (which can contain only
40macros, or a template and some macros), and import the functions as items of
41the ``forms`` variable.
42
43The macro can then be called at will:
44
45.. code-block:: jinja
46
47 <p>{{ forms.input('username') }}</p>
48 <p>{{ forms.input('password', null, 'password') }}</p>
49
50If macros are defined and used in the same template, you can use the
51special ``_self`` variable to import them:
52
53.. code-block:: jinja
54
55 {% import _self as forms %}
56
57 <p>{{ forms.input('username') }}</p>
58
59.. warning::
60
61 When you define a macro in the template where you are going to use it, you
62 might be tempted to call the macro directly via ``_self.input()`` instead
63 of importing it; even if seems to work, this is just a side-effect of the
64 current implementation and it won't work anymore in Twig 2.x.
65
66When you want to use a macro in another macro from the same file, you need to
67import it locally:
68
69.. code-block:: jinja
70
71 {% macro input(name, value, type, size) %}
72 <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
73 {% endmacro %}
74
75 {% macro wrapped_input(name, value, type, size) %}
76 {% import _self as forms %}
77
78 <div class="field">
79 {{ forms.input(name, value, type, size) }}
80 </div>
81 {% endmacro %}
82
83.. seealso:: :doc:`from<../tags/from>`, :doc:`import<../tags/import>`
diff --git a/vendor/twig/twig/doc/tags/sandbox.rst b/vendor/twig/twig/doc/tags/sandbox.rst
new file mode 100644
index 00000000..e186726c
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/sandbox.rst
@@ -0,0 +1,30 @@
1``sandbox``
2===========
3
4The ``sandbox`` tag can be used to enable the sandboxing mode for an included
5template, when sandboxing is not enabled globally for the Twig environment:
6
7.. code-block:: jinja
8
9 {% sandbox %}
10 {% include 'user.html' %}
11 {% endsandbox %}
12
13.. warning::
14
15 The ``sandbox`` tag is only available when the sandbox extension is
16 enabled (see the :doc:`Twig for Developers<../api>` chapter).
17
18.. note::
19
20 The ``sandbox`` tag can only be used to sandbox an include tag and it
21 cannot be used to sandbox a section of a template. The following example
22 won't work:
23
24 .. code-block:: jinja
25
26 {% sandbox %}
27 {% for i in 1..2 %}
28 {{ i }}
29 {% endfor %}
30 {% endsandbox %}
diff --git a/vendor/twig/twig/doc/tags/set.rst b/vendor/twig/twig/doc/tags/set.rst
new file mode 100644
index 00000000..3eba239a
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/set.rst
@@ -0,0 +1,78 @@
1``set``
2=======
3
4Inside code blocks you can also assign values to variables. Assignments use
5the ``set`` tag and can have multiple targets.
6
7Here is how you can assign the ``bar`` value to the ``foo`` variable:
8
9.. code-block:: jinja
10
11 {% set foo = 'bar' %}
12
13After the ``set`` call, the ``foo`` variable is available in the template like
14any other ones:
15
16.. code-block:: jinja
17
18 {# displays bar #}
19 {{ foo }}
20
21The assigned value can be any valid :ref:`Twig expressions
22<twig-expressions>`:
23
24.. code-block:: jinja
25
26 {% set foo = [1, 2] %}
27 {% set foo = {'foo': 'bar'} %}
28 {% set foo = 'foo' ~ 'bar' %}
29
30Several variables can be assigned in one block:
31
32.. code-block:: jinja
33
34 {% set foo, bar = 'foo', 'bar' %}
35
36 {# is equivalent to #}
37
38 {% set foo = 'foo' %}
39 {% set bar = 'bar' %}
40
41The ``set`` tag can also be used to 'capture' chunks of text:
42
43.. code-block:: jinja
44
45 {% set foo %}
46 <div id="pagination">
47 ...
48 </div>
49 {% endset %}
50
51.. caution::
52
53 If you enable automatic output escaping, Twig will only consider the
54 content to be safe when capturing chunks of text.
55
56.. note::
57
58 Note that loops are scoped in Twig; therefore a variable declared inside a
59 ``for`` loop is not accessible outside the loop itself:
60
61 .. code-block:: jinja
62
63 {% for item in list %}
64 {% set foo = item %}
65 {% endfor %}
66
67 {# foo is NOT available #}
68
69 If you want to access the variable, just declare it before the loop:
70
71 .. code-block:: jinja
72
73 {% set foo = "" %}
74 {% for item in list %}
75 {% set foo = item %}
76 {% endfor %}
77
78 {# foo is available #}
diff --git a/vendor/twig/twig/doc/tags/spaceless.rst b/vendor/twig/twig/doc/tags/spaceless.rst
new file mode 100644
index 00000000..12e77b25
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/spaceless.rst
@@ -0,0 +1,37 @@
1``spaceless``
2=============
3
4Use the ``spaceless`` tag to remove whitespace *between HTML tags*, not
5whitespace within HTML tags or whitespace in plain text:
6
7.. code-block:: jinja
8
9 {% spaceless %}
10 <div>
11 <strong>foo</strong>
12 </div>
13 {% endspaceless %}
14
15 {# output will be <div><strong>foo</strong></div> #}
16
17This tag is not meant to "optimize" the size of the generated HTML content but
18merely to avoid extra whitespace between HTML tags to avoid browser rendering
19quirks under some circumstances.
20
21.. tip::
22
23 If you want to optimize the size of the generated HTML content, gzip
24 compress the output instead.
25
26.. tip::
27
28 If you want to create a tag that actually removes all extra whitespace in
29 an HTML string, be warned that this is not as easy as it seems to be
30 (think of ``textarea`` or ``pre`` tags for instance). Using a third-party
31 library like Tidy is probably a better idea.
32
33.. tip::
34
35 For more information on whitespace control, read the
36 :doc:`dedicated<../templates>` section of the documentation and learn how
37 you can also use the whitespace control modifier on your tags.
diff --git a/vendor/twig/twig/doc/tags/use.rst b/vendor/twig/twig/doc/tags/use.rst
new file mode 100644
index 00000000..085f9161
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/use.rst
@@ -0,0 +1,123 @@
1``use``
2=======
3
4.. versionadded:: 1.1
5 Horizontal reuse was added in Twig 1.1.
6
7.. note::
8
9 Horizontal reuse is an advanced Twig feature that is hardly ever needed in
10 regular templates. It is mainly used by projects that need to make
11 template blocks reusable without using inheritance.
12
13Template inheritance is one of the most powerful Twig's feature but it is
14limited to single inheritance; a template can only extend one other template.
15This limitation makes template inheritance simple to understand and easy to
16debug:
17
18.. code-block:: jinja
19
20 {% extends "base.html" %}
21
22 {% block title %}{% endblock %}
23 {% block content %}{% endblock %}
24
25Horizontal reuse is a way to achieve the same goal as multiple inheritance,
26but without the associated complexity:
27
28.. code-block:: jinja
29
30 {% extends "base.html" %}
31
32 {% use "blocks.html" %}
33
34 {% block title %}{% endblock %}
35 {% block content %}{% endblock %}
36
37The ``use`` statement tells Twig to import the blocks defined in
38```blocks.html`` into the current template (it's like macros, but for blocks):
39
40.. code-block:: jinja
41
42 # blocks.html
43 {% block sidebar %}{% endblock %}
44
45In this example, the ``use`` statement imports the ``sidebar`` block into the
46main template. The code is mostly equivalent to the following one (the
47imported blocks are not outputted automatically):
48
49.. code-block:: jinja
50
51 {% extends "base.html" %}
52
53 {% block sidebar %}{% endblock %}
54 {% block title %}{% endblock %}
55 {% block content %}{% endblock %}
56
57.. note::
58
59 The ``use`` tag only imports a template if it does not extend another
60 template, if it does not define macros, and if the body is empty. But it
61 can *use* other templates.
62
63.. note::
64
65 Because ``use`` statements are resolved independently of the context
66 passed to the template, the template reference cannot be an expression.
67
68The main template can also override any imported block. If the template
69already defines the ``sidebar`` block, then the one defined in ``blocks.html``
70is ignored. To avoid name conflicts, you can rename imported blocks:
71
72.. code-block:: jinja
73
74 {% extends "base.html" %}
75
76 {% use "blocks.html" with sidebar as base_sidebar %}
77
78 {% block sidebar %}{% endblock %}
79 {% block title %}{% endblock %}
80 {% block content %}{% endblock %}
81
82.. versionadded:: 1.3
83 The ``parent()`` support was added in Twig 1.3.
84
85The ``parent()`` function automatically determines the correct inheritance
86tree, so it can be used when overriding a block defined in an imported
87template:
88
89.. code-block:: jinja
90
91 {% extends "base.html" %}
92
93 {% use "blocks.html" %}
94
95 {% block sidebar %}
96 {{ parent() }}
97 {% endblock %}
98
99 {% block title %}{% endblock %}
100 {% block content %}{% endblock %}
101
102In this example, ``parent()`` will correctly call the ``sidebar`` block from
103the ``blocks.html`` template.
104
105.. tip::
106
107 In Twig 1.2, renaming allows you to simulate inheritance by calling the
108 "parent" block:
109
110 .. code-block:: jinja
111
112 {% extends "base.html" %}
113
114 {% use "blocks.html" with sidebar as parent_sidebar %}
115
116 {% block sidebar %}
117 {{ block('parent_sidebar') }}
118 {% endblock %}
119
120.. note::
121
122 You can use as many ``use`` statements as you want in any given template.
123 If two imported templates define the same block, the latest one wins.
diff --git a/vendor/twig/twig/doc/tags/verbatim.rst b/vendor/twig/twig/doc/tags/verbatim.rst
new file mode 100644
index 00000000..fe61ca1b
--- /dev/null
+++ b/vendor/twig/twig/doc/tags/verbatim.rst
@@ -0,0 +1,24 @@
1``verbatim``
2============
3
4.. versionadded:: 1.12
5 The ``verbatim`` tag was added in Twig 1.12 (it was named ``raw`` before).
6
7The ``verbatim`` tag marks sections as being raw text that should not be
8parsed. For example to put Twig syntax as example into a template you can use
9this snippet:
10
11.. code-block:: jinja
12
13 {% verbatim %}
14 <ul>
15 {% for item in seq %}
16 <li>{{ item }}</li>
17 {% endfor %}
18 </ul>
19 {% endverbatim %}
20
21.. note::
22
23 The ``verbatim`` tag works in the exact same way as the old ``raw`` tag,
24 but was renamed to avoid confusion with the ``raw`` filter. \ No newline at end of file
diff --git a/vendor/twig/twig/doc/templates.rst b/vendor/twig/twig/doc/templates.rst
new file mode 100644
index 00000000..542b8aef
--- /dev/null
+++ b/vendor/twig/twig/doc/templates.rst
@@ -0,0 +1,851 @@
1Twig for Template Designers
2===========================
3
4This document describes the syntax and semantics of the template engine and
5will be most useful as reference to those creating Twig templates.
6
7Synopsis
8--------
9
10A template is simply a text file. It can generate any text-based format (HTML,
11XML, CSV, LaTeX, etc.). It doesn't have a specific extension, ``.html`` or
12``.xml`` are just fine.
13
14A template contains **variables** or **expressions**, which get replaced with
15values when the template is evaluated, and **tags**, which control the logic
16of the template.
17
18Below is a minimal template that illustrates a few basics. We will cover the
19details later on:
20
21.. code-block:: html+jinja
22
23 <!DOCTYPE html>
24 <html>
25 <head>
26 <title>My Webpage</title>
27 </head>
28 <body>
29 <ul id="navigation">
30 {% for item in navigation %}
31 <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
32 {% endfor %}
33 </ul>
34
35 <h1>My Webpage</h1>
36 {{ a_variable }}
37 </body>
38 </html>
39
40There are two kinds of delimiters: ``{% ... %}`` and ``{{ ... }}``. The first
41one is used to execute statements such as for-loops, the latter prints the
42result of an expression to the template.
43
44IDEs Integration
45----------------
46
47Many IDEs support syntax highlighting and auto-completion for Twig:
48
49* *Textmate* via the `Twig bundle`_
50* *Vim* via the `Jinja syntax plugin`_
51* *Netbeans* via the `Twig syntax plugin`_ (until 7.1, native as of 7.2)
52* *PhpStorm* (native as of 2.1)
53* *Eclipse* via the `Twig plugin`_
54* *Sublime Text* via the `Twig bundle`_
55* *GtkSourceView* via the `Twig language definition`_ (used by gedit and other projects)
56* *Coda* and *SubEthaEdit* via the `Twig syntax mode`_
57* *Coda 2* via the `other Twig syntax mode`_
58* *Komodo* and *Komodo Edit* via the Twig highlight/syntax check mode
59* *Notepad++* via the `Notepad++ Twig Highlighter`_
60* *Emacs* via `web-mode.el`_
61
62Variables
63---------
64
65The application passes variables to the templates you can mess around in the
66template. Variables may have attributes or elements on them you can access
67too. How a variable looks like heavily depends on the application providing
68those.
69
70You can use a dot (``.``) to access attributes of a variable (methods or
71properties of a PHP object, or items of a PHP array), or the so-called
72"subscript" syntax (``[]``):
73
74.. code-block:: jinja
75
76 {{ foo.bar }}
77 {{ foo['bar'] }}
78
79When the attribute contains special characters (like ``-`` that would be
80interpreted as the minus operator), use the ``attribute`` function instead to
81access the variable attribute:
82
83.. code-block:: jinja
84
85 {# equivalent to the non-working foo.data-foo #}
86 {{ attribute(foo, 'data-foo') }}
87
88.. note::
89
90 It's important to know that the curly braces are *not* part of the
91 variable but the print statement. If you access variables inside tags
92 don't put the braces around.
93
94If a variable or attribute does not exist, you will get back a ``null`` value
95when the ``strict_variables`` option is set to ``false``, otherwise Twig will
96throw an error (see :ref:`environment options<environment_options>`).
97
98.. sidebar:: Implementation
99
100 For convenience sake ``foo.bar`` does the following things on the PHP
101 layer:
102
103 * check if ``foo`` is an array and ``bar`` a valid element;
104 * if not, and if ``foo`` is an object, check that ``bar`` is a valid property;
105 * if not, and if ``foo`` is an object, check that ``bar`` is a valid method
106 (even if ``bar`` is the constructor - use ``__construct()`` instead);
107 * if not, and if ``foo`` is an object, check that ``getBar`` is a valid method;
108 * if not, and if ``foo`` is an object, check that ``isBar`` is a valid method;
109 * if not, return a ``null`` value.
110
111 ``foo['bar']`` on the other hand only works with PHP arrays:
112
113 * check if ``foo`` is an array and ``bar`` a valid element;
114 * if not, return a ``null`` value.
115
116.. note::
117
118 If you want to get a dynamic attribute on a variable, use the
119 :doc:`attribute<functions/attribute>` function instead.
120
121Global Variables
122~~~~~~~~~~~~~~~~
123
124The following variables are always available in templates:
125
126* ``_self``: references the current template;
127* ``_context``: references the current context;
128* ``_charset``: references the current charset.
129
130Setting Variables
131~~~~~~~~~~~~~~~~~
132
133You can assign values to variables inside code blocks. Assignments use the
134:doc:`set<tags/set>` tag:
135
136.. code-block:: jinja
137
138 {% set foo = 'foo' %}
139 {% set foo = [1, 2] %}
140 {% set foo = {'foo': 'bar'} %}
141
142Filters
143-------
144
145Variables can be modified by **filters**. Filters are separated from the
146variable by a pipe symbol (``|``) and may have optional arguments in
147parentheses. Multiple filters can be chained. The output of one filter is
148applied to the next.
149
150The following example removes all HTML tags from the ``name`` and title-cases
151it:
152
153.. code-block:: jinja
154
155 {{ name|striptags|title }}
156
157Filters that accept arguments have parentheses around the arguments. This
158example will join a list by commas:
159
160.. code-block:: jinja
161
162 {{ list|join(', ') }}
163
164To apply a filter on a section of code, wrap it with the
165:doc:`filter<tags/filter>` tag:
166
167.. code-block:: jinja
168
169 {% filter upper %}
170 This text becomes uppercase
171 {% endfilter %}
172
173Go to the :doc:`filters<filters/index>` page to learn more about the built-in
174filters.
175
176Functions
177---------
178
179Functions can be called to generate content. Functions are called by their
180name followed by parentheses (``()``) and may have arguments.
181
182For instance, the ``range`` function returns a list containing an arithmetic
183progression of integers:
184
185.. code-block:: jinja
186
187 {% for i in range(0, 3) %}
188 {{ i }},
189 {% endfor %}
190
191Go to the :doc:`functions<functions/index>` page to learn more about the
192built-in functions.
193
194Named Arguments
195---------------
196
197.. versionadded:: 1.12
198 Support for named arguments was added in Twig 1.12.
199
200Arguments for filters and functions can also be passed as *named arguments*:
201
202.. code-block:: jinja
203
204 {% for i in range(low=1, high=10, step=2) %}
205 {{ i }},
206 {% endfor %}
207
208Using named arguments makes your templates more explicit about the meaning of
209the values you pass as arguments:
210
211.. code-block:: jinja
212
213 {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
214
215 {# versus #}
216
217 {{ data|convert_encoding(from='iso-2022-jp', to='UTF-8') }}
218
219Named arguments also allow you to skip some arguments for which you don't want
220to change the default value:
221
222.. code-block:: jinja
223
224 {# the first argument is the date format, which defaults to the global date format if null is passed #}
225 {{ "now"|date(null, "Europe/Paris") }}
226
227 {# or skip the format value by using a named argument for the timezone #}
228 {{ "now"|date(timezone="Europe/Paris") }}
229
230You can also use both positional and named arguments in one call, in which
231case positional arguments must always come before named arguments:
232
233.. code-block:: jinja
234
235 {{ "now"|date('d/m/Y H:i', timezone="Europe/Paris") }}
236
237.. tip::
238
239 Each function and filter documentation page has a section where the names
240 of all arguments are listed when supported.
241
242Control Structure
243-----------------
244
245A control structure refers to all those things that control the flow of a
246program - conditionals (i.e. ``if``/``elseif``/``else``), ``for``-loops, as
247well as things like blocks. Control structures appear inside ``{% ... %}``
248blocks.
249
250For example, to display a list of users provided in a variable called
251``users``, use the :doc:`for<tags/for>` tag:
252
253.. code-block:: jinja
254
255 <h1>Members</h1>
256 <ul>
257 {% for user in users %}
258 <li>{{ user.username|e }}</li>
259 {% endfor %}
260 </ul>
261
262The :doc:`if<tags/if>` tag can be used to test an expression:
263
264.. code-block:: jinja
265
266 {% if users|length > 0 %}
267 <ul>
268 {% for user in users %}
269 <li>{{ user.username|e }}</li>
270 {% endfor %}
271 </ul>
272 {% endif %}
273
274Go to the :doc:`tags<tags/index>` page to learn more about the built-in tags.
275
276Comments
277--------
278
279To comment-out part of a line in a template, use the comment syntax ``{# ...
280#}``. This is useful for debugging or to add information for other template
281designers or yourself:
282
283.. code-block:: jinja
284
285 {# note: disabled template because we no longer use this
286 {% for user in users %}
287 ...
288 {% endfor %}
289 #}
290
291Including other Templates
292-------------------------
293
294The :doc:`include<tags/include>` tag is useful to include a template and
295return the rendered content of that template into the current one:
296
297.. code-block:: jinja
298
299 {% include 'sidebar.html' %}
300
301Per default included templates are passed the current context.
302
303The context that is passed to the included template includes variables defined
304in the template:
305
306.. code-block:: jinja
307
308 {% for box in boxes %}
309 {% include "render_box.html" %}
310 {% endfor %}
311
312The included template ``render_box.html`` is able to access ``box``.
313
314The filename of the template depends on the template loader. For instance, the
315``Twig_Loader_Filesystem`` allows you to access other templates by giving the
316filename. You can access templates in subdirectories with a slash:
317
318.. code-block:: jinja
319
320 {% include "sections/articles/sidebar.html" %}
321
322This behavior depends on the application embedding Twig.
323
324Template Inheritance
325--------------------
326
327The most powerful part of Twig is template inheritance. Template inheritance
328allows you to build a base "skeleton" template that contains all the common
329elements of your site and defines **blocks** that child templates can
330override.
331
332Sounds complicated but is very basic. It's easier to understand it by
333starting with an example.
334
335Let's define a base template, ``base.html``, which defines a simple HTML
336skeleton document that you might use for a simple two-column page:
337
338.. code-block:: html+jinja
339
340 <!DOCTYPE html>
341 <html>
342 <head>
343 {% block head %}
344 <link rel="stylesheet" href="style.css" />
345 <title>{% block title %}{% endblock %} - My Webpage</title>
346 {% endblock %}
347 </head>
348 <body>
349 <div id="content">{% block content %}{% endblock %}</div>
350 <div id="footer">
351 {% block footer %}
352 &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
353 {% endblock %}
354 </div>
355 </body>
356 </html>
357
358In this example, the :doc:`block<tags/block>` tags define four blocks that
359child templates can fill in. All the ``block`` tag does is to tell the
360template engine that a child template may override those portions of the
361template.
362
363A child template might look like this:
364
365.. code-block:: jinja
366
367 {% extends "base.html" %}
368
369 {% block title %}Index{% endblock %}
370 {% block head %}
371 {{ parent() }}
372 <style type="text/css">
373 .important { color: #336699; }
374 </style>
375 {% endblock %}
376 {% block content %}
377 <h1>Index</h1>
378 <p class="important">
379 Welcome to my awesome homepage.
380 </p>
381 {% endblock %}
382
383The :doc:`extends<tags/extends>` tag is the key here. It tells the template
384engine that this template "extends" another template. When the template system
385evaluates this template, first it locates the parent. The extends tag should
386be the first tag in the template.
387
388Note that since the child template doesn't define the ``footer`` block, the
389value from the parent template is used instead.
390
391It's possible to render the contents of the parent block by using the
392:doc:`parent<functions/parent>` function. This gives back the results of the
393parent block:
394
395.. code-block:: jinja
396
397 {% block sidebar %}
398 <h3>Table Of Contents</h3>
399 ...
400 {{ parent() }}
401 {% endblock %}
402
403.. tip::
404
405 The documentation page for the :doc:`extends<tags/extends>` tag describes
406 more advanced features like block nesting, scope, dynamic inheritance, and
407 conditional inheritance.
408
409.. note::
410
411 Twig also supports multiple inheritance with the so called horizontal reuse
412 with the help of the :doc:`use<tags/use>` tag. This is an advanced feature
413 hardly ever needed in regular templates.
414
415HTML Escaping
416-------------
417
418When generating HTML from templates, there's always a risk that a variable
419will include characters that affect the resulting HTML. There are two
420approaches: manually escaping each variable or automatically escaping
421everything by default.
422
423Twig supports both, automatic escaping is enabled by default.
424
425.. note::
426
427 Automatic escaping is only supported if the *escaper* extension has been
428 enabled (which is the default).
429
430Working with Manual Escaping
431~~~~~~~~~~~~~~~~~~~~~~~~~~~~
432
433If manual escaping is enabled, it is **your** responsibility to escape
434variables if needed. What to escape? Any variable you don't trust.
435
436Escaping works by piping the variable through the
437:doc:`escape<filters/escape>` or ``e`` filter:
438
439.. code-block:: jinja
440
441 {{ user.username|e }}
442
443By default, the ``escape`` filter uses the ``html`` strategy, but depending on
444the escaping context, you might want to explicitly use any other available
445strategies:
446
447.. code-block:: jinja
448
449 {{ user.username|e('js') }}
450 {{ user.username|e('css') }}
451 {{ user.username|e('url') }}
452 {{ user.username|e('html_attr') }}
453
454Working with Automatic Escaping
455~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
456
457Whether automatic escaping is enabled or not, you can mark a section of a
458template to be escaped or not by using the :doc:`autoescape<tags/autoescape>`
459tag:
460
461.. code-block:: jinja
462
463 {% autoescape %}
464 Everything will be automatically escaped in this block (using the HTML strategy)
465 {% endautoescape %}
466
467By default, auto-escaping uses the ``html`` escaping strategy. If you output
468variables in other contexts, you need to explicitly escape them with the
469appropriate escaping strategy:
470
471.. code-block:: jinja
472
473 {% autoescape 'js' %}
474 Everything will be automatically escaped in this block (using the JS strategy)
475 {% endautoescape %}
476
477Escaping
478--------
479
480It is sometimes desirable or even necessary to have Twig ignore parts it would
481otherwise handle as variables or blocks. For example if the default syntax is
482used and you want to use ``{{`` as raw string in the template and not start a
483variable you have to use a trick.
484
485The easiest way is to output the variable delimiter (``{{``) by using a variable
486expression:
487
488.. code-block:: jinja
489
490 {{ '{{' }}
491
492For bigger sections it makes sense to mark a block
493:doc:`verbatim<tags/verbatim>`.
494
495Macros
496------
497
498.. versionadded:: 1.12
499 Support for default argument values was added in Twig 1.12.
500
501Macros are comparable with functions in regular programming languages. They
502are useful to reuse often used HTML fragments to not repeat yourself.
503
504A macro is defined via the :doc:`macro<tags/macro>` tag. Here is a small example
505(subsequently called ``forms.html``) of a macro that renders a form element:
506
507.. code-block:: jinja
508
509 {% macro input(name, value, type, size) %}
510 <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
511 {% endmacro %}
512
513Macros can be defined in any template, and need to be "imported" via the
514:doc:`import<tags/import>` tag before being used:
515
516.. code-block:: jinja
517
518 {% import "forms.html" as forms %}
519
520 <p>{{ forms.input('username') }}</p>
521
522Alternatively, you can import individual macro names from a template into the
523current namespace via the :doc:`from<tags/from>` tag and optionally alias them:
524
525.. code-block:: jinja
526
527 {% from 'forms.html' import input as input_field %}
528
529 <dl>
530 <dt>Username</dt>
531 <dd>{{ input_field('username') }}</dd>
532 <dt>Password</dt>
533 <dd>{{ input_field('password', '', 'password') }}</dd>
534 </dl>
535
536A default value can also be defined for macro arguments when not provided in a
537macro call:
538
539.. code-block:: jinja
540
541 {% macro input(name, value = "", type = "text", size = 20) %}
542 <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
543 {% endmacro %}
544
545.. _twig-expressions:
546
547Expressions
548-----------
549
550Twig allows expressions everywhere. These work very similar to regular PHP and
551even if you're not working with PHP you should feel comfortable with it.
552
553.. note::
554
555 The operator precedence is as follows, with the lowest-precedence
556 operators listed first: ``b-and``, ``b-xor``, ``b-or``, ``or``, ``and``,
557 ``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``, ``in``, ``..``, ``+``,
558 ``-``, ``~``, ``*``, ``/``, ``//``, ``%``, ``is``, ``**``, ``|``, ``[]``,
559 and ``.``:
560
561 .. code-block:: jinja
562
563 {% set greeting = 'Hello' %}
564 {% set name = 'Fabien' %}
565
566 {{ greeting ~ name|lower }} {# Hello fabien #}
567
568 {# use parenthesis to change precedence #}
569 {{ (greeting ~ name)|lower }} {# hello fabien #}
570
571Literals
572~~~~~~~~
573
574.. versionadded:: 1.5
575 Support for hash keys as names and expressions was added in Twig 1.5.
576
577The simplest form of expressions are literals. Literals are representations
578for PHP types such as strings, numbers, and arrays. The following literals
579exist:
580
581* ``"Hello World"``: Everything between two double or single quotes is a
582 string. They are useful whenever you need a string in the template (for
583 example as arguments to function calls, filters or just to extend or include
584 a template). A string can contain a delimiter if it is preceded by a
585 backslash (``\``) -- like in ``'It\'s good'``.
586
587* ``42`` / ``42.23``: Integers and floating point numbers are created by just
588 writing the number down. If a dot is present the number is a float,
589 otherwise an integer.
590
591* ``["foo", "bar"]``: Arrays are defined by a sequence of expressions
592 separated by a comma (``,``) and wrapped with squared brackets (``[]``).
593
594* ``{"foo": "bar"}``: Hashes are defined by a list of keys and values
595 separated by a comma (``,``) and wrapped with curly braces (``{}``):
596
597 .. code-block:: jinja
598
599 {# keys as string #}
600 { 'foo': 'foo', 'bar': 'bar' }
601
602 {# keys as names (equivalent to the previous hash) -- as of Twig 1.5 #}
603 { foo: 'foo', bar: 'bar' }
604
605 {# keys as integer #}
606 { 2: 'foo', 4: 'bar' }
607
608 {# keys as expressions (the expression must be enclosed into parentheses) -- as of Twig 1.5 #}
609 { (1 + 1): 'foo', (a ~ 'b'): 'bar' }
610
611* ``true`` / ``false``: ``true`` represents the true value, ``false``
612 represents the false value.
613
614* ``null``: ``null`` represents no specific value. This is the value returned
615 when a variable does not exist. ``none`` is an alias for ``null``.
616
617Arrays and hashes can be nested:
618
619.. code-block:: jinja
620
621 {% set foo = [1, {"foo": "bar"}] %}
622
623.. tip::
624
625 Using double-quoted or single-quoted strings has no impact on performance
626 but string interpolation is only supported in double-quoted strings.
627
628Math
629~~~~
630
631Twig allows you to calculate with values. This is rarely useful in templates
632but exists for completeness' sake. The following operators are supported:
633
634* ``+``: Adds two objects together (the operands are casted to numbers). ``{{
635 1 + 1 }}`` is ``2``.
636
637* ``-``: Subtracts the second number from the first one. ``{{ 3 - 2 }}`` is
638 ``1``.
639
640* ``/``: Divides two numbers. The returned value will be a floating point
641 number. ``{{ 1 / 2 }}`` is ``{{ 0.5 }}``.
642
643* ``%``: Calculates the remainder of an integer division. ``{{ 11 % 7 }}`` is
644 ``4``.
645
646* ``//``: Divides two numbers and returns the truncated integer result. ``{{
647 20 // 7 }}`` is ``2``.
648
649* ``*``: Multiplies the left operand with the right one. ``{{ 2 * 2 }}`` would
650 return ``4``.
651
652* ``**``: Raises the left operand to the power of the right operand. ``{{ 2 **
653 3 }}`` would return ``8``.
654
655Logic
656~~~~~
657
658You can combine multiple expressions with the following operators:
659
660* ``and``: Returns true if the left and the right operands are both true.
661
662* ``or``: Returns true if the left or the right operand is true.
663
664* ``not``: Negates a statement.
665
666* ``(expr)``: Groups an expression.
667
668.. note::
669
670 Twig also support bitwise operators (``b-and``, ``b-xor``, and ``b-or``).
671
672Comparisons
673~~~~~~~~~~~
674
675The following comparison operators are supported in any expression: ``==``,
676``!=``, ``<``, ``>``, ``>=``, and ``<=``.
677
678Containment Operator
679~~~~~~~~~~~~~~~~~~~~
680
681The ``in`` operator performs containment test.
682
683It returns ``true`` if the left operand is contained in the right:
684
685.. code-block:: jinja
686
687 {# returns true #}
688
689 {{ 1 in [1, 2, 3] }}
690
691 {{ 'cd' in 'abcde' }}
692
693.. tip::
694
695 You can use this filter to perform a containment test on strings, arrays,
696 or objects implementing the ``Traversable`` interface.
697
698To perform a negative test, use the ``not in`` operator:
699
700.. code-block:: jinja
701
702 {% if 1 not in [1, 2, 3] %}
703
704 {# is equivalent to #}
705 {% if not (1 in [1, 2, 3]) %}
706
707Test Operator
708~~~~~~~~~~~~~
709
710The ``is`` operator performs tests. Tests can be used to test a variable against
711a common expression. The right operand is name of the test:
712
713.. code-block:: jinja
714
715 {# find out if a variable is odd #}
716
717 {{ name is odd }}
718
719Tests can accept arguments too:
720
721.. code-block:: jinja
722
723 {% if loop.index is divisibleby(3) %}
724
725Tests can be negated by using the ``is not`` operator:
726
727.. code-block:: jinja
728
729 {% if loop.index is not divisibleby(3) %}
730
731 {# is equivalent to #}
732 {% if not (loop.index is divisibleby(3)) %}
733
734Go to the :doc:`tests<tests/index>` page to learn more about the built-in
735tests.
736
737Other Operators
738~~~~~~~~~~~~~~~
739
740.. versionadded:: 1.12.0
741 Support for the extended ternary operator was added in Twig 1.12.0.
742
743The following operators are very useful but don't fit into any of the other
744categories:
745
746* ``..``: Creates a sequence based on the operand before and after the
747 operator (this is just syntactic sugar for the :doc:`range<functions/range>`
748 function).
749
750* ``|``: Applies a filter.
751
752* ``~``: Converts all operands into strings and concatenates them. ``{{ "Hello
753 " ~ name ~ "!" }}`` would return (assuming ``name`` is ``'John'``) ``Hello
754 John!``.
755
756* ``.``, ``[]``: Gets an attribute of an object.
757
758* ``?:``: The ternary operator:
759
760 .. code-block:: jinja
761
762 {{ foo ? 'yes' : 'no' }}
763
764 {# as of Twig 1.12.0 #}
765 {{ foo ?: 'no' }} == {{ foo ? foo : 'no' }}
766 {{ foo ? 'yes' }} == {{ foo ? 'yes' : '' }}
767
768String Interpolation
769~~~~~~~~~~~~~~~~~~~~
770
771.. versionadded:: 1.5
772 String interpolation was added in Twig 1.5.
773
774String interpolation (`#{expression}`) allows any valid expression to appear
775within a *double-quoted string*. The result of evaluating that expression is
776inserted into the string:
777
778.. code-block:: jinja
779
780 {{ "foo #{bar} baz" }}
781 {{ "foo #{1 + 2} baz" }}
782
783Whitespace Control
784------------------
785
786.. versionadded:: 1.1
787 Tag level whitespace control was added in Twig 1.1.
788
789The first newline after a template tag is removed automatically (like in PHP.)
790Whitespace is not further modified by the template engine, so each whitespace
791(spaces, tabs, newlines etc.) is returned unchanged.
792
793Use the ``spaceless`` tag to remove whitespace *between HTML tags*:
794
795.. code-block:: jinja
796
797 {% spaceless %}
798 <div>
799 <strong>foo bar</strong>
800 </div>
801 {% endspaceless %}
802
803 {# output will be <div><strong>foo bar</strong></div> #}
804
805In addition to the spaceless tag you can also control whitespace on a per tag
806level. By using the whitespace control modifier on your tags, you can trim
807leading and or trailing whitespace:
808
809.. code-block:: jinja
810
811 {% set value = 'no spaces' %}
812 {#- No leading/trailing whitespace -#}
813 {%- if true -%}
814 {{- value -}}
815 {%- endif -%}
816
817 {# output 'no spaces' #}
818
819The above sample shows the default whitespace control modifier, and how you can
820use it to remove whitespace around tags. Trimming space will consume all whitespace
821for that side of the tag. It is possible to use whitespace trimming on one side
822of a tag:
823
824.. code-block:: jinja
825
826 {% set value = 'no spaces' %}
827 <li> {{- value }} </li>
828
829 {# outputs '<li>no spaces </li>' #}
830
831Extensions
832----------
833
834Twig can be easily extended.
835
836If you are looking for new tags, filters, or functions, have a look at the Twig official
837`extension repository`_.
838
839If you want to create your own, read the :ref:`Creating an
840Extension<creating_extensions>` chapter.
841
842.. _`Twig bundle`: https://github.com/Anomareh/PHP-Twig.tmbundle
843.. _`Jinja syntax plugin`: http://jinja.pocoo.org/2/documentation/integration
844.. _`Twig syntax plugin`: http://plugins.netbeans.org/plugin/37069/php-twig
845.. _`Twig plugin`: https://github.com/pulse00/Twig-Eclipse-Plugin
846.. _`Twig language definition`: https://github.com/gabrielcorpse/gedit-twig-template-language
847.. _`extension repository`: http://github.com/fabpot/Twig-extensions
848.. _`Twig syntax mode`: https://github.com/bobthecow/Twig-HTML.mode
849.. _`other Twig syntax mode`: https://github.com/muxx/Twig-HTML.mode
850.. _`Notepad++ Twig Highlighter`: https://github.com/Banane9/notepadplusplus-twig
851.. _`web-mode.el`: http://web-mode.org/
diff --git a/vendor/twig/twig/doc/tests/constant.rst b/vendor/twig/twig/doc/tests/constant.rst
new file mode 100644
index 00000000..8d0724a8
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/constant.rst
@@ -0,0 +1,22 @@
1``constant``
2============
3
4.. versionadded: 1.13.1
5 constant now accepts object instances as the second argument.
6
7``constant`` checks if a variable has the exact same value as a constant. You
8can use either global constants or class constants:
9
10.. code-block:: jinja
11
12 {% if post.status is constant('Post::PUBLISHED') %}
13 the status attribute is exactly the same as Post::PUBLISHED
14 {% endif %}
15
16You can test constants from object instances as well:
17
18.. code-block:: jinja
19
20 {% if post.status is constant('PUBLISHED', post) %}
21 the status attribute is exactly the same as Post::PUBLISHED
22 {% endif %}
diff --git a/vendor/twig/twig/doc/tests/defined.rst b/vendor/twig/twig/doc/tests/defined.rst
new file mode 100644
index 00000000..702ce725
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/defined.rst
@@ -0,0 +1,30 @@
1``defined``
2===========
3
4``defined`` checks if a variable is defined in the current context. This is very
5useful if you use the ``strict_variables`` option:
6
7.. code-block:: jinja
8
9 {# defined works with variable names #}
10 {% if foo is defined %}
11 ...
12 {% endif %}
13
14 {# and attributes on variables names #}
15 {% if foo.bar is defined %}
16 ...
17 {% endif %}
18
19 {% if foo['bar'] is defined %}
20 ...
21 {% endif %}
22
23When using the ``defined`` test on an expression that uses variables in some
24method calls, be sure that they are all defined first:
25
26.. code-block:: jinja
27
28 {% if var is defined and foo.method(var) is defined %}
29 ...
30 {% endif %}
diff --git a/vendor/twig/twig/doc/tests/divisibleby.rst b/vendor/twig/twig/doc/tests/divisibleby.rst
new file mode 100644
index 00000000..9b0b9644
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/divisibleby.rst
@@ -0,0 +1,10 @@
1``divisibleby``
2===============
3
4``divisibleby`` checks if a variable is divisible by a number:
5
6.. code-block:: jinja
7
8 {% if loop.index is divisibleby(3) %}
9 ...
10 {% endif %}
diff --git a/vendor/twig/twig/doc/tests/empty.rst b/vendor/twig/twig/doc/tests/empty.rst
new file mode 100644
index 00000000..e5b55999
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/empty.rst
@@ -0,0 +1,11 @@
1``empty``
2=========
3
4``empty`` checks if a variable is empty:
5
6.. code-block:: jinja
7
8 {# evaluates to true if the foo variable is null, false, an empty array, or the empty string #}
9 {% if foo is empty %}
10 ...
11 {% endif %}
diff --git a/vendor/twig/twig/doc/tests/even.rst b/vendor/twig/twig/doc/tests/even.rst
new file mode 100644
index 00000000..6ab5cc39
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/even.rst
@@ -0,0 +1,10 @@
1``even``
2========
3
4``even`` returns ``true`` if the given number is even:
5
6.. code-block:: jinja
7
8 {{ var is even }}
9
10.. seealso:: :doc:`odd<../tests/odd>`
diff --git a/vendor/twig/twig/doc/tests/index.rst b/vendor/twig/twig/doc/tests/index.rst
new file mode 100644
index 00000000..c63208ee
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/index.rst
@@ -0,0 +1,15 @@
1Tests
2=====
3
4.. toctree::
5 :maxdepth: 1
6
7 constant
8 defined
9 divisibleby
10 empty
11 even
12 iterable
13 null
14 odd
15 sameas
diff --git a/vendor/twig/twig/doc/tests/iterable.rst b/vendor/twig/twig/doc/tests/iterable.rst
new file mode 100644
index 00000000..89a172f7
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/iterable.rst
@@ -0,0 +1,19 @@
1``iterable``
2============
3
4.. versionadded:: 1.7
5 The iterable test was added in Twig 1.7.
6
7``iterable`` checks if a variable is an array or a traversable object:
8
9.. code-block:: jinja
10
11 {# evaluates to true if the foo variable is iterable #}
12 {% if users is iterable %}
13 {% for user in users %}
14 Hello {{ user }}!
15 {% endfor %}
16 {% else %}
17 {# users is probably a string #}
18 Hello {{ users }}!
19 {% endif %}
diff --git a/vendor/twig/twig/doc/tests/null.rst b/vendor/twig/twig/doc/tests/null.rst
new file mode 100644
index 00000000..44eec62e
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/null.rst
@@ -0,0 +1,12 @@
1``null``
2========
3
4``null`` returns ``true`` if the variable is ``null``:
5
6.. code-block:: jinja
7
8 {{ var is null }}
9
10.. note::
11
12 ``none`` is an alias for ``null``.
diff --git a/vendor/twig/twig/doc/tests/odd.rst b/vendor/twig/twig/doc/tests/odd.rst
new file mode 100644
index 00000000..9eece777
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/odd.rst
@@ -0,0 +1,10 @@
1``odd``
2=======
3
4``odd`` returns ``true`` if the given number is odd:
5
6.. code-block:: jinja
7
8 {{ var is odd }}
9
10.. seealso:: :doc:`even<../tests/even>`
diff --git a/vendor/twig/twig/doc/tests/sameas.rst b/vendor/twig/twig/doc/tests/sameas.rst
new file mode 100644
index 00000000..efb15c35
--- /dev/null
+++ b/vendor/twig/twig/doc/tests/sameas.rst
@@ -0,0 +1,11 @@
1``sameas``
2==========
3
4``sameas`` checks if a variable points to the same memory address than another
5variable:
6
7.. code-block:: jinja
8
9 {% if foo.attribute is sameas(false) %}
10 the foo attribute really is the ``false`` PHP value
11 {% endif %}
diff --git a/vendor/twig/twig/ext/twig/.gitignore b/vendor/twig/twig/ext/twig/.gitignore
new file mode 100644
index 00000000..56ea76cc
--- /dev/null
+++ b/vendor/twig/twig/ext/twig/.gitignore
@@ -0,0 +1,30 @@
1*.sw*
2.deps
3Makefile
4Makefile.fragments
5Makefile.global
6Makefile.objects
7acinclude.m4
8aclocal.m4
9build/
10config.cache
11config.guess
12config.h
13config.h.in
14config.log
15config.nice
16config.status
17config.sub
18configure
19configure.in
20install-sh
21libtool
22ltmain.sh
23missing
24mkinstalldirs
25run-tests.php
26twig.loT
27.libs/
28modules/
29twig.la
30twig.lo
diff --git a/vendor/twig/twig/ext/twig/LICENSE b/vendor/twig/twig/ext/twig/LICENSE
new file mode 100644
index 00000000..66b8bb4c
--- /dev/null
+++ b/vendor/twig/twig/ext/twig/LICENSE
@@ -0,0 +1,22 @@
1Copyright (c) 2011, Derick Rethans <derick@derickrethans.nl>
2All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright notice,
8 this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12
13THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
17FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/twig/twig/ext/twig/config.m4 b/vendor/twig/twig/ext/twig/config.m4
new file mode 100644
index 00000000..83486be4
--- /dev/null
+++ b/vendor/twig/twig/ext/twig/config.m4
@@ -0,0 +1,8 @@
1dnl config.m4 for extension twig
2
3PHP_ARG_ENABLE(twig, whether to enable twig support,
4[ --enable-twig Enable twig support])
5
6if test "$PHP_TWIG" != "no"; then
7 PHP_NEW_EXTENSION(twig, twig.c, $ext_shared)
8fi
diff --git a/vendor/twig/twig/ext/twig/config.w32 b/vendor/twig/twig/ext/twig/config.w32
new file mode 100644
index 00000000..cb287b99
--- /dev/null
+++ b/vendor/twig/twig/ext/twig/config.w32
@@ -0,0 +1,8 @@
1// vim:ft=javascript
2
3ARG_ENABLE("twig", "Twig support", "no");
4
5if (PHP_TWIG != "no") {
6 AC_DEFINE('HAVE_TWIG', 1);
7 EXTENSION('twig', 'twig.c');
8}
diff --git a/vendor/twig/twig/ext/twig/php_twig.h b/vendor/twig/twig/ext/twig/php_twig.h
new file mode 100644
index 00000000..1cf0ad44
--- /dev/null
+++ b/vendor/twig/twig/ext/twig/php_twig.h
@@ -0,0 +1,31 @@
1/*
2 +----------------------------------------------------------------------+
3 | Twig Extension |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2011 Derick Rethans |
6 +----------------------------------------------------------------------+
7 | Redistribution and use in source and binary forms, with or without |
8 | modification, are permitted provided that the conditions mentioned |
9 | in the accompanying LICENSE file are met (BSD, revised). |
10 +----------------------------------------------------------------------+
11 | Author: Derick Rethans <derick@derickrethans.nl> |
12 +----------------------------------------------------------------------+
13 */
14
15#ifndef PHP_TWIG_H
16#define PHP_TWIG_H
17
18#define PHP_TWIG_VERSION "1.13.2"
19
20#include "php.h"
21
22extern zend_module_entry twig_module_entry;
23#define phpext_twig_ptr &twig_module_entry
24
25#ifdef ZTS
26#include "TSRM.h"
27#endif
28
29PHP_FUNCTION(twig_template_get_attributes);
30
31#endif
diff --git a/vendor/twig/twig/ext/twig/twig.c b/vendor/twig/twig/ext/twig/twig.c
new file mode 100644
index 00000000..3ba9ff2c
--- /dev/null
+++ b/vendor/twig/twig/ext/twig/twig.c
@@ -0,0 +1,1076 @@
1/*
2 +----------------------------------------------------------------------+
3 | Twig Extension |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2011 Derick Rethans |
6 +----------------------------------------------------------------------+
7 | Redistribution and use in source and binary forms, with or without |
8 | modification, are permitted provided that the conditions mentioned |
9 | in the accompanying LICENSE file are met (BSD, revised). |
10 +----------------------------------------------------------------------+
11 | Author: Derick Rethans <derick@derickrethans.nl> |
12 +----------------------------------------------------------------------+
13 */
14
15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include "php.h"
20#include "php_twig.h"
21#include "ext/standard/php_string.h"
22#include "ext/standard/php_smart_str.h"
23
24#include "Zend/zend_object_handlers.h"
25#include "Zend/zend_interfaces.h"
26#include "Zend/zend_exceptions.h"
27
28#ifndef Z_ADDREF_P
29#define Z_ADDREF_P(pz) (pz)->refcount++
30#endif
31
32#define FREE_DTOR(z) \
33 zval_dtor(z); \
34 efree(z);
35
36#if PHP_VERSION_ID >= 50300
37 #define APPLY_TSRMLS_DC TSRMLS_DC
38 #define APPLY_TSRMLS_CC TSRMLS_CC
39 #define APPLY_TSRMLS_FETCH()
40#else
41 #define APPLY_TSRMLS_DC
42 #define APPLY_TSRMLS_CC
43 #define APPLY_TSRMLS_FETCH() TSRMLS_FETCH()
44#endif
45
46ZEND_BEGIN_ARG_INFO_EX(twig_template_get_attribute_args, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 6)
47 ZEND_ARG_INFO(0, template)
48 ZEND_ARG_INFO(0, object)
49 ZEND_ARG_INFO(0, item)
50 ZEND_ARG_INFO(0, arguments)
51 ZEND_ARG_INFO(0, type)
52 ZEND_ARG_INFO(0, isDefinedTest)
53ZEND_END_ARG_INFO()
54
55zend_function_entry twig_functions[] = {
56 PHP_FE(twig_template_get_attributes, twig_template_get_attribute_args)
57 {NULL, NULL, NULL}
58};
59
60
61zend_module_entry twig_module_entry = {
62 STANDARD_MODULE_HEADER,
63 "twig",
64 twig_functions,
65 NULL,
66 NULL,
67 NULL,
68 NULL,
69 NULL,
70 PHP_TWIG_VERSION,
71 STANDARD_MODULE_PROPERTIES
72};
73
74
75#ifdef COMPILE_DL_TWIG
76ZEND_GET_MODULE(twig)
77#endif
78
79int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
80{
81 zval temp;
82 int result;
83
84 if (Z_TYPE_P(array) != IS_ARRAY) {
85 return 0;
86 }
87
88 switch (Z_TYPE_P(key)) {
89 case IS_NULL:
90 return zend_hash_exists(Z_ARRVAL_P(array), "", 1);
91
92 case IS_BOOL:
93 case IS_DOUBLE:
94 convert_to_long(key);
95 case IS_LONG:
96 return zend_hash_index_exists(Z_ARRVAL_P(array), Z_LVAL_P(key));
97
98 default:
99 convert_to_string(key);
100 return zend_symtable_exists(Z_ARRVAL_P(array), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1);
101 }
102}
103
104int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
105{
106 if (Z_TYPE_P(object) != IS_OBJECT) {
107 return 0;
108 }
109 return instanceof_function(Z_OBJCE_P(object), interface TSRMLS_CC);
110}
111
112int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
113{
114 zend_class_entry **pce;
115 if (Z_TYPE_P(object) != IS_OBJECT) {
116 return 0;
117 }
118 if (zend_lookup_class(interface, strlen(interface), &pce TSRMLS_CC) == FAILURE) {
119 return 0;
120 }
121 return instanceof_function(Z_OBJCE_P(object), *pce TSRMLS_CC);
122}
123
124zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
125{
126 zend_class_entry *ce = Z_OBJCE_P(object);
127 zval *retval;
128
129 if (Z_TYPE_P(object) == IS_OBJECT) {
130 SEPARATE_ARG_IF_REF(offset);
131 zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
132
133 zval_ptr_dtor(&offset);
134
135 if (!retval) {
136 if (!EG(exception)) {
137 zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
138 }
139 return NULL;
140 }
141
142 return retval;
143 }
144 return NULL;
145}
146
147int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
148{
149 zend_class_entry *ce = Z_OBJCE_P(object);
150 zval *retval;
151
152 if (Z_TYPE_P(object) == IS_OBJECT) {
153 SEPARATE_ARG_IF_REF(offset);
154 zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
155
156 zval_ptr_dtor(&offset);
157
158 if (!retval) {
159 if (!EG(exception)) {
160 zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
161 }
162 return 0;
163 }
164
165 return (retval && Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval));
166 }
167 return 0;
168}
169
170char *TWIG_STRTOLOWER(const char *str, int str_len)
171{
172 char *item_dup;
173
174 item_dup = estrndup(str, str_len);
175 php_strtolower(item_dup, str_len);
176 return item_dup;
177}
178
179zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC)
180{
181 zend_fcall_info fci;
182 zval ***args = NULL;
183 int arg_count = 0;
184 HashTable *table;
185 HashPosition pos;
186 int i = 0;
187 zval *retval_ptr;
188 zval *zfunction;
189
190 if (arguments) {
191 table = HASH_OF(arguments);
192 args = safe_emalloc(sizeof(zval **), table->nNumOfElements, 0);
193
194 zend_hash_internal_pointer_reset_ex(table, &pos);
195
196 while (zend_hash_get_current_data_ex(table, (void **)&args[i], &pos) == SUCCESS) {
197 i++;
198 zend_hash_move_forward_ex(table, &pos);
199 }
200 arg_count = table->nNumOfElements;
201 }
202
203 MAKE_STD_ZVAL(zfunction);
204 ZVAL_STRING(zfunction, function, 1);
205 fci.size = sizeof(fci);
206 fci.function_table = EG(function_table);
207 fci.function_name = zfunction;
208 fci.symbol_table = NULL;
209#if PHP_VERSION_ID >= 50300
210 fci.object_ptr = object;
211#else
212 fci.object_pp = &object;
213#endif
214 fci.retval_ptr_ptr = &retval_ptr;
215 fci.param_count = arg_count;
216 fci.params = args;
217 fci.no_separation = 0;
218
219 if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
220 ALLOC_INIT_ZVAL(retval_ptr);
221 ZVAL_BOOL(retval_ptr, 0);
222 }
223
224 if (args) {
225 efree(fci.params);
226 }
227 FREE_DTOR(zfunction);
228 return retval_ptr;
229}
230
231int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
232{
233 zval *ret;
234 int res;
235
236 ret = TWIG_CALL_USER_FUNC_ARRAY(object, functionName, NULL TSRMLS_CC);
237 res = Z_LVAL_P(ret);
238 zval_ptr_dtor(&ret);
239 return res;
240}
241
242zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
243{
244 zval **tmp_zval;
245 zend_class_entry *ce;
246
247 if (class == NULL || Z_TYPE_P(class) != IS_OBJECT) {
248 return NULL;
249 }
250
251 ce = zend_get_class_entry(class TSRMLS_CC);
252#if PHP_VERSION_ID >= 50400
253 tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0, NULL TSRMLS_CC);
254#else
255 tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0 TSRMLS_CC);
256#endif
257 return *tmp_zval;
258}
259
260zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
261{
262 zval **tmp_zval;
263 char *tmp_name;
264
265 if (class == NULL || Z_TYPE_P(class) != IS_ARRAY) {
266 if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
267 // array access object
268 return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC);
269 }
270 return NULL;
271 }
272
273 switch(Z_TYPE_P(prop_name)) {
274 case IS_NULL:
275 zend_hash_find(HASH_OF(class), "", 1, (void**) &tmp_zval);
276 return *tmp_zval;
277
278 case IS_BOOL:
279 case IS_DOUBLE:
280 convert_to_long(prop_name);
281 case IS_LONG:
282 zend_hash_index_find(HASH_OF(class), Z_LVAL_P(prop_name), (void **) &tmp_zval);
283 return *tmp_zval;
284
285 case IS_STRING:
286 zend_symtable_find(HASH_OF(class), Z_STRVAL_P(prop_name), Z_STRLEN_P(prop_name) + 1, (void**) &tmp_zval);
287 return *tmp_zval;
288 }
289
290 return NULL;
291}
292
293zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC)
294{
295 zval **tmp_zval;
296
297 if (class == NULL/* || Z_TYPE_P(class) != IS_ARRAY*/) {
298 return NULL;
299 }
300
301 if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
302 // array access object
303 zval *tmp_name_zval;
304 zval *tmp_ret_zval;
305
306 ALLOC_INIT_ZVAL(tmp_name_zval);
307 ZVAL_STRING(tmp_name_zval, prop_name, 1);
308 tmp_ret_zval = TWIG_GET_ARRAYOBJECT_ELEMENT(class, tmp_name_zval TSRMLS_CC);
309 FREE_DTOR(tmp_name_zval);
310 return tmp_ret_zval;
311 }
312
313 if (zend_symtable_find(HASH_OF(class), prop_name, prop_name_length+1, (void**)&tmp_zval) == SUCCESS) {
314 return *tmp_zval;
315 }
316 return NULL;
317}
318
319zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
320{
321 zval *tmp = NULL;
322
323 if (Z_OBJ_HT_P(object)->read_property) {
324#if PHP_VERSION_ID >= 50400
325 tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS, NULL TSRMLS_CC);
326#else
327 tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS TSRMLS_CC);
328#endif
329 if (tmp != EG(uninitialized_zval_ptr)) {
330 return tmp;
331 } else {
332 return NULL;
333 }
334 }
335 return tmp;
336}
337
338int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
339{
340 if (Z_OBJ_HT_P(object)->has_property) {
341#if PHP_VERSION_ID >= 50400
342 return Z_OBJ_HT_P(object)->has_property(object, propname, 0, NULL TSRMLS_CC);
343#else
344 return Z_OBJ_HT_P(object)->has_property(object, propname, 0 TSRMLS_CC);
345#endif
346 }
347 return 0;
348}
349
350int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
351{
352 if (Z_OBJ_HT_P(object)->get_properties) {
353 return zend_hash_quick_exists(
354 Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC), // the properties hash
355 prop, // property name
356 prop_len + 1, // property length
357 zend_get_hash_value(prop, prop_len + 1) // hash value
358 );
359 }
360 return 0;
361}
362
363zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
364{
365 zval *tmp_name_zval, *tmp;
366
367 ALLOC_INIT_ZVAL(tmp_name_zval);
368 ZVAL_STRING(tmp_name_zval, propname, 1);
369 tmp = TWIG_PROPERTY(object, tmp_name_zval TSRMLS_CC);
370 FREE_DTOR(tmp_name_zval);
371 return tmp;
372}
373
374int TWIG_CALL_B_0(zval *object, char *method)
375{
376 return 0;
377}
378
379zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
380{
381 zend_fcall_info fci;
382 zval **args[1];
383 zval *argument;
384 zval *zfunction;
385 zval *retval_ptr;
386
387 MAKE_STD_ZVAL(argument);
388 ZVAL_STRING(argument, arg0, 1);
389 args[0] = &argument;
390
391 MAKE_STD_ZVAL(zfunction);
392 ZVAL_STRING(zfunction, method, 1);
393 fci.size = sizeof(fci);
394 fci.function_table = EG(function_table);
395 fci.function_name = zfunction;
396 fci.symbol_table = NULL;
397#if PHP_VERSION_ID >= 50300
398 fci.object_ptr = object;
399#else
400 fci.object_pp = &object;
401#endif
402 fci.retval_ptr_ptr = &retval_ptr;
403 fci.param_count = 1;
404 fci.params = args;
405 fci.no_separation = 0;
406
407 if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
408 FREE_DTOR(zfunction);
409 zval_ptr_dtor(&argument);
410 return 0;
411 }
412 FREE_DTOR(zfunction);
413 zval_ptr_dtor(&argument);
414 return retval_ptr;
415}
416
417int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
418{
419 zval *retval_ptr;
420 int success;
421
422 retval_ptr = TWIG_CALL_S(object, method, arg0 TSRMLS_CC);
423 success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
424
425 if (retval_ptr) {
426 zval_ptr_dtor(&retval_ptr);
427 }
428
429 return success;
430}
431
432int TWIG_CALL_Z(zval *object, char *method, zval *arg1 TSRMLS_DC)
433{
434 zend_fcall_info fci;
435 zval **args[1];
436 zval *zfunction;
437 zval *retval_ptr;
438 int success;
439
440 args[0] = &arg1;
441
442 MAKE_STD_ZVAL(zfunction);
443 ZVAL_STRING(zfunction, method, 1);
444 fci.size = sizeof(fci);
445 fci.function_table = EG(function_table);
446 fci.function_name = zfunction;
447 fci.symbol_table = NULL;
448#if PHP_VERSION_ID >= 50300
449 fci.object_ptr = object;
450#else
451 fci.object_pp = &object;
452#endif
453 fci.retval_ptr_ptr = &retval_ptr;
454 fci.param_count = 1;
455 fci.params = args;
456 fci.no_separation = 0;
457
458 if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
459 FREE_DTOR(zfunction);
460 if (retval_ptr) {
461 zval_ptr_dtor(&retval_ptr);
462 }
463 return 0;
464 }
465
466 FREE_DTOR(zfunction);
467
468 success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
469 if (retval_ptr) {
470 zval_ptr_dtor(&retval_ptr);
471 }
472
473 return success;
474}
475
476int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
477{
478 zend_fcall_info fci;
479 zval **args[2];
480 zval *zfunction;
481 zval *retval_ptr;
482 int success;
483
484 args[0] = &arg1;
485 args[1] = &arg2;
486
487 MAKE_STD_ZVAL(zfunction);
488 ZVAL_STRING(zfunction, method, 1);
489 fci.size = sizeof(fci);
490 fci.function_table = EG(function_table);
491 fci.function_name = zfunction;
492 fci.symbol_table = NULL;
493#if PHP_VERSION_ID >= 50300
494 fci.object_ptr = object;
495#else
496 fci.object_pp = &object;
497#endif
498 fci.retval_ptr_ptr = &retval_ptr;
499 fci.param_count = 2;
500 fci.params = args;
501 fci.no_separation = 0;
502
503 if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
504 FREE_DTOR(zfunction);
505 return 0;
506 }
507
508 FREE_DTOR(zfunction);
509
510 success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
511 if (retval_ptr) {
512 zval_ptr_dtor(&retval_ptr);
513 }
514
515 return success;
516}
517
518#ifndef Z_SET_REFCOUNT_P
519# define Z_SET_REFCOUNT_P(pz, rc) pz->refcount = rc
520# define Z_UNSET_ISREF_P(pz) pz->is_ref = 0
521#endif
522
523void TWIG_NEW(zval *object, char *class, zval *arg0, zval *arg1 TSRMLS_DC)
524{
525 zend_class_entry **pce;
526
527 if (zend_lookup_class(class, strlen(class), &pce TSRMLS_CC) == FAILURE) {
528 return;
529 }
530
531 Z_TYPE_P(object) = IS_OBJECT;
532 object_init_ex(object, *pce);
533 Z_SET_REFCOUNT_P(object, 1);
534 Z_UNSET_ISREF_P(object);
535
536 TWIG_CALL_ZZ(object, "__construct", arg0, arg1 TSRMLS_CC);
537}
538
539static int twig_add_array_key_to_string(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
540{
541 smart_str *buf;
542 char *joiner;
543 APPLY_TSRMLS_FETCH();
544
545 buf = va_arg(args, smart_str*);
546 joiner = va_arg(args, char*);
547
548 if (buf->len != 0) {
549 smart_str_appends(buf, joiner);
550 }
551
552 if (hash_key->nKeyLength == 0) {
553 smart_str_append_long(buf, (long) hash_key->h);
554 } else {
555 char *key, *tmp_str;
556 int key_len, tmp_len;
557 key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC);
558 tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL);
559
560 smart_str_appendl(buf, tmp_str, tmp_len);
561 efree(key);
562 efree(tmp_str);
563 }
564
565 return 0;
566}
567
568char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
569{
570 smart_str collector = { 0, 0, 0 };
571
572 smart_str_appendl(&collector, "", 0);
573 zend_hash_apply_with_arguments(HASH_OF(array) APPLY_TSRMLS_CC, twig_add_array_key_to_string, 2, &collector, joiner);
574 smart_str_0(&collector);
575
576 return collector.c;
577}
578
579static void TWIG_THROW_EXCEPTION(char *exception_name TSRMLS_DC, char *message, ...)
580{
581 char *buffer;
582 va_list args;
583 zend_class_entry **pce;
584
585 if (zend_lookup_class(exception_name, strlen(exception_name), &pce TSRMLS_CC) == FAILURE) {
586 return;
587 }
588
589 va_start(args, message);
590 vspprintf(&buffer, 0, message, args);
591 va_end(args);
592
593 zend_throw_exception_ex(*pce, 0 TSRMLS_CC, buffer);
594 efree(buffer);
595}
596
597static void TWIG_RUNTIME_ERROR(zval *template TSRMLS_DC, char *message, ...)
598{
599 char *buffer;
600 va_list args;
601 zend_class_entry **pce;
602 zval *ex;
603 zval *constructor;
604 zval *zmessage;
605 zval *lineno;
606 zval *filename_func;
607 zval *filename;
608 zval *constructor_args[3];
609 zval *constructor_retval;
610
611 if (zend_lookup_class("Twig_Error_Runtime", strlen("Twig_Error_Runtime"), &pce TSRMLS_CC) == FAILURE) {
612 return;
613 }
614
615 va_start(args, message);
616 vspprintf(&buffer, 0, message, args);
617 va_end(args);
618
619 MAKE_STD_ZVAL(ex);
620 object_init_ex(ex, *pce);
621
622 // Call Twig_Error constructor
623 MAKE_STD_ZVAL(constructor);
624 MAKE_STD_ZVAL(zmessage);
625 MAKE_STD_ZVAL(lineno);
626 MAKE_STD_ZVAL(filename);
627 MAKE_STD_ZVAL(filename_func);
628 MAKE_STD_ZVAL(constructor_retval);
629
630 ZVAL_STRINGL(constructor, "__construct", sizeof("__construct")-1, 1);
631 ZVAL_STRING(zmessage, buffer, 1);
632 ZVAL_LONG(lineno, -1);
633
634 // Get template filename
635 ZVAL_STRINGL(filename_func, "getTemplateName", sizeof("getTemplateName")-1, 1);
636 call_user_function(EG(function_table), &template, filename_func, filename, 0, 0 TSRMLS_CC);
637
638 constructor_args[0] = zmessage;
639 constructor_args[1] = lineno;
640 constructor_args[2] = filename;
641 call_user_function(EG(function_table), &ex, constructor, constructor_retval, 3, constructor_args TSRMLS_CC);
642
643 zval_ptr_dtor(&constructor_retval);
644 zval_ptr_dtor(&zmessage);
645 zval_ptr_dtor(&lineno);
646 zval_ptr_dtor(&filename);
647 FREE_DTOR(constructor);
648 FREE_DTOR(filename_func);
649 efree(buffer);
650
651 zend_throw_exception_object(ex TSRMLS_CC);
652}
653
654static char *TWIG_GET_CLASS_NAME(zval *object TSRMLS_DC)
655{
656 char *class_name;
657 zend_uint class_name_len;
658
659 if (Z_TYPE_P(object) != IS_OBJECT) {
660 return "";
661 }
662#if PHP_API_VERSION >= 20100412
663 zend_get_object_classname(object, (const char **) &class_name, &class_name_len TSRMLS_CC);
664#else
665 zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC);
666#endif
667 return class_name;
668}
669
670static int twig_add_method_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
671{
672 zval *retval;
673 char *item;
674 size_t item_len;
675 zend_function *mptr = (zend_function *) pDest;
676 APPLY_TSRMLS_FETCH();
677
678 if (!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)) {
679 return 0;
680 }
681
682 retval = va_arg(args, zval*);
683
684 item_len = strlen(mptr->common.function_name);
685 item = estrndup(mptr->common.function_name, item_len);
686 php_strtolower(item, item_len);
687
688 add_assoc_stringl_ex(retval, item, item_len+1, item, item_len, 0);
689
690 return 0;
691}
692
693static int twig_add_property_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
694{
695 zend_class_entry *ce;
696 zval *retval;
697 char *class_name, *prop_name;
698 zend_property_info *pptr = (zend_property_info *) pDest;
699 APPLY_TSRMLS_FETCH();
700
701 if (!(pptr->flags & ZEND_ACC_PUBLIC)) {
702 return 0;
703 }
704
705 ce = *va_arg(args, zend_class_entry**);
706 retval = va_arg(args, zval*);
707
708#if PHP_API_VERSION >= 20100412
709 zend_unmangle_property_name(pptr->name, pptr->name_length, (const char **) &class_name, (const char **) &prop_name);
710#else
711 zend_unmangle_property_name(pptr->name, pptr->name_length, &class_name, &prop_name);
712#endif
713
714 add_assoc_string(retval, prop_name, prop_name, 1);
715
716 return 0;
717}
718
719static void twig_add_class_to_cache(zval *cache, zval *object, char *class_name TSRMLS_DC)
720{
721 zval *class_info, *class_methods, *class_properties;
722 zend_class_entry *class_ce;
723
724 class_ce = zend_get_class_entry(object TSRMLS_CC);
725
726 ALLOC_INIT_ZVAL(class_info);
727 ALLOC_INIT_ZVAL(class_methods);
728 ALLOC_INIT_ZVAL(class_properties);
729 array_init(class_info);
730 array_init(class_methods);
731 array_init(class_properties);
732 // add all methods to self::cache[$class]['methods']
733 zend_hash_apply_with_arguments(&class_ce->function_table APPLY_TSRMLS_CC, twig_add_method_to_class, 1, class_methods);
734 zend_hash_apply_with_arguments(&class_ce->properties_info APPLY_TSRMLS_CC, twig_add_property_to_class, 2, &class_ce, class_properties);
735
736 add_assoc_zval(class_info, "methods", class_methods);
737 add_assoc_zval(class_info, "properties", class_properties);
738 add_assoc_zval(cache, class_name, class_info);
739}
740
741/* {{{ proto mixed twig_template_get_attributes(TwigTemplate template, mixed object, mixed item, array arguments, string type, boolean isDefinedTest, boolean ignoreStrictCheck)
742 A C implementation of TwigTemplate::getAttribute() */
743PHP_FUNCTION(twig_template_get_attributes)
744{
745 zval *template;
746 zval *object;
747 char *item;
748 int item_len;
749 zval *zitem, ztmpitem;
750 zval *arguments = NULL;
751 zval *ret = NULL;
752 char *type = NULL;
753 int type_len = 0;
754 zend_bool isDefinedTest = 0;
755 zend_bool ignoreStrictCheck = 0;
756 int free_ret = 0;
757 zval *tmp_self_cache;
758
759
760 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozz|asbb", &template, &object, &zitem, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) {
761 return;
762 }
763
764 // convert the item to a string
765 ztmpitem = *zitem;
766 zval_copy_ctor(&ztmpitem);
767 convert_to_string(&ztmpitem);
768 item_len = Z_STRLEN(ztmpitem);
769 item = estrndup(Z_STRVAL(ztmpitem), item_len);
770 zval_dtor(&ztmpitem);
771
772 if (!type) {
773 type = "any";
774 }
775
776/*
777 // array
778 if (Twig_TemplateInterface::METHOD_CALL !== $type) {
779 $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
780
781 if ((is_array($object) && array_key_exists($arrayItem, $object))
782 || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
783 ) {
784 if ($isDefinedTest) {
785 return true;
786 }
787
788 return $object[$arrayItem];
789 }
790*/
791
792
793 if (strcmp("method", type) != 0) {
794 if ((TWIG_ARRAY_KEY_EXISTS(object, zitem))
795 || (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, zitem TSRMLS_CC))
796 ) {
797
798 if (isDefinedTest) {
799 RETURN_TRUE;
800 }
801
802 ret = TWIG_GET_ARRAY_ELEMENT_ZVAL(object, zitem TSRMLS_CC);
803
804 if (!ret) {
805 ret = &EG(uninitialized_zval);
806 }
807 RETVAL_ZVAL(ret, 1, 0);
808 if (free_ret) {
809 zval_ptr_dtor(&ret);
810 }
811 return;
812 }
813/*
814 if (Twig_TemplateInterface::ARRAY_CALL === $type) {
815 if ($isDefinedTest) {
816 return false;
817 }
818 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
819 return null;
820 }
821*/
822 if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) {
823 if (isDefinedTest) {
824 RETURN_FALSE;
825 }
826 if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
827 return;
828 }
829/*
830 if (is_object($object)) {
831 throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName());
832 } elseif (is_array($object)) {
833 throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName());
834 } elseif (Twig_TemplateInterface::ARRAY_CALL === $type) {
835 throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
836 } else {
837 throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
838 }
839 }
840 }
841*/
842 if (Z_TYPE_P(object) == IS_OBJECT) {
843 TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" in object (with ArrayAccess) of type \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
844 } else if (Z_TYPE_P(object) == IS_ARRAY) {
845 TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC));
846 } else {
847 char *type_name = zend_zval_type_name(object);
848 Z_ADDREF_P(object);
849 convert_to_string(object);
850 TWIG_RUNTIME_ERROR(template TSRMLS_CC,
851 (strcmp("array", type) == 0)
852 ? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")"
853 : "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\")",
854 item, type_name, Z_STRVAL_P(object));
855 zval_ptr_dtor(&object);
856 }
857 return;
858 }
859 }
860
861/*
862 if (!is_object($object)) {
863 if ($isDefinedTest) {
864 return false;
865 }
866*/
867
868 if (Z_TYPE_P(object) != IS_OBJECT) {
869 if (isDefinedTest) {
870 RETURN_FALSE;
871 }
872/*
873 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
874 return null;
875 }
876 throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
877 }
878*/
879 if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
880 return;
881 }
882
883 char *type_name = zend_zval_type_name(object);
884 Z_ADDREF_P(object);
885 convert_to_string_ex(&object);
886
887 TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object));
888
889 zval_ptr_dtor(&object);
890
891 return;
892 }
893/*
894 $class = get_class($object);
895*/
896 char *class_name = NULL;
897 zval *tmp_class;
898
899 class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC);
900 tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC);
901 tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
902
903 if (!tmp_class) {
904 twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC);
905 tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
906 }
907 efree(class_name);
908
909/*
910 // object property
911 if (Twig_TemplateInterface::METHOD_CALL !== $type) {
912 if (isset($object->$item) || array_key_exists((string) $item, $object)) {
913 if ($isDefinedTest) {
914 return true;
915 }
916
917 if ($this->env->hasExtension('sandbox')) {
918 $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
919 }
920
921 return $object->$item;
922 }
923 }
924*/
925 if (strcmp("method", type) != 0) {
926 zval *tmp_properties, *tmp_item;
927
928 tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC);
929 tmp_item = TWIG_GET_ARRAY_ELEMENT(tmp_properties, item, item_len TSRMLS_CC);
930
931 if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) {
932 if (isDefinedTest) {
933 RETURN_TRUE;
934 }
935 if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
936 TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC);
937 }
938 if (EG(exception)) {
939 return;
940 }
941
942 ret = TWIG_PROPERTY(object, zitem TSRMLS_CC);
943 RETURN_ZVAL(ret, 1, 0);
944 }
945 }
946/*
947 // object method
948 if (!isset(self::$cache[$class]['methods'])) {
949 self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
950 }
951
952 $lcItem = strtolower($item);
953 if (isset(self::$cache[$class]['methods'][$lcItem])) {
954 $method = (string) $item;
955 } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
956 $method = 'get'.$item;
957 } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
958 $method = 'is'.$item;
959 } elseif (isset(self::$cache[$class]['methods']['__call'])) {
960 $method = (string) $item;
961*/
962 {
963 char *lcItem = TWIG_STRTOLOWER(item, item_len);
964 int lcItem_length;
965 char *method = NULL;
966 char *tmp_method_name_get;
967 char *tmp_method_name_is;
968 zval *tmp_methods;
969
970 lcItem_length = strlen(lcItem);
971 tmp_method_name_get = emalloc(4 + lcItem_length);
972 tmp_method_name_is = emalloc(3 + lcItem_length);
973
974 sprintf(tmp_method_name_get, "get%s", lcItem);
975 sprintf(tmp_method_name_is, "is%s", lcItem);
976
977 tmp_methods = TWIG_GET_ARRAY_ELEMENT(tmp_class, "methods", strlen("methods") TSRMLS_CC);
978
979 if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, lcItem, lcItem_length TSRMLS_CC)) {
980 method = item;
981 } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_get, lcItem_length + 3 TSRMLS_CC)) {
982 method = tmp_method_name_get;
983 } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_is, lcItem_length + 2 TSRMLS_CC)) {
984 method = tmp_method_name_is;
985 } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, "__call", 6 TSRMLS_CC)) {
986 method = item;
987/*
988 } else {
989 if ($isDefinedTest) {
990 return false;
991 }
992
993 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
994 return null;
995 }
996
997 throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
998 }
999
1000 if ($isDefinedTest) {
1001 return true;
1002 }
1003*/
1004 } else {
1005 efree(tmp_method_name_get);
1006 efree(tmp_method_name_is);
1007 efree(lcItem);
1008
1009 if (isDefinedTest) {
1010 RETURN_FALSE;
1011 }
1012 if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
1013 return;
1014 }
1015 TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Method \"%s\" for object \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
1016 return;
1017 }
1018
1019 if (isDefinedTest) {
1020 efree(tmp_method_name_get);
1021 efree(tmp_method_name_is);
1022 efree(lcItem);
1023 RETURN_TRUE;
1024 }
1025/*
1026 if ($this->env->hasExtension('sandbox')) {
1027 $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
1028 }
1029*/
1030 if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
1031 TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, zitem TSRMLS_CC);
1032 }
1033 if (EG(exception)) {
1034 efree(tmp_method_name_get);
1035 efree(tmp_method_name_is);
1036 efree(lcItem);
1037 return;
1038 }
1039/*
1040 $ret = call_user_func_array(array($object, $method), $arguments);
1041*/
1042 ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
1043 free_ret = 1;
1044 efree(tmp_method_name_get);
1045 efree(tmp_method_name_is);
1046 efree(lcItem);
1047 }
1048/*
1049 // useful when calling a template method from a template
1050 // this is not supported but unfortunately heavily used in the Symfony profiler
1051 if ($object instanceof Twig_TemplateInterface) {
1052 return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
1053 }
1054
1055 return $ret;
1056*/
1057 // ret can be null, if e.g. the called method throws an exception
1058 if (ret) {
1059 if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) {
1060 if (Z_STRLEN_P(ret) != 0) {
1061 zval *charset = TWIG_CALL_USER_FUNC_ARRAY(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getCharset", NULL TSRMLS_CC);
1062 TWIG_NEW(return_value, "Twig_Markup", ret, charset TSRMLS_CC);
1063 zval_ptr_dtor(&charset);
1064 if (ret) {
1065 zval_ptr_dtor(&ret);
1066 }
1067 return;
1068 }
1069 }
1070
1071 RETVAL_ZVAL(ret, 1, 0);
1072 if (free_ret) {
1073 zval_ptr_dtor(&ret);
1074 }
1075 }
1076}
diff --git a/vendor/twig/twig/lib/Twig/Autoloader.php b/vendor/twig/twig/lib/Twig/Autoloader.php
new file mode 100644
index 00000000..7007d315
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Autoloader.php
@@ -0,0 +1,48 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Autoloads Twig classes.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Autoloader
18{
19 /**
20 * Registers Twig_Autoloader as an SPL autoloader.
21 *
22 * @param Boolean $prepend Whether to prepend the autoloader or not.
23 */
24 public static function register($prepend = false)
25 {
26 if (version_compare(phpversion(), '5.3.0', '>=')) {
27 spl_autoload_register(array(new self, 'autoload'), true, $prepend);
28 } else {
29 spl_autoload_register(array(new self, 'autoload'));
30 }
31 }
32
33 /**
34 * Handles autoloading of classes.
35 *
36 * @param string $class A class name.
37 */
38 public static function autoload($class)
39 {
40 if (0 !== strpos($class, 'Twig')) {
41 return;
42 }
43
44 if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
45 require $file;
46 }
47 }
48}
diff --git a/vendor/twig/twig/lib/Twig/Compiler.php b/vendor/twig/twig/lib/Twig/Compiler.php
new file mode 100644
index 00000000..99aecbcc
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Compiler.php
@@ -0,0 +1,267 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Compiles a node to PHP code.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Compiler implements Twig_CompilerInterface
19{
20 protected $lastLine;
21 protected $source;
22 protected $indentation;
23 protected $env;
24 protected $debugInfo;
25 protected $sourceOffset;
26 protected $sourceLine;
27 protected $filename;
28
29 /**
30 * Constructor.
31 *
32 * @param Twig_Environment $env The twig environment instance
33 */
34 public function __construct(Twig_Environment $env)
35 {
36 $this->env = $env;
37 $this->debugInfo = array();
38 }
39
40 public function getFilename()
41 {
42 return $this->filename;
43 }
44
45 /**
46 * Returns the environment instance related to this compiler.
47 *
48 * @return Twig_Environment The environment instance
49 */
50 public function getEnvironment()
51 {
52 return $this->env;
53 }
54
55 /**
56 * Gets the current PHP code after compilation.
57 *
58 * @return string The PHP code
59 */
60 public function getSource()
61 {
62 return $this->source;
63 }
64
65 /**
66 * Compiles a node.
67 *
68 * @param Twig_NodeInterface $node The node to compile
69 * @param integer $indentation The current indentation
70 *
71 * @return Twig_Compiler The current compiler instance
72 */
73 public function compile(Twig_NodeInterface $node, $indentation = 0)
74 {
75 $this->lastLine = null;
76 $this->source = '';
77 $this->sourceOffset = 0;
78 // source code starts at 1 (as we then increment it when we encounter new lines)
79 $this->sourceLine = 1;
80 $this->indentation = $indentation;
81
82 if ($node instanceof Twig_Node_Module) {
83 $this->filename = $node->getAttribute('filename');
84 }
85
86 $node->compile($this);
87
88 return $this;
89 }
90
91 public function subcompile(Twig_NodeInterface $node, $raw = true)
92 {
93 if (false === $raw) {
94 $this->addIndentation();
95 }
96
97 $node->compile($this);
98
99 return $this;
100 }
101
102 /**
103 * Adds a raw string to the compiled code.
104 *
105 * @param string $string The string
106 *
107 * @return Twig_Compiler The current compiler instance
108 */
109 public function raw($string)
110 {
111 $this->source .= $string;
112
113 return $this;
114 }
115
116 /**
117 * Writes a string to the compiled code by adding indentation.
118 *
119 * @return Twig_Compiler The current compiler instance
120 */
121 public function write()
122 {
123 $strings = func_get_args();
124 foreach ($strings as $string) {
125 $this->addIndentation();
126 $this->source .= $string;
127 }
128
129 return $this;
130 }
131
132 /**
133 * Appends an indentation to the current PHP code after compilation.
134 *
135 * @return Twig_Compiler The current compiler instance
136 */
137 public function addIndentation()
138 {
139 $this->source .= str_repeat(' ', $this->indentation * 4);
140
141 return $this;
142 }
143
144 /**
145 * Adds a quoted string to the compiled code.
146 *
147 * @param string $value The string
148 *
149 * @return Twig_Compiler The current compiler instance
150 */
151 public function string($value)
152 {
153 $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
154
155 return $this;
156 }
157
158 /**
159 * Returns a PHP representation of a given value.
160 *
161 * @param mixed $value The value to convert
162 *
163 * @return Twig_Compiler The current compiler instance
164 */
165 public function repr($value)
166 {
167 if (is_int($value) || is_float($value)) {
168 if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
169 setlocale(LC_NUMERIC, 'C');
170 }
171
172 $this->raw($value);
173
174 if (false !== $locale) {
175 setlocale(LC_NUMERIC, $locale);
176 }
177 } elseif (null === $value) {
178 $this->raw('null');
179 } elseif (is_bool($value)) {
180 $this->raw($value ? 'true' : 'false');
181 } elseif (is_array($value)) {
182 $this->raw('array(');
183 $i = 0;
184 foreach ($value as $key => $value) {
185 if ($i++) {
186 $this->raw(', ');
187 }
188 $this->repr($key);
189 $this->raw(' => ');
190 $this->repr($value);
191 }
192 $this->raw(')');
193 } else {
194 $this->string($value);
195 }
196
197 return $this;
198 }
199
200 /**
201 * Adds debugging information.
202 *
203 * @param Twig_NodeInterface $node The related twig node
204 *
205 * @return Twig_Compiler The current compiler instance
206 */
207 public function addDebugInfo(Twig_NodeInterface $node)
208 {
209 if ($node->getLine() != $this->lastLine) {
210 $this->write("// line {$node->getLine()}\n");
211
212 // when mbstring.func_overload is set to 2
213 // mb_substr_count() replaces substr_count()
214 // but they have different signatures!
215 if (((int) ini_get('mbstring.func_overload')) & 2) {
216 // this is much slower than the "right" version
217 $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
218 } else {
219 $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
220 }
221 $this->sourceOffset = strlen($this->source);
222 $this->debugInfo[$this->sourceLine] = $node->getLine();
223
224 $this->lastLine = $node->getLine();
225 }
226
227 return $this;
228 }
229
230 public function getDebugInfo()
231 {
232 return $this->debugInfo;
233 }
234
235 /**
236 * Indents the generated code.
237 *
238 * @param integer $step The number of indentation to add
239 *
240 * @return Twig_Compiler The current compiler instance
241 */
242 public function indent($step = 1)
243 {
244 $this->indentation += $step;
245
246 return $this;
247 }
248
249 /**
250 * Outdents the generated code.
251 *
252 * @param integer $step The number of indentation to remove
253 *
254 * @return Twig_Compiler The current compiler instance
255 */
256 public function outdent($step = 1)
257 {
258 // can't outdent by more steps than the current indentation level
259 if ($this->indentation < $step) {
260 throw new LogicException('Unable to call outdent() as the indentation would become negative');
261 }
262
263 $this->indentation -= $step;
264
265 return $this;
266 }
267}
diff --git a/vendor/twig/twig/lib/Twig/CompilerInterface.php b/vendor/twig/twig/lib/Twig/CompilerInterface.php
new file mode 100644
index 00000000..e293ec91
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/CompilerInterface.php
@@ -0,0 +1,35 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Interface implemented by compiler classes.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18interface Twig_CompilerInterface
19{
20 /**
21 * Compiles a node.
22 *
23 * @param Twig_NodeInterface $node The node to compile
24 *
25 * @return Twig_CompilerInterface The current compiler instance
26 */
27 public function compile(Twig_NodeInterface $node);
28
29 /**
30 * Gets the current PHP code after compilation.
31 *
32 * @return string The PHP code
33 */
34 public function getSource();
35}
diff --git a/vendor/twig/twig/lib/Twig/Environment.php b/vendor/twig/twig/lib/Twig/Environment.php
new file mode 100644
index 00000000..6d4c5c57
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Environment.php
@@ -0,0 +1,1224 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Stores the Twig configuration.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Environment
18{
19 const VERSION = '1.13.2';
20
21 protected $charset;
22 protected $loader;
23 protected $debug;
24 protected $autoReload;
25 protected $cache;
26 protected $lexer;
27 protected $parser;
28 protected $compiler;
29 protected $baseTemplateClass;
30 protected $extensions;
31 protected $parsers;
32 protected $visitors;
33 protected $filters;
34 protected $tests;
35 protected $functions;
36 protected $globals;
37 protected $runtimeInitialized;
38 protected $extensionInitialized;
39 protected $loadedTemplates;
40 protected $strictVariables;
41 protected $unaryOperators;
42 protected $binaryOperators;
43 protected $templateClassPrefix = '__TwigTemplate_';
44 protected $functionCallbacks;
45 protected $filterCallbacks;
46 protected $staging;
47
48 /**
49 * Constructor.
50 *
51 * Available options:
52 *
53 * * debug: When set to true, it automatically set "auto_reload" to true as
54 * well (default to false).
55 *
56 * * charset: The charset used by the templates (default to UTF-8).
57 *
58 * * base_template_class: The base template class to use for generated
59 * templates (default to Twig_Template).
60 *
61 * * cache: An absolute path where to store the compiled templates, or
62 * false to disable compilation cache (default).
63 *
64 * * auto_reload: Whether to reload the template is the original source changed.
65 * If you don't provide the auto_reload option, it will be
66 * determined automatically base on the debug value.
67 *
68 * * strict_variables: Whether to ignore invalid variables in templates
69 * (default to false).
70 *
71 * * autoescape: Whether to enable auto-escaping (default to html):
72 * * false: disable auto-escaping
73 * * true: equivalent to html
74 * * html, js: set the autoescaping to one of the supported strategies
75 * * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
76 *
77 * * optimizations: A flag that indicates which optimizations to apply
78 * (default to -1 which means that all optimizations are enabled;
79 * set it to 0 to disable).
80 *
81 * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
82 * @param array $options An array of options
83 */
84 public function __construct(Twig_LoaderInterface $loader = null, $options = array())
85 {
86 if (null !== $loader) {
87 $this->setLoader($loader);
88 }
89
90 $options = array_merge(array(
91 'debug' => false,
92 'charset' => 'UTF-8',
93 'base_template_class' => 'Twig_Template',
94 'strict_variables' => false,
95 'autoescape' => 'html',
96 'cache' => false,
97 'auto_reload' => null,
98 'optimizations' => -1,
99 ), $options);
100
101 $this->debug = (bool) $options['debug'];
102 $this->charset = strtoupper($options['charset']);
103 $this->baseTemplateClass = $options['base_template_class'];
104 $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
105 $this->strictVariables = (bool) $options['strict_variables'];
106 $this->runtimeInitialized = false;
107 $this->setCache($options['cache']);
108 $this->functionCallbacks = array();
109 $this->filterCallbacks = array();
110
111 $this->addExtension(new Twig_Extension_Core());
112 $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
113 $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
114 $this->extensionInitialized = false;
115 $this->staging = new Twig_Extension_Staging();
116 }
117
118 /**
119 * Gets the base template class for compiled templates.
120 *
121 * @return string The base template class name
122 */
123 public function getBaseTemplateClass()
124 {
125 return $this->baseTemplateClass;
126 }
127
128 /**
129 * Sets the base template class for compiled templates.
130 *
131 * @param string $class The base template class name
132 */
133 public function setBaseTemplateClass($class)
134 {
135 $this->baseTemplateClass = $class;
136 }
137
138 /**
139 * Enables debugging mode.
140 */
141 public function enableDebug()
142 {
143 $this->debug = true;
144 }
145
146 /**
147 * Disables debugging mode.
148 */
149 public function disableDebug()
150 {
151 $this->debug = false;
152 }
153
154 /**
155 * Checks if debug mode is enabled.
156 *
157 * @return Boolean true if debug mode is enabled, false otherwise
158 */
159 public function isDebug()
160 {
161 return $this->debug;
162 }
163
164 /**
165 * Enables the auto_reload option.
166 */
167 public function enableAutoReload()
168 {
169 $this->autoReload = true;
170 }
171
172 /**
173 * Disables the auto_reload option.
174 */
175 public function disableAutoReload()
176 {
177 $this->autoReload = false;
178 }
179
180 /**
181 * Checks if the auto_reload option is enabled.
182 *
183 * @return Boolean true if auto_reload is enabled, false otherwise
184 */
185 public function isAutoReload()
186 {
187 return $this->autoReload;
188 }
189
190 /**
191 * Enables the strict_variables option.
192 */
193 public function enableStrictVariables()
194 {
195 $this->strictVariables = true;
196 }
197
198 /**
199 * Disables the strict_variables option.
200 */
201 public function disableStrictVariables()
202 {
203 $this->strictVariables = false;
204 }
205
206 /**
207 * Checks if the strict_variables option is enabled.
208 *
209 * @return Boolean true if strict_variables is enabled, false otherwise
210 */
211 public function isStrictVariables()
212 {
213 return $this->strictVariables;
214 }
215
216 /**
217 * Gets the cache directory or false if cache is disabled.
218 *
219 * @return string|false
220 */
221 public function getCache()
222 {
223 return $this->cache;
224 }
225
226 /**
227 * Sets the cache directory or false if cache is disabled.
228 *
229 * @param string|false $cache The absolute path to the compiled templates,
230 * or false to disable cache
231 */
232 public function setCache($cache)
233 {
234 $this->cache = $cache ? $cache : false;
235 }
236
237 /**
238 * Gets the cache filename for a given template.
239 *
240 * @param string $name The template name
241 *
242 * @return string The cache file name
243 */
244 public function getCacheFilename($name)
245 {
246 if (false === $this->cache) {
247 return false;
248 }
249
250 $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
251
252 return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php';
253 }
254
255 /**
256 * Gets the template class associated with the given string.
257 *
258 * @param string $name The name for which to calculate the template class name
259 * @param integer $index The index if it is an embedded template
260 *
261 * @return string The template class name
262 */
263 public function getTemplateClass($name, $index = null)
264 {
265 return $this->templateClassPrefix.md5($this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index);
266 }
267
268 /**
269 * Gets the template class prefix.
270 *
271 * @return string The template class prefix
272 */
273 public function getTemplateClassPrefix()
274 {
275 return $this->templateClassPrefix;
276 }
277
278 /**
279 * Renders a template.
280 *
281 * @param string $name The template name
282 * @param array $context An array of parameters to pass to the template
283 *
284 * @return string The rendered template
285 */
286 public function render($name, array $context = array())
287 {
288 return $this->loadTemplate($name)->render($context);
289 }
290
291 /**
292 * Displays a template.
293 *
294 * @param string $name The template name
295 * @param array $context An array of parameters to pass to the template
296 */
297 public function display($name, array $context = array())
298 {
299 $this->loadTemplate($name)->display($context);
300 }
301
302 /**
303 * Loads a template by name.
304 *
305 * @param string $name The template name
306 * @param integer $index The index if it is an embedded template
307 *
308 * @return Twig_TemplateInterface A template instance representing the given template name
309 */
310 public function loadTemplate($name, $index = null)
311 {
312 $cls = $this->getTemplateClass($name, $index);
313
314 if (isset($this->loadedTemplates[$cls])) {
315 return $this->loadedTemplates[$cls];
316 }
317
318 if (!class_exists($cls, false)) {
319 if (false === $cache = $this->getCacheFilename($name)) {
320 eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name));
321 } else {
322 if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) {
323 $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name));
324 }
325
326 require_once $cache;
327 }
328 }
329
330 if (!$this->runtimeInitialized) {
331 $this->initRuntime();
332 }
333
334 return $this->loadedTemplates[$cls] = new $cls($this);
335 }
336
337 /**
338 * Returns true if the template is still fresh.
339 *
340 * Besides checking the loader for freshness information,
341 * this method also checks if the enabled extensions have
342 * not changed.
343 *
344 * @param string $name The template name
345 * @param timestamp $time The last modification time of the cached template
346 *
347 * @return Boolean true if the template is fresh, false otherwise
348 */
349 public function isTemplateFresh($name, $time)
350 {
351 foreach ($this->extensions as $extension) {
352 $r = new ReflectionObject($extension);
353 if (filemtime($r->getFileName()) > $time) {
354 return false;
355 }
356 }
357
358 return $this->getLoader()->isFresh($name, $time);
359 }
360
361 public function resolveTemplate($names)
362 {
363 if (!is_array($names)) {
364 $names = array($names);
365 }
366
367 foreach ($names as $name) {
368 if ($name instanceof Twig_Template) {
369 return $name;
370 }
371
372 try {
373 return $this->loadTemplate($name);
374 } catch (Twig_Error_Loader $e) {
375 }
376 }
377
378 if (1 === count($names)) {
379 throw $e;
380 }
381
382 throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
383 }
384
385 /**
386 * Clears the internal template cache.
387 */
388 public function clearTemplateCache()
389 {
390 $this->loadedTemplates = array();
391 }
392
393 /**
394 * Clears the template cache files on the filesystem.
395 */
396 public function clearCacheFiles()
397 {
398 if (false === $this->cache) {
399 return;
400 }
401
402 foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
403 if ($file->isFile()) {
404 @unlink($file->getPathname());
405 }
406 }
407 }
408
409 /**
410 * Gets the Lexer instance.
411 *
412 * @return Twig_LexerInterface A Twig_LexerInterface instance
413 */
414 public function getLexer()
415 {
416 if (null === $this->lexer) {
417 $this->lexer = new Twig_Lexer($this);
418 }
419
420 return $this->lexer;
421 }
422
423 /**
424 * Sets the Lexer instance.
425 *
426 * @param Twig_LexerInterface A Twig_LexerInterface instance
427 */
428 public function setLexer(Twig_LexerInterface $lexer)
429 {
430 $this->lexer = $lexer;
431 }
432
433 /**
434 * Tokenizes a source code.
435 *
436 * @param string $source The template source code
437 * @param string $name The template name
438 *
439 * @return Twig_TokenStream A Twig_TokenStream instance
440 */
441 public function tokenize($source, $name = null)
442 {
443 return $this->getLexer()->tokenize($source, $name);
444 }
445
446 /**
447 * Gets the Parser instance.
448 *
449 * @return Twig_ParserInterface A Twig_ParserInterface instance
450 */
451 public function getParser()
452 {
453 if (null === $this->parser) {
454 $this->parser = new Twig_Parser($this);
455 }
456
457 return $this->parser;
458 }
459
460 /**
461 * Sets the Parser instance.
462 *
463 * @param Twig_ParserInterface A Twig_ParserInterface instance
464 */
465 public function setParser(Twig_ParserInterface $parser)
466 {
467 $this->parser = $parser;
468 }
469
470 /**
471 * Parses a token stream.
472 *
473 * @param Twig_TokenStream $tokens A Twig_TokenStream instance
474 *
475 * @return Twig_Node_Module A Node tree
476 */
477 public function parse(Twig_TokenStream $tokens)
478 {
479 return $this->getParser()->parse($tokens);
480 }
481
482 /**
483 * Gets the Compiler instance.
484 *
485 * @return Twig_CompilerInterface A Twig_CompilerInterface instance
486 */
487 public function getCompiler()
488 {
489 if (null === $this->compiler) {
490 $this->compiler = new Twig_Compiler($this);
491 }
492
493 return $this->compiler;
494 }
495
496 /**
497 * Sets the Compiler instance.
498 *
499 * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance
500 */
501 public function setCompiler(Twig_CompilerInterface $compiler)
502 {
503 $this->compiler = $compiler;
504 }
505
506 /**
507 * Compiles a Node.
508 *
509 * @param Twig_NodeInterface $node A Twig_NodeInterface instance
510 *
511 * @return string The compiled PHP source code
512 */
513 public function compile(Twig_NodeInterface $node)
514 {
515 return $this->getCompiler()->compile($node)->getSource();
516 }
517
518 /**
519 * Compiles a template source code.
520 *
521 * @param string $source The template source code
522 * @param string $name The template name
523 *
524 * @return string The compiled PHP source code
525 */
526 public function compileSource($source, $name = null)
527 {
528 try {
529 return $this->compile($this->parse($this->tokenize($source, $name)));
530 } catch (Twig_Error $e) {
531 $e->setTemplateFile($name);
532 throw $e;
533 } catch (Exception $e) {
534 throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e);
535 }
536 }
537
538 /**
539 * Sets the Loader instance.
540 *
541 * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
542 */
543 public function setLoader(Twig_LoaderInterface $loader)
544 {
545 $this->loader = $loader;
546 }
547
548 /**
549 * Gets the Loader instance.
550 *
551 * @return Twig_LoaderInterface A Twig_LoaderInterface instance
552 */
553 public function getLoader()
554 {
555 if (null === $this->loader) {
556 throw new LogicException('You must set a loader first.');
557 }
558
559 return $this->loader;
560 }
561
562 /**
563 * Sets the default template charset.
564 *
565 * @param string $charset The default charset
566 */
567 public function setCharset($charset)
568 {
569 $this->charset = strtoupper($charset);
570 }
571
572 /**
573 * Gets the default template charset.
574 *
575 * @return string The default charset
576 */
577 public function getCharset()
578 {
579 return $this->charset;
580 }
581
582 /**
583 * Initializes the runtime environment.
584 */
585 public function initRuntime()
586 {
587 $this->runtimeInitialized = true;
588
589 foreach ($this->getExtensions() as $extension) {
590 $extension->initRuntime($this);
591 }
592 }
593
594 /**
595 * Returns true if the given extension is registered.
596 *
597 * @param string $name The extension name
598 *
599 * @return Boolean Whether the extension is registered or not
600 */
601 public function hasExtension($name)
602 {
603 return isset($this->extensions[$name]);
604 }
605
606 /**
607 * Gets an extension by name.
608 *
609 * @param string $name The extension name
610 *
611 * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
612 */
613 public function getExtension($name)
614 {
615 if (!isset($this->extensions[$name])) {
616 throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name));
617 }
618
619 return $this->extensions[$name];
620 }
621
622 /**
623 * Registers an extension.
624 *
625 * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
626 */
627 public function addExtension(Twig_ExtensionInterface $extension)
628 {
629 if ($this->extensionInitialized) {
630 throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
631 }
632
633 $this->extensions[$extension->getName()] = $extension;
634 }
635
636 /**
637 * Removes an extension by name.
638 *
639 * This method is deprecated and you should not use it.
640 *
641 * @param string $name The extension name
642 *
643 * @deprecated since 1.12 (to be removed in 2.0)
644 */
645 public function removeExtension($name)
646 {
647 if ($this->extensionInitialized) {
648 throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
649 }
650
651 unset($this->extensions[$name]);
652 }
653
654 /**
655 * Registers an array of extensions.
656 *
657 * @param array $extensions An array of extensions
658 */
659 public function setExtensions(array $extensions)
660 {
661 foreach ($extensions as $extension) {
662 $this->addExtension($extension);
663 }
664 }
665
666 /**
667 * Returns all registered extensions.
668 *
669 * @return array An array of extensions
670 */
671 public function getExtensions()
672 {
673 return $this->extensions;
674 }
675
676 /**
677 * Registers a Token Parser.
678 *
679 * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
680 */
681 public function addTokenParser(Twig_TokenParserInterface $parser)
682 {
683 if ($this->extensionInitialized) {
684 throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
685 }
686
687 $this->staging->addTokenParser($parser);
688 }
689
690 /**
691 * Gets the registered Token Parsers.
692 *
693 * @return Twig_TokenParserBrokerInterface A broker containing token parsers
694 */
695 public function getTokenParsers()
696 {
697 if (!$this->extensionInitialized) {
698 $this->initExtensions();
699 }
700
701 return $this->parsers;
702 }
703
704 /**
705 * Gets registered tags.
706 *
707 * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
708 *
709 * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
710 */
711 public function getTags()
712 {
713 $tags = array();
714 foreach ($this->getTokenParsers()->getParsers() as $parser) {
715 if ($parser instanceof Twig_TokenParserInterface) {
716 $tags[$parser->getTag()] = $parser;
717 }
718 }
719
720 return $tags;
721 }
722
723 /**
724 * Registers a Node Visitor.
725 *
726 * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
727 */
728 public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
729 {
730 if ($this->extensionInitialized) {
731 throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
732 }
733
734 $this->staging->addNodeVisitor($visitor);
735 }
736
737 /**
738 * Gets the registered Node Visitors.
739 *
740 * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
741 */
742 public function getNodeVisitors()
743 {
744 if (!$this->extensionInitialized) {
745 $this->initExtensions();
746 }
747
748 return $this->visitors;
749 }
750
751 /**
752 * Registers a Filter.
753 *
754 * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance
755 * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance
756 */
757 public function addFilter($name, $filter = null)
758 {
759 if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
760 throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter');
761 }
762
763 if ($name instanceof Twig_SimpleFilter) {
764 $filter = $name;
765 $name = $filter->getName();
766 }
767
768 if ($this->extensionInitialized) {
769 throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
770 }
771
772 $this->staging->addFilter($name, $filter);
773 }
774
775 /**
776 * Get a filter by name.
777 *
778 * Subclasses may override this method and load filters differently;
779 * so no list of filters is available.
780 *
781 * @param string $name The filter name
782 *
783 * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
784 */
785 public function getFilter($name)
786 {
787 if (!$this->extensionInitialized) {
788 $this->initExtensions();
789 }
790
791 if (isset($this->filters[$name])) {
792 return $this->filters[$name];
793 }
794
795 foreach ($this->filters as $pattern => $filter) {
796 $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
797
798 if ($count) {
799 if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
800 array_shift($matches);
801 $filter->setArguments($matches);
802
803 return $filter;
804 }
805 }
806 }
807
808 foreach ($this->filterCallbacks as $callback) {
809 if (false !== $filter = call_user_func($callback, $name)) {
810 return $filter;
811 }
812 }
813
814 return false;
815 }
816
817 public function registerUndefinedFilterCallback($callable)
818 {
819 $this->filterCallbacks[] = $callable;
820 }
821
822 /**
823 * Gets the registered Filters.
824 *
825 * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback.
826 *
827 * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances
828 *
829 * @see registerUndefinedFilterCallback
830 */
831 public function getFilters()
832 {
833 if (!$this->extensionInitialized) {
834 $this->initExtensions();
835 }
836
837 return $this->filters;
838 }
839
840 /**
841 * Registers a Test.
842 *
843 * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance
844 * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance
845 */
846 public function addTest($name, $test = null)
847 {
848 if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) {
849 throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest');
850 }
851
852 if ($name instanceof Twig_SimpleTest) {
853 $test = $name;
854 $name = $test->getName();
855 }
856
857 if ($this->extensionInitialized) {
858 throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
859 }
860
861 $this->staging->addTest($name, $test);
862 }
863
864 /**
865 * Gets the registered Tests.
866 *
867 * @return Twig_TestInterface[] An array of Twig_TestInterface instances
868 */
869 public function getTests()
870 {
871 if (!$this->extensionInitialized) {
872 $this->initExtensions();
873 }
874
875 return $this->tests;
876 }
877
878 /**
879 * Gets a test by name.
880 *
881 * @param string $name The test name
882 *
883 * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
884 */
885 public function getTest($name)
886 {
887 if (!$this->extensionInitialized) {
888 $this->initExtensions();
889 }
890
891 if (isset($this->tests[$name])) {
892 return $this->tests[$name];
893 }
894
895 return false;
896 }
897
898 /**
899 * Registers a Function.
900 *
901 * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance
902 * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance
903 */
904 public function addFunction($name, $function = null)
905 {
906 if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) {
907 throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction');
908 }
909
910 if ($name instanceof Twig_SimpleFunction) {
911 $function = $name;
912 $name = $function->getName();
913 }
914
915 if ($this->extensionInitialized) {
916 throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
917 }
918
919 $this->staging->addFunction($name, $function);
920 }
921
922 /**
923 * Get a function by name.
924 *
925 * Subclasses may override this method and load functions differently;
926 * so no list of functions is available.
927 *
928 * @param string $name function name
929 *
930 * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
931 */
932 public function getFunction($name)
933 {
934 if (!$this->extensionInitialized) {
935 $this->initExtensions();
936 }
937
938 if (isset($this->functions[$name])) {
939 return $this->functions[$name];
940 }
941
942 foreach ($this->functions as $pattern => $function) {
943 $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
944
945 if ($count) {
946 if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
947 array_shift($matches);
948 $function->setArguments($matches);
949
950 return $function;
951 }
952 }
953 }
954
955 foreach ($this->functionCallbacks as $callback) {
956 if (false !== $function = call_user_func($callback, $name)) {
957 return $function;
958 }
959 }
960
961 return false;
962 }
963
964 public function registerUndefinedFunctionCallback($callable)
965 {
966 $this->functionCallbacks[] = $callable;
967 }
968
969 /**
970 * Gets registered functions.
971 *
972 * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
973 *
974 * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances
975 *
976 * @see registerUndefinedFunctionCallback
977 */
978 public function getFunctions()
979 {
980 if (!$this->extensionInitialized) {
981 $this->initExtensions();
982 }
983
984 return $this->functions;
985 }
986
987 /**
988 * Registers a Global.
989 *
990 * New globals can be added before compiling or rendering a template;
991 * but after, you can only update existing globals.
992 *
993 * @param string $name The global name
994 * @param mixed $value The global value
995 */
996 public function addGlobal($name, $value)
997 {
998 if ($this->extensionInitialized || $this->runtimeInitialized) {
999 if (null === $this->globals) {
1000 $this->globals = $this->initGlobals();
1001 }
1002
1003 /* This condition must be uncommented in Twig 2.0
1004 if (!array_key_exists($name, $this->globals)) {
1005 throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
1006 }
1007 */
1008 }
1009
1010 if ($this->extensionInitialized || $this->runtimeInitialized) {
1011 // update the value
1012 $this->globals[$name] = $value;
1013 } else {
1014 $this->staging->addGlobal($name, $value);
1015 }
1016 }
1017
1018 /**
1019 * Gets the registered Globals.
1020 *
1021 * @return array An array of globals
1022 */
1023 public function getGlobals()
1024 {
1025 if (!$this->runtimeInitialized && !$this->extensionInitialized) {
1026 return $this->initGlobals();
1027 }
1028
1029 if (null === $this->globals) {
1030 $this->globals = $this->initGlobals();
1031 }
1032
1033 return $this->globals;
1034 }
1035
1036 /**
1037 * Merges a context with the defined globals.
1038 *
1039 * @param array $context An array representing the context
1040 *
1041 * @return array The context merged with the globals
1042 */
1043 public function mergeGlobals(array $context)
1044 {
1045 // we don't use array_merge as the context being generally
1046 // bigger than globals, this code is faster.
1047 foreach ($this->getGlobals() as $key => $value) {
1048 if (!array_key_exists($key, $context)) {
1049 $context[$key] = $value;
1050 }
1051 }
1052
1053 return $context;
1054 }
1055
1056 /**
1057 * Gets the registered unary Operators.
1058 *
1059 * @return array An array of unary operators
1060 */
1061 public function getUnaryOperators()
1062 {
1063 if (!$this->extensionInitialized) {
1064 $this->initExtensions();
1065 }
1066
1067 return $this->unaryOperators;
1068 }
1069
1070 /**
1071 * Gets the registered binary Operators.
1072 *
1073 * @return array An array of binary operators
1074 */
1075 public function getBinaryOperators()
1076 {
1077 if (!$this->extensionInitialized) {
1078 $this->initExtensions();
1079 }
1080
1081 return $this->binaryOperators;
1082 }
1083
1084 public function computeAlternatives($name, $items)
1085 {
1086 $alternatives = array();
1087 foreach ($items as $item) {
1088 $lev = levenshtein($name, $item);
1089 if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
1090 $alternatives[$item] = $lev;
1091 }
1092 }
1093 asort($alternatives);
1094
1095 return array_keys($alternatives);
1096 }
1097
1098 protected function initGlobals()
1099 {
1100 $globals = array();
1101 foreach ($this->extensions as $extension) {
1102 $extGlob = $extension->getGlobals();
1103 if (!is_array($extGlob)) {
1104 throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
1105 }
1106
1107 $globals[] = $extGlob;
1108 }
1109
1110 $globals[] = $this->staging->getGlobals();
1111
1112 return call_user_func_array('array_merge', $globals);
1113 }
1114
1115 protected function initExtensions()
1116 {
1117 if ($this->extensionInitialized) {
1118 return;
1119 }
1120
1121 $this->extensionInitialized = true;
1122 $this->parsers = new Twig_TokenParserBroker();
1123 $this->filters = array();
1124 $this->functions = array();
1125 $this->tests = array();
1126 $this->visitors = array();
1127 $this->unaryOperators = array();
1128 $this->binaryOperators = array();
1129
1130 foreach ($this->extensions as $extension) {
1131 $this->initExtension($extension);
1132 }
1133 $this->initExtension($this->staging);
1134 }
1135
1136 protected function initExtension(Twig_ExtensionInterface $extension)
1137 {
1138 // filters
1139 foreach ($extension->getFilters() as $name => $filter) {
1140 if ($name instanceof Twig_SimpleFilter) {
1141 $filter = $name;
1142 $name = $filter->getName();
1143 } elseif ($filter instanceof Twig_SimpleFilter) {
1144 $name = $filter->getName();
1145 }
1146
1147 $this->filters[$name] = $filter;
1148 }
1149
1150 // functions
1151 foreach ($extension->getFunctions() as $name => $function) {
1152 if ($name instanceof Twig_SimpleFunction) {
1153 $function = $name;
1154 $name = $function->getName();
1155 } elseif ($function instanceof Twig_SimpleFunction) {
1156 $name = $function->getName();
1157 }
1158
1159 $this->functions[$name] = $function;
1160 }
1161
1162 // tests
1163 foreach ($extension->getTests() as $name => $test) {
1164 if ($name instanceof Twig_SimpleTest) {
1165 $test = $name;
1166 $name = $test->getName();
1167 } elseif ($test instanceof Twig_SimpleTest) {
1168 $name = $test->getName();
1169 }
1170
1171 $this->tests[$name] = $test;
1172 }
1173
1174 // token parsers
1175 foreach ($extension->getTokenParsers() as $parser) {
1176 if ($parser instanceof Twig_TokenParserInterface) {
1177 $this->parsers->addTokenParser($parser);
1178 } elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
1179 $this->parsers->addTokenParserBroker($parser);
1180 } else {
1181 throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
1182 }
1183 }
1184
1185 // node visitors
1186 foreach ($extension->getNodeVisitors() as $visitor) {
1187 $this->visitors[] = $visitor;
1188 }
1189
1190 // operators
1191 if ($operators = $extension->getOperators()) {
1192 if (2 !== count($operators)) {
1193 throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
1194 }
1195
1196 $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
1197 $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
1198 }
1199 }
1200
1201 protected function writeCacheFile($file, $content)
1202 {
1203 $dir = dirname($file);
1204 if (!is_dir($dir)) {
1205 if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
1206 throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir));
1207 }
1208 } elseif (!is_writable($dir)) {
1209 throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir));
1210 }
1211
1212 $tmpFile = tempnam(dirname($file), basename($file));
1213 if (false !== @file_put_contents($tmpFile, $content)) {
1214 // rename does not work on Win32 before 5.2.6
1215 if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) {
1216 @chmod($file, 0666 & ~umask());
1217
1218 return;
1219 }
1220 }
1221
1222 throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
1223 }
1224}
diff --git a/vendor/twig/twig/lib/Twig/Error.php b/vendor/twig/twig/lib/Twig/Error.php
new file mode 100644
index 00000000..61a4cfa0
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Error.php
@@ -0,0 +1,243 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Twig base exception.
14 *
15 * This exception class and its children must only be used when
16 * an error occurs during the loading of a template, when a syntax error
17 * is detected in a template, or when rendering a template. Other
18 * errors must use regular PHP exception classes (like when the template
19 * cache directory is not writable for instance).
20 *
21 * To help debugging template issues, this class tracks the original template
22 * name and line where the error occurred.
23 *
24 * Whenever possible, you must set these information (original template name
25 * and line number) yourself by passing them to the constructor. If some or all
26 * these information are not available from where you throw the exception, then
27 * this class will guess them automatically (when the line number is set to -1
28 * and/or the filename is set to null). As this is a costly operation, this
29 * can be disabled by passing false for both the filename and the line number
30 * when creating a new instance of this class.
31 *
32 * @author Fabien Potencier <fabien@symfony.com>
33 */
34class Twig_Error extends Exception
35{
36 protected $lineno;
37 protected $filename;
38 protected $rawMessage;
39 protected $previous;
40
41 /**
42 * Constructor.
43 *
44 * Set both the line number and the filename to false to
45 * disable automatic guessing of the original template name
46 * and line number.
47 *
48 * Set the line number to -1 to enable its automatic guessing.
49 * Set the filename to null to enable its automatic guessing.
50 *
51 * By default, automatic guessing is enabled.
52 *
53 * @param string $message The error message
54 * @param integer $lineno The template line where the error occurred
55 * @param string $filename The template file name where the error occurred
56 * @param Exception $previous The previous exception
57 */
58 public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
59 {
60 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
61 $this->previous = $previous;
62 parent::__construct('');
63 } else {
64 parent::__construct('', 0, $previous);
65 }
66
67 $this->lineno = $lineno;
68 $this->filename = $filename;
69
70 if (-1 === $this->lineno || null === $this->filename) {
71 $this->guessTemplateInfo();
72 }
73
74 $this->rawMessage = $message;
75
76 $this->updateRepr();
77 }
78
79 /**
80 * Gets the raw message.
81 *
82 * @return string The raw message
83 */
84 public function getRawMessage()
85 {
86 return $this->rawMessage;
87 }
88
89 /**
90 * Gets the filename where the error occurred.
91 *
92 * @return string The filename
93 */
94 public function getTemplateFile()
95 {
96 return $this->filename;
97 }
98
99 /**
100 * Sets the filename where the error occurred.
101 *
102 * @param string $filename The filename
103 */
104 public function setTemplateFile($filename)
105 {
106 $this->filename = $filename;
107
108 $this->updateRepr();
109 }
110
111 /**
112 * Gets the template line where the error occurred.
113 *
114 * @return integer The template line
115 */
116 public function getTemplateLine()
117 {
118 return $this->lineno;
119 }
120
121 /**
122 * Sets the template line where the error occurred.
123 *
124 * @param integer $lineno The template line
125 */
126 public function setTemplateLine($lineno)
127 {
128 $this->lineno = $lineno;
129
130 $this->updateRepr();
131 }
132
133 public function guess()
134 {
135 $this->guessTemplateInfo();
136 $this->updateRepr();
137 }
138
139 /**
140 * For PHP < 5.3.0, provides access to the getPrevious() method.
141 *
142 * @param string $method The method name
143 * @param array $arguments The parameters to be passed to the method
144 *
145 * @return Exception The previous exception or null
146 *
147 * @throws BadMethodCallException
148 */
149 public function __call($method, $arguments)
150 {
151 if ('getprevious' == strtolower($method)) {
152 return $this->previous;
153 }
154
155 throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
156 }
157
158 protected function updateRepr()
159 {
160 $this->message = $this->rawMessage;
161
162 $dot = false;
163 if ('.' === substr($this->message, -1)) {
164 $this->message = substr($this->message, 0, -1);
165 $dot = true;
166 }
167
168 if ($this->filename) {
169 if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
170 $filename = sprintf('"%s"', $this->filename);
171 } else {
172 $filename = json_encode($this->filename);
173 }
174 $this->message .= sprintf(' in %s', $filename);
175 }
176
177 if ($this->lineno && $this->lineno >= 0) {
178 $this->message .= sprintf(' at line %d', $this->lineno);
179 }
180
181 if ($dot) {
182 $this->message .= '.';
183 }
184 }
185
186 protected function guessTemplateInfo()
187 {
188 $template = null;
189 $templateClass = null;
190
191 if (version_compare(phpversion(), '5.3.6', '>=')) {
192 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
193 } else {
194 $backtrace = debug_backtrace();
195 }
196
197 foreach ($backtrace as $trace) {
198 if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
199 $currentClass = get_class($trace['object']);
200 $isEmbedContainer = 0 === strpos($templateClass, $currentClass);
201 if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
202 $template = $trace['object'];
203 $templateClass = get_class($trace['object']);
204 }
205 }
206 }
207
208 // update template filename
209 if (null !== $template && null === $this->filename) {
210 $this->filename = $template->getTemplateName();
211 }
212
213 if (null === $template || $this->lineno > -1) {
214 return;
215 }
216
217 $r = new ReflectionObject($template);
218 $file = $r->getFileName();
219
220 $exceptions = array($e = $this);
221 while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
222 $exceptions[] = $e;
223 }
224
225 while ($e = array_pop($exceptions)) {
226 $traces = $e->getTrace();
227 while ($trace = array_shift($traces)) {
228 if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
229 continue;
230 }
231
232 foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
233 if ($codeLine <= $trace['line']) {
234 // update template line
235 $this->lineno = $templateLine;
236
237 return;
238 }
239 }
240 }
241 }
242 }
243}
diff --git a/vendor/twig/twig/lib/Twig/Error/Loader.php b/vendor/twig/twig/lib/Twig/Error/Loader.php
new file mode 100644
index 00000000..68efb574
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Error/Loader.php
@@ -0,0 +1,31 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Exception thrown when an error occurs during template loading.
14 *
15 * Automatic template information guessing is always turned off as
16 * if a template cannot be loaded, there is nothing to guess.
17 * However, when a template is loaded from another one, then, we need
18 * to find the current context and this is automatically done by
19 * Twig_Template::displayWithErrorHandling().
20 *
21 * This strategy makes Twig_Environment::resolveTemplate() much faster.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 */
25class Twig_Error_Loader extends Twig_Error
26{
27 public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
28 {
29 parent::__construct($message, false, false, $previous);
30 }
31}
diff --git a/vendor/twig/twig/lib/Twig/Error/Runtime.php b/vendor/twig/twig/lib/Twig/Error/Runtime.php
new file mode 100644
index 00000000..8b6ceddb
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Error/Runtime.php
@@ -0,0 +1,20 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Exception thrown when an error occurs at runtime.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Error_Runtime extends Twig_Error
19{
20}
diff --git a/vendor/twig/twig/lib/Twig/Error/Syntax.php b/vendor/twig/twig/lib/Twig/Error/Syntax.php
new file mode 100644
index 00000000..0f5c5792
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Error/Syntax.php
@@ -0,0 +1,20 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Exception thrown when a syntax error occurs during lexing or parsing of a template.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Error_Syntax extends Twig_Error
19{
20}
diff --git a/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php b/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php
new file mode 100644
index 00000000..ce434765
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Adds an exists() method for loaders.
14 *
15 * @author Florin Patan <florinpatan@gmail.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18interface Twig_ExistsLoaderInterface
19{
20 /**
21 * Check if we have the source code of a template, given its name.
22 *
23 * @param string $name The name of the template to check if we can load
24 *
25 * @return boolean If the template source code is handled by this loader or not
26 */
27 public function exists($name);
28}
diff --git a/vendor/twig/twig/lib/Twig/ExpressionParser.php b/vendor/twig/twig/lib/Twig/ExpressionParser.php
new file mode 100644
index 00000000..9cf19344
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/ExpressionParser.php
@@ -0,0 +1,600 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Parses expressions.
15 *
16 * This parser implements a "Precedence climbing" algorithm.
17 *
18 * @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
19 * @see http://en.wikipedia.org/wiki/Operator-precedence_parser
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 */
23class Twig_ExpressionParser
24{
25 const OPERATOR_LEFT = 1;
26 const OPERATOR_RIGHT = 2;
27
28 protected $parser;
29 protected $unaryOperators;
30 protected $binaryOperators;
31
32 public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
33 {
34 $this->parser = $parser;
35 $this->unaryOperators = $unaryOperators;
36 $this->binaryOperators = $binaryOperators;
37 }
38
39 public function parseExpression($precedence = 0)
40 {
41 $expr = $this->getPrimary();
42 $token = $this->parser->getCurrentToken();
43 while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
44 $op = $this->binaryOperators[$token->getValue()];
45 $this->parser->getStream()->next();
46
47 if (isset($op['callable'])) {
48 $expr = call_user_func($op['callable'], $this->parser, $expr);
49 } else {
50 $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
51 $class = $op['class'];
52 $expr = new $class($expr, $expr1, $token->getLine());
53 }
54
55 $token = $this->parser->getCurrentToken();
56 }
57
58 if (0 === $precedence) {
59 return $this->parseConditionalExpression($expr);
60 }
61
62 return $expr;
63 }
64
65 protected function getPrimary()
66 {
67 $token = $this->parser->getCurrentToken();
68
69 if ($this->isUnary($token)) {
70 $operator = $this->unaryOperators[$token->getValue()];
71 $this->parser->getStream()->next();
72 $expr = $this->parseExpression($operator['precedence']);
73 $class = $operator['class'];
74
75 return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
76 } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
77 $this->parser->getStream()->next();
78 $expr = $this->parseExpression();
79 $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
80
81 return $this->parsePostfixExpression($expr);
82 }
83
84 return $this->parsePrimaryExpression();
85 }
86
87 protected function parseConditionalExpression($expr)
88 {
89 while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) {
90 $this->parser->getStream()->next();
91 if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
92 $expr2 = $this->parseExpression();
93 if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
94 $this->parser->getStream()->next();
95 $expr3 = $this->parseExpression();
96 } else {
97 $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
98 }
99 } else {
100 $this->parser->getStream()->next();
101 $expr2 = $expr;
102 $expr3 = $this->parseExpression();
103 }
104
105 $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
106 }
107
108 return $expr;
109 }
110
111 protected function isUnary(Twig_Token $token)
112 {
113 return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
114 }
115
116 protected function isBinary(Twig_Token $token)
117 {
118 return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
119 }
120
121 public function parsePrimaryExpression()
122 {
123 $token = $this->parser->getCurrentToken();
124 switch ($token->getType()) {
125 case Twig_Token::NAME_TYPE:
126 $this->parser->getStream()->next();
127 switch ($token->getValue()) {
128 case 'true':
129 case 'TRUE':
130 $node = new Twig_Node_Expression_Constant(true, $token->getLine());
131 break;
132
133 case 'false':
134 case 'FALSE':
135 $node = new Twig_Node_Expression_Constant(false, $token->getLine());
136 break;
137
138 case 'none':
139 case 'NONE':
140 case 'null':
141 case 'NULL':
142 $node = new Twig_Node_Expression_Constant(null, $token->getLine());
143 break;
144
145 default:
146 if ('(' === $this->parser->getCurrentToken()->getValue()) {
147 $node = $this->getFunctionNode($token->getValue(), $token->getLine());
148 } else {
149 $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
150 }
151 }
152 break;
153
154 case Twig_Token::NUMBER_TYPE:
155 $this->parser->getStream()->next();
156 $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
157 break;
158
159 case Twig_Token::STRING_TYPE:
160 case Twig_Token::INTERPOLATION_START_TYPE:
161 $node = $this->parseStringExpression();
162 break;
163
164 default:
165 if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
166 $node = $this->parseArrayExpression();
167 } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
168 $node = $this->parseHashExpression();
169 } else {
170 throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
171 }
172 }
173
174 return $this->parsePostfixExpression($node);
175 }
176
177 public function parseStringExpression()
178 {
179 $stream = $this->parser->getStream();
180
181 $nodes = array();
182 // a string cannot be followed by another string in a single expression
183 $nextCanBeString = true;
184 while (true) {
185 if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) {
186 $token = $stream->next();
187 $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
188 $nextCanBeString = false;
189 } elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) {
190 $stream->next();
191 $nodes[] = $this->parseExpression();
192 $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
193 $nextCanBeString = true;
194 } else {
195 break;
196 }
197 }
198
199 $expr = array_shift($nodes);
200 foreach ($nodes as $node) {
201 $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
202 }
203
204 return $expr;
205 }
206
207 public function parseArrayExpression()
208 {
209 $stream = $this->parser->getStream();
210 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
211
212 $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
213 $first = true;
214 while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
215 if (!$first) {
216 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
217
218 // trailing ,?
219 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
220 break;
221 }
222 }
223 $first = false;
224
225 $node->addElement($this->parseExpression());
226 }
227 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
228
229 return $node;
230 }
231
232 public function parseHashExpression()
233 {
234 $stream = $this->parser->getStream();
235 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
236
237 $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
238 $first = true;
239 while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
240 if (!$first) {
241 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
242
243 // trailing ,?
244 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
245 break;
246 }
247 }
248 $first = false;
249
250 // a hash key can be:
251 //
252 // * a number -- 12
253 // * a string -- 'a'
254 // * a name, which is equivalent to a string -- a
255 // * an expression, which must be enclosed in parentheses -- (1 + 2)
256 if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) {
257 $token = $stream->next();
258 $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
259 } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
260 $key = $this->parseExpression();
261 } else {
262 $current = $stream->getCurrent();
263
264 throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
265 }
266
267 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
268 $value = $this->parseExpression();
269
270 $node->addElement($value, $key);
271 }
272 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
273
274 return $node;
275 }
276
277 public function parsePostfixExpression($node)
278 {
279 while (true) {
280 $token = $this->parser->getCurrentToken();
281 if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
282 if ('.' == $token->getValue() || '[' == $token->getValue()) {
283 $node = $this->parseSubscriptExpression($node);
284 } elseif ('|' == $token->getValue()) {
285 $node = $this->parseFilterExpression($node);
286 } else {
287 break;
288 }
289 } else {
290 break;
291 }
292 }
293
294 return $node;
295 }
296
297 public function getFunctionNode($name, $line)
298 {
299 switch ($name) {
300 case 'parent':
301 $args = $this->parseArguments();
302 if (!count($this->parser->getBlockStack())) {
303 throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
304 }
305
306 if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
307 throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
308 }
309
310 return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
311 case 'block':
312 return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
313 case 'attribute':
314 $args = $this->parseArguments();
315 if (count($args) < 2) {
316 throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
317 }
318
319 return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line);
320 default:
321 if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
322 $arguments = new Twig_Node_Expression_Array(array(), $line);
323 foreach ($this->parseArguments() as $n) {
324 $arguments->addElement($n);
325 }
326
327 $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
328 $node->setAttribute('safe', true);
329
330 return $node;
331 }
332
333 $args = $this->parseArguments(true);
334 $class = $this->getFunctionNodeClass($name, $line);
335
336 return new $class($name, $args, $line);
337 }
338 }
339
340 public function parseSubscriptExpression($node)
341 {
342 $stream = $this->parser->getStream();
343 $token = $stream->next();
344 $lineno = $token->getLine();
345 $arguments = new Twig_Node_Expression_Array(array(), $lineno);
346 $type = Twig_TemplateInterface::ANY_CALL;
347 if ($token->getValue() == '.') {
348 $token = $stream->next();
349 if (
350 $token->getType() == Twig_Token::NAME_TYPE
351 ||
352 $token->getType() == Twig_Token::NUMBER_TYPE
353 ||
354 ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
355 ) {
356 $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
357
358 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
359 $type = Twig_TemplateInterface::METHOD_CALL;
360 foreach ($this->parseArguments() as $n) {
361 $arguments->addElement($n);
362 }
363 }
364 } else {
365 throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
366 }
367
368 if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
369 if (!$arg instanceof Twig_Node_Expression_Constant) {
370 throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
371 }
372
373 $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
374 $node->setAttribute('safe', true);
375
376 return $node;
377 }
378 } else {
379 $type = Twig_TemplateInterface::ARRAY_CALL;
380
381 // slice?
382 $slice = false;
383 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
384 $slice = true;
385 $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
386 } else {
387 $arg = $this->parseExpression();
388 }
389
390 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
391 $slice = true;
392 $stream->next();
393 }
394
395 if ($slice) {
396 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
397 $length = new Twig_Node_Expression_Constant(null, $token->getLine());
398 } else {
399 $length = $this->parseExpression();
400 }
401
402 $class = $this->getFilterNodeClass('slice', $token->getLine());
403 $arguments = new Twig_Node(array($arg, $length));
404 $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
405
406 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
407
408 return $filter;
409 }
410
411 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
412 }
413
414 return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
415 }
416
417 public function parseFilterExpression($node)
418 {
419 $this->parser->getStream()->next();
420
421 return $this->parseFilterExpressionRaw($node);
422 }
423
424 public function parseFilterExpressionRaw($node, $tag = null)
425 {
426 while (true) {
427 $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
428
429 $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
430 if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
431 $arguments = new Twig_Node();
432 } else {
433 $arguments = $this->parseArguments(true);
434 }
435
436 $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
437
438 $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
439
440 if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
441 break;
442 }
443
444 $this->parser->getStream()->next();
445 }
446
447 return $node;
448 }
449
450 /**
451 * Parses arguments.
452 *
453 * @param Boolean $namedArguments Whether to allow named arguments or not
454 * @param Boolean $definition Whether we are parsing arguments for a function definition
455 */
456 public function parseArguments($namedArguments = false, $definition = false)
457 {
458 $args = array();
459 $stream = $this->parser->getStream();
460
461 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
462 while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
463 if (!empty($args)) {
464 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
465 }
466
467 if ($definition) {
468 $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
469 $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
470 } else {
471 $value = $this->parseExpression();
472 }
473
474 $name = null;
475 if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
476 $token = $stream->next();
477 if (!$value instanceof Twig_Node_Expression_Name) {
478 throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
479 }
480 $name = $value->getAttribute('name');
481
482 if ($definition) {
483 $value = $this->parsePrimaryExpression();
484
485 if (!$this->checkConstantExpression($value)) {
486 throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
487 }
488 } else {
489 $value = $this->parseExpression();
490 }
491 }
492
493 if ($definition) {
494 if (null === $name) {
495 $name = $value->getAttribute('name');
496 $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
497 }
498 $args[$name] = $value;
499 } else {
500 if (null === $name) {
501 $args[] = $value;
502 } else {
503 $args[$name] = $value;
504 }
505 }
506 }
507 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
508
509 return new Twig_Node($args);
510 }
511
512 public function parseAssignmentExpression()
513 {
514 $targets = array();
515 while (true) {
516 $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
517 if (in_array($token->getValue(), array('true', 'false', 'none'))) {
518 throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
519 }
520 $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
521
522 if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
523 break;
524 }
525 $this->parser->getStream()->next();
526 }
527
528 return new Twig_Node($targets);
529 }
530
531 public function parseMultitargetExpression()
532 {
533 $targets = array();
534 while (true) {
535 $targets[] = $this->parseExpression();
536 if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
537 break;
538 }
539 $this->parser->getStream()->next();
540 }
541
542 return new Twig_Node($targets);
543 }
544
545 protected function getFunctionNodeClass($name, $line)
546 {
547 $env = $this->parser->getEnvironment();
548
549 if (false === $function = $env->getFunction($name)) {
550 $message = sprintf('The function "%s" does not exist', $name);
551 if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
552 $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
553 }
554
555 throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
556 }
557
558 if ($function instanceof Twig_SimpleFunction) {
559 return $function->getNodeClass();
560 }
561
562 return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
563 }
564
565 protected function getFilterNodeClass($name, $line)
566 {
567 $env = $this->parser->getEnvironment();
568
569 if (false === $filter = $env->getFilter($name)) {
570 $message = sprintf('The filter "%s" does not exist', $name);
571 if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
572 $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
573 }
574
575 throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
576 }
577
578 if ($filter instanceof Twig_SimpleFilter) {
579 return $filter->getNodeClass();
580 }
581
582 return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
583 }
584
585 // checks that the node only contains "constant" elements
586 protected function checkConstantExpression(Twig_NodeInterface $node)
587 {
588 if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
589 return false;
590 }
591
592 foreach ($node as $n) {
593 if (!$this->checkConstantExpression($n)) {
594 return false;
595 }
596 }
597
598 return true;
599 }
600}
diff --git a/vendor/twig/twig/lib/Twig/Extension.php b/vendor/twig/twig/lib/Twig/Extension.php
new file mode 100644
index 00000000..931fc033
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Extension.php
@@ -0,0 +1,93 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11abstract class Twig_Extension implements Twig_ExtensionInterface
12{
13 /**
14 * Initializes the runtime environment.
15 *
16 * This is where you can load some file that contains filter functions for instance.
17 *
18 * @param Twig_Environment $environment The current Twig_Environment instance
19 */
20 public function initRuntime(Twig_Environment $environment)
21 {
22 }
23
24 /**
25 * Returns the token parser instances to add to the existing list.
26 *
27 * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
28 */
29 public function getTokenParsers()
30 {
31 return array();
32 }
33
34 /**
35 * Returns the node visitor instances to add to the existing list.
36 *
37 * @return array An array of Twig_NodeVisitorInterface instances
38 */
39 public function getNodeVisitors()
40 {
41 return array();
42 }
43
44 /**
45 * Returns a list of filters to add to the existing list.
46 *
47 * @return array An array of filters
48 */
49 public function getFilters()
50 {
51 return array();
52 }
53
54 /**
55 * Returns a list of tests to add to the existing list.
56 *
57 * @return array An array of tests
58 */
59 public function getTests()
60 {
61 return array();
62 }
63
64 /**
65 * Returns a list of functions to add to the existing list.
66 *
67 * @return array An array of functions
68 */
69 public function getFunctions()
70 {
71 return array();
72 }
73
74 /**
75 * Returns a list of operators to add to the existing list.
76 *
77 * @return array An array of operators
78 */
79 public function getOperators()
80 {
81 return array();
82 }
83
84 /**
85 * Returns a list of global variables to add to the existing list.
86 *
87 * @return array An array of global variables
88 */
89 public function getGlobals()
90 {
91 return array();
92 }
93}
diff --git a/vendor/twig/twig/lib/Twig/Extension/Core.php b/vendor/twig/twig/lib/Twig/Extension/Core.php
new file mode 100644
index 00000000..e68687b4
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Extension/Core.php
@@ -0,0 +1,1355 @@
1<?php
2
3if (!defined('ENT_SUBSTITUTE')) {
4 define('ENT_SUBSTITUTE', 8);
5}
6
7/*
8 * This file is part of Twig.
9 *
10 * (c) 2009 Fabien Potencier
11 *
12 * For the full copyright and license information, please view the LICENSE
13 * file that was distributed with this source code.
14 */
15class Twig_Extension_Core extends Twig_Extension
16{
17 protected $dateFormats = array('F j, Y H:i', '%d days');
18 protected $numberFormat = array(0, '.', ',');
19 protected $timezone = null;
20
21 /**
22 * Sets the default format to be used by the date filter.
23 *
24 * @param string $format The default date format string
25 * @param string $dateIntervalFormat The default date interval format string
26 */
27 public function setDateFormat($format = null, $dateIntervalFormat = null)
28 {
29 if (null !== $format) {
30 $this->dateFormats[0] = $format;
31 }
32
33 if (null !== $dateIntervalFormat) {
34 $this->dateFormats[1] = $dateIntervalFormat;
35 }
36 }
37
38 /**
39 * Gets the default format to be used by the date filter.
40 *
41 * @return array The default date format string and the default date interval format string
42 */
43 public function getDateFormat()
44 {
45 return $this->dateFormats;
46 }
47
48 /**
49 * Sets the default timezone to be used by the date filter.
50 *
51 * @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object
52 */
53 public function setTimezone($timezone)
54 {
55 $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone);
56 }
57
58 /**
59 * Gets the default timezone to be used by the date filter.
60 *
61 * @return DateTimeZone The default timezone currently in use
62 */
63 public function getTimezone()
64 {
65 if (null === $this->timezone) {
66 $this->timezone = new DateTimeZone(date_default_timezone_get());
67 }
68
69 return $this->timezone;
70 }
71
72 /**
73 * Sets the default format to be used by the number_format filter.
74 *
75 * @param integer $decimal The number of decimal places to use.
76 * @param string $decimalPoint The character(s) to use for the decimal point.
77 * @param string $thousandSep The character(s) to use for the thousands separator.
78 */
79 public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
80 {
81 $this->numberFormat = array($decimal, $decimalPoint, $thousandSep);
82 }
83
84 /**
85 * Get the default format used by the number_format filter.
86 *
87 * @return array The arguments for number_format()
88 */
89 public function getNumberFormat()
90 {
91 return $this->numberFormat;
92 }
93
94 /**
95 * Returns the token parser instance to add to the existing list.
96 *
97 * @return array An array of Twig_TokenParser instances
98 */
99 public function getTokenParsers()
100 {
101 return array(
102 new Twig_TokenParser_For(),
103 new Twig_TokenParser_If(),
104 new Twig_TokenParser_Extends(),
105 new Twig_TokenParser_Include(),
106 new Twig_TokenParser_Block(),
107 new Twig_TokenParser_Use(),
108 new Twig_TokenParser_Filter(),
109 new Twig_TokenParser_Macro(),
110 new Twig_TokenParser_Import(),
111 new Twig_TokenParser_From(),
112 new Twig_TokenParser_Set(),
113 new Twig_TokenParser_Spaceless(),
114 new Twig_TokenParser_Flush(),
115 new Twig_TokenParser_Do(),
116 new Twig_TokenParser_Embed(),
117 );
118 }
119
120 /**
121 * Returns a list of filters to add to the existing list.
122 *
123 * @return array An array of filters
124 */
125 public function getFilters()
126 {
127 $filters = array(
128 // formatting filters
129 new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)),
130 new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)),
131 new Twig_SimpleFilter('format', 'sprintf'),
132 new Twig_SimpleFilter('replace', 'strtr'),
133 new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)),
134 new Twig_SimpleFilter('abs', 'abs'),
135
136 // encoding
137 new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'),
138 new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'),
139 new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'),
140
141 // string filters
142 new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)),
143 new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)),
144 new Twig_SimpleFilter('upper', 'strtoupper'),
145 new Twig_SimpleFilter('lower', 'strtolower'),
146 new Twig_SimpleFilter('striptags', 'strip_tags'),
147 new Twig_SimpleFilter('trim', 'trim'),
148 new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
149
150 // array helpers
151 new Twig_SimpleFilter('join', 'twig_join_filter'),
152 new Twig_SimpleFilter('split', 'twig_split_filter'),
153 new Twig_SimpleFilter('sort', 'twig_sort_filter'),
154 new Twig_SimpleFilter('merge', 'twig_array_merge'),
155 new Twig_SimpleFilter('batch', 'twig_array_batch'),
156
157 // string/array filters
158 new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)),
159 new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)),
160 new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)),
161 new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)),
162 new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)),
163
164 // iteration and runtime
165 new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')),
166 new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'),
167
168 // escaping
169 new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
170 new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
171 );
172
173 if (function_exists('mb_get_info')) {
174 $filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true));
175 $filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true));
176 }
177
178 return $filters;
179 }
180
181 /**
182 * Returns a list of global functions to add to the existing list.
183 *
184 * @return array An array of global functions
185 */
186 public function getFunctions()
187 {
188 return array(
189 new Twig_SimpleFunction('range', 'range'),
190 new Twig_SimpleFunction('constant', 'twig_constant'),
191 new Twig_SimpleFunction('cycle', 'twig_cycle'),
192 new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)),
193 new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)),
194 new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))),
195 );
196 }
197
198 /**
199 * Returns a list of tests to add to the existing list.
200 *
201 * @return array An array of tests
202 */
203 public function getTests()
204 {
205 return array(
206 new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')),
207 new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')),
208 new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')),
209 new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
210 new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
211 new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
212 new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
213 new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')),
214 new Twig_SimpleTest('empty', 'twig_test_empty'),
215 new Twig_SimpleTest('iterable', 'twig_test_iterable'),
216 );
217 }
218
219 /**
220 * Returns a list of operators to add to the existing list.
221 *
222 * @return array An array of operators
223 */
224 public function getOperators()
225 {
226 return array(
227 array(
228 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
229 '-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'),
230 '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'),
231 ),
232 array(
233 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
234 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
235 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
236 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
237 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
238 '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
239 '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
240 '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
241 '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
242 '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
243 '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
244 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
245 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
246 '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
247 '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
248 '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
249 '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
250 '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
251 '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
252 '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
253 '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
254 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
255 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
256 '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
257 ),
258 );
259 }
260
261 public function parseNotTestExpression(Twig_Parser $parser, $node)
262 {
263 return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
264 }
265
266 public function parseTestExpression(Twig_Parser $parser, $node)
267 {
268 $stream = $parser->getStream();
269 $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
270 $arguments = null;
271 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
272 $arguments = $parser->getExpressionParser()->parseArguments(true);
273 }
274
275 $class = $this->getTestNodeClass($parser, $name, $node->getLine());
276
277 return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine());
278 }
279
280 protected function getTestNodeClass(Twig_Parser $parser, $name, $line)
281 {
282 $env = $parser->getEnvironment();
283 $testMap = $env->getTests();
284 if (!isset($testMap[$name])) {
285 $message = sprintf('The test "%s" does not exist', $name);
286 if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) {
287 $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
288 }
289
290 throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
291 }
292
293 if ($testMap[$name] instanceof Twig_SimpleTest) {
294 return $testMap[$name]->getNodeClass();
295 }
296
297 return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test';
298 }
299
300 /**
301 * Returns the name of the extension.
302 *
303 * @return string The extension name
304 */
305 public function getName()
306 {
307 return 'core';
308 }
309}
310
311/**
312 * Cycles over a value.
313 *
314 * @param ArrayAccess|array $values An array or an ArrayAccess instance
315 * @param integer $position The cycle position
316 *
317 * @return string The next value in the cycle
318 */
319function twig_cycle($values, $position)
320{
321 if (!is_array($values) && !$values instanceof ArrayAccess) {
322 return $values;
323 }
324
325 return $values[$position % count($values)];
326}
327
328/**
329 * Returns a random value depending on the supplied parameter type:
330 * - a random item from a Traversable or array
331 * - a random character from a string
332 * - a random integer between 0 and the integer parameter
333 *
334 * @param Twig_Environment $env A Twig_Environment instance
335 * @param Traversable|array|integer|string $values The values to pick a random item from
336 *
337 * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is).
338 *
339 * @return mixed A random value from the given sequence
340 */
341function twig_random(Twig_Environment $env, $values = null)
342{
343 if (null === $values) {
344 return mt_rand();
345 }
346
347 if (is_int($values) || is_float($values)) {
348 return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values);
349 }
350
351 if ($values instanceof Traversable) {
352 $values = iterator_to_array($values);
353 } elseif (is_string($values)) {
354 if ('' === $values) {
355 return '';
356 }
357 if (null !== $charset = $env->getCharset()) {
358 if ('UTF-8' != $charset) {
359 $values = twig_convert_encoding($values, 'UTF-8', $charset);
360 }
361
362 // unicode version of str_split()
363 // split at all positions, but not after the start and not before the end
364 $values = preg_split('/(?<!^)(?!$)/u', $values);
365
366 if ('UTF-8' != $charset) {
367 foreach ($values as $i => $value) {
368 $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8');
369 }
370 }
371 } else {
372 return $values[mt_rand(0, strlen($values) - 1)];
373 }
374 }
375
376 if (!is_array($values)) {
377 return $values;
378 }
379
380 if (0 === count($values)) {
381 throw new Twig_Error_Runtime('The random function cannot pick from an empty array.');
382 }
383
384 return $values[array_rand($values, 1)];
385}
386
387/**
388 * Converts a date to the given format.
389 *
390 * <pre>
391 * {{ post.published_at|date("m/d/Y") }}
392 * </pre>
393 *
394 * @param Twig_Environment $env A Twig_Environment instance
395 * @param DateTime|DateInterval|string $date A date
396 * @param string $format A format
397 * @param DateTimeZone|string $timezone A timezone
398 *
399 * @return string The formatted date
400 */
401function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null)
402{
403 if (null === $format) {
404 $formats = $env->getExtension('core')->getDateFormat();
405 $format = $date instanceof DateInterval ? $formats[1] : $formats[0];
406 }
407
408 if ($date instanceof DateInterval) {
409 return $date->format($format);
410 }
411
412 return twig_date_converter($env, $date, $timezone)->format($format);
413}
414
415/**
416 * Returns a new date object modified
417 *
418 * <pre>
419 * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
420 * </pre>
421 *
422 * @param Twig_Environment $env A Twig_Environment instance
423 * @param DateTime|string $date A date
424 * @param string $modifier A modifier string
425 *
426 * @return DateTime A new date object
427 */
428function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
429{
430 $date = twig_date_converter($env, $date, false);
431 $date->modify($modifier);
432
433 return $date;
434}
435
436/**
437 * Converts an input to a DateTime instance.
438 *
439 * <pre>
440 * {% if date(user.created_at) < date('+2days') %}
441 * {# do something #}
442 * {% endif %}
443 * </pre>
444 *
445 * @param Twig_Environment $env A Twig_Environment instance
446 * @param DateTime|string $date A date
447 * @param DateTimeZone|string $timezone A timezone
448 *
449 * @return DateTime A DateTime instance
450 */
451function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null)
452{
453 // determine the timezone
454 if (!$timezone) {
455 $defaultTimezone = $env->getExtension('core')->getTimezone();
456 } elseif (!$timezone instanceof DateTimeZone) {
457 $defaultTimezone = new DateTimeZone($timezone);
458 } else {
459 $defaultTimezone = $timezone;
460 }
461
462 if ($date instanceof DateTime) {
463 $date = clone $date;
464 if (false !== $timezone) {
465 $date->setTimezone($defaultTimezone);
466 }
467
468 return $date;
469 }
470
471 $asString = (string) $date;
472 if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
473 $date = '@'.$date;
474 }
475
476 $date = new DateTime($date, $defaultTimezone);
477 if (false !== $timezone) {
478 $date->setTimezone($defaultTimezone);
479 }
480
481 return $date;
482}
483
484/**
485 * Number format filter.
486 *
487 * All of the formatting options can be left null, in that case the defaults will
488 * be used. Supplying any of the parameters will override the defaults set in the
489 * environment object.
490 *
491 * @param Twig_Environment $env A Twig_Environment instance
492 * @param mixed $number A float/int/string of the number to format
493 * @param integer $decimal The number of decimal points to display.
494 * @param string $decimalPoint The character(s) to use for the decimal point.
495 * @param string $thousandSep The character(s) to use for the thousands separator.
496 *
497 * @return string The formatted number
498 */
499function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
500{
501 $defaults = $env->getExtension('core')->getNumberFormat();
502 if (null === $decimal) {
503 $decimal = $defaults[0];
504 }
505
506 if (null === $decimalPoint) {
507 $decimalPoint = $defaults[1];
508 }
509
510 if (null === $thousandSep) {
511 $thousandSep = $defaults[2];
512 }
513
514 return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
515}
516
517/**
518 * URL encodes a string as a path segment or an array as a query string.
519 *
520 * @param string|array $url A URL or an array of query parameters
521 * @param bool $raw true to use rawurlencode() instead of urlencode
522 *
523 * @return string The URL encoded value
524 */
525function twig_urlencode_filter($url, $raw = false)
526{
527 if (is_array($url)) {
528 return http_build_query($url, '', '&');
529 }
530
531 if ($raw) {
532 return rawurlencode($url);
533 }
534
535 return urlencode($url);
536}
537
538if (version_compare(PHP_VERSION, '5.3.0', '<')) {
539 /**
540 * JSON encodes a variable.
541 *
542 * @param mixed $value The value to encode.
543 * @param integer $options Not used on PHP 5.2.x
544 *
545 * @return mixed The JSON encoded value
546 */
547 function twig_jsonencode_filter($value, $options = 0)
548 {
549 if ($value instanceof Twig_Markup) {
550 $value = (string) $value;
551 } elseif (is_array($value)) {
552 array_walk_recursive($value, '_twig_markup2string');
553 }
554
555 return json_encode($value);
556 }
557} else {
558 /**
559 * JSON encodes a variable.
560 *
561 * @param mixed $value The value to encode.
562 * @param integer $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
563 *
564 * @return mixed The JSON encoded value
565 */
566 function twig_jsonencode_filter($value, $options = 0)
567 {
568 if ($value instanceof Twig_Markup) {
569 $value = (string) $value;
570 } elseif (is_array($value)) {
571 array_walk_recursive($value, '_twig_markup2string');
572 }
573
574 return json_encode($value, $options);
575 }
576}
577
578function _twig_markup2string(&$value)
579{
580 if ($value instanceof Twig_Markup) {
581 $value = (string) $value;
582 }
583}
584
585/**
586 * Merges an array with another one.
587 *
588 * <pre>
589 * {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
590 *
591 * {% set items = items|merge({ 'peugeot': 'car' }) %}
592 *
593 * {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
594 * </pre>
595 *
596 * @param array $arr1 An array
597 * @param array $arr2 An array
598 *
599 * @return array The merged array
600 */
601function twig_array_merge($arr1, $arr2)
602{
603 if (!is_array($arr1) || !is_array($arr2)) {
604 throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.');
605 }
606
607 return array_merge($arr1, $arr2);
608}
609
610/**
611 * Slices a variable.
612 *
613 * @param Twig_Environment $env A Twig_Environment instance
614 * @param mixed $item A variable
615 * @param integer $start Start of the slice
616 * @param integer $length Size of the slice
617 * @param Boolean $preserveKeys Whether to preserve key or not (when the input is an array)
618 *
619 * @return mixed The sliced variable
620 */
621function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
622{
623 if ($item instanceof Traversable) {
624 $item = iterator_to_array($item, false);
625 }
626
627 if (is_array($item)) {
628 return array_slice($item, $start, $length, $preserveKeys);
629 }
630
631 $item = (string) $item;
632
633 if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
634 return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
635 }
636
637 return null === $length ? substr($item, $start) : substr($item, $start, $length);
638}
639
640/**
641 * Returns the first element of the item.
642 *
643 * @param Twig_Environment $env A Twig_Environment instance
644 * @param mixed $item A variable
645 *
646 * @return mixed The first element of the item
647 */
648function twig_first(Twig_Environment $env, $item)
649{
650 $elements = twig_slice($env, $item, 0, 1, false);
651
652 return is_string($elements) ? $elements[0] : current($elements);
653}
654
655/**
656 * Returns the last element of the item.
657 *
658 * @param Twig_Environment $env A Twig_Environment instance
659 * @param mixed $item A variable
660 *
661 * @return mixed The last element of the item
662 */
663function twig_last(Twig_Environment $env, $item)
664{
665 $elements = twig_slice($env, $item, -1, 1, false);
666
667 return is_string($elements) ? $elements[0] : current($elements);
668}
669
670/**
671 * Joins the values to a string.
672 *
673 * The separator between elements is an empty string per default, you can define it with the optional parameter.
674 *
675 * <pre>
676 * {{ [1, 2, 3]|join('|') }}
677 * {# returns 1|2|3 #}
678 *
679 * {{ [1, 2, 3]|join }}
680 * {# returns 123 #}
681 * </pre>
682 *
683 * @param array $value An array
684 * @param string $glue The separator
685 *
686 * @return string The concatenated string
687 */
688function twig_join_filter($value, $glue = '')
689{
690 if ($value instanceof Traversable) {
691 $value = iterator_to_array($value, false);
692 }
693
694 return implode($glue, (array) $value);
695}
696
697/**
698 * Splits the string into an array.
699 *
700 * <pre>
701 * {{ "one,two,three"|split(',') }}
702 * {# returns [one, two, three] #}
703 *
704 * {{ "one,two,three,four,five"|split(',', 3) }}
705 * {# returns [one, two, "three,four,five"] #}
706 *
707 * {{ "123"|split('') }}
708 * {# returns [1, 2, 3] #}
709 *
710 * {{ "aabbcc"|split('', 2) }}
711 * {# returns [aa, bb, cc] #}
712 * </pre>
713 *
714 * @param string $value A string
715 * @param string $delimiter The delimiter
716 * @param integer $limit The limit
717 *
718 * @return array The split string as an array
719 */
720function twig_split_filter($value, $delimiter, $limit = null)
721{
722 if (empty($delimiter)) {
723 return str_split($value, null === $limit ? 1 : $limit);
724 }
725
726 return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
727}
728
729// The '_default' filter is used internally to avoid using the ternary operator
730// which costs a lot for big contexts (before PHP 5.4). So, on average,
731// a function call is cheaper.
732function _twig_default_filter($value, $default = '')
733{
734 if (twig_test_empty($value)) {
735 return $default;
736 }
737
738 return $value;
739}
740
741/**
742 * Returns the keys for the given array.
743 *
744 * It is useful when you want to iterate over the keys of an array:
745 *
746 * <pre>
747 * {% for key in array|keys %}
748 * {# ... #}
749 * {% endfor %}
750 * </pre>
751 *
752 * @param array $array An array
753 *
754 * @return array The keys
755 */
756function twig_get_array_keys_filter($array)
757{
758 if (is_object($array) && $array instanceof Traversable) {
759 return array_keys(iterator_to_array($array));
760 }
761
762 if (!is_array($array)) {
763 return array();
764 }
765
766 return array_keys($array);
767}
768
769/**
770 * Reverses a variable.
771 *
772 * @param Twig_Environment $env A Twig_Environment instance
773 * @param array|Traversable|string $item An array, a Traversable instance, or a string
774 * @param Boolean $preserveKeys Whether to preserve key or not
775 *
776 * @return mixed The reversed input
777 */
778function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false)
779{
780 if (is_object($item) && $item instanceof Traversable) {
781 return array_reverse(iterator_to_array($item), $preserveKeys);
782 }
783
784 if (is_array($item)) {
785 return array_reverse($item, $preserveKeys);
786 }
787
788 if (null !== $charset = $env->getCharset()) {
789 $string = (string) $item;
790
791 if ('UTF-8' != $charset) {
792 $item = twig_convert_encoding($string, 'UTF-8', $charset);
793 }
794
795 preg_match_all('/./us', $item, $matches);
796
797 $string = implode('', array_reverse($matches[0]));
798
799 if ('UTF-8' != $charset) {
800 $string = twig_convert_encoding($string, $charset, 'UTF-8');
801 }
802
803 return $string;
804 }
805
806 return strrev((string) $item);
807}
808
809/**
810 * Sorts an array.
811 *
812 * @param array $array An array
813 */
814function twig_sort_filter($array)
815{
816 asort($array);
817
818 return $array;
819}
820
821/* used internally */
822function twig_in_filter($value, $compare)
823{
824 if (is_array($compare)) {
825 return in_array($value, $compare, is_object($value));
826 } elseif (is_string($compare)) {
827 if (!strlen($value)) {
828 return empty($compare);
829 }
830
831 return false !== strpos($compare, (string) $value);
832 } elseif ($compare instanceof Traversable) {
833 return in_array($value, iterator_to_array($compare, false), is_object($value));
834 }
835
836 return false;
837}
838
839/**
840 * Escapes a string.
841 *
842 * @param Twig_Environment $env A Twig_Environment instance
843 * @param string $string The value to be escaped
844 * @param string $strategy The escaping strategy
845 * @param string $charset The charset
846 * @param Boolean $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
847 */
848function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
849{
850 if ($autoescape && $string instanceof Twig_Markup) {
851 return $string;
852 }
853
854 if (!is_string($string)) {
855 if (is_object($string) && method_exists($string, '__toString')) {
856 $string = (string) $string;
857 } else {
858 return $string;
859 }
860 }
861
862 if (null === $charset) {
863 $charset = $env->getCharset();
864 }
865
866 switch ($strategy) {
867 case 'html':
868 // see http://php.net/htmlspecialchars
869
870 // Using a static variable to avoid initializing the array
871 // each time the function is called. Moving the declaration on the
872 // top of the function slow downs other escaping strategies.
873 static $htmlspecialcharsCharsets = array(
874 'ISO-8859-1' => true, 'ISO8859-1' => true,
875 'ISO-8859-15' => true, 'ISO8859-15' => true,
876 'utf-8' => true, 'UTF-8' => true,
877 'CP866' => true, 'IBM866' => true, '866' => true,
878 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
879 '1251' => true,
880 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
881 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
882 'BIG5' => true, '950' => true,
883 'GB2312' => true, '936' => true,
884 'BIG5-HKSCS' => true,
885 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
886 'EUC-JP' => true, 'EUCJP' => true,
887 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
888 );
889
890 if (isset($htmlspecialcharsCharsets[$charset])) {
891 return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
892 }
893
894 if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
895 // cache the lowercase variant for future iterations
896 $htmlspecialcharsCharsets[$charset] = true;
897
898 return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
899 }
900
901 $string = twig_convert_encoding($string, 'UTF-8', $charset);
902 $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
903
904 return twig_convert_encoding($string, $charset, 'UTF-8');
905
906 case 'js':
907 // escape all non-alphanumeric characters
908 // into their \xHH or \uHHHH representations
909 if ('UTF-8' != $charset) {
910 $string = twig_convert_encoding($string, 'UTF-8', $charset);
911 }
912
913 if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
914 throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
915 }
916
917 $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string);
918
919 if ('UTF-8' != $charset) {
920 $string = twig_convert_encoding($string, $charset, 'UTF-8');
921 }
922
923 return $string;
924
925 case 'css':
926 if ('UTF-8' != $charset) {
927 $string = twig_convert_encoding($string, 'UTF-8', $charset);
928 }
929
930 if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
931 throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
932 }
933
934 $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string);
935
936 if ('UTF-8' != $charset) {
937 $string = twig_convert_encoding($string, $charset, 'UTF-8');
938 }
939
940 return $string;
941
942 case 'html_attr':
943 if ('UTF-8' != $charset) {
944 $string = twig_convert_encoding($string, 'UTF-8', $charset);
945 }
946
947 if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
948 throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
949 }
950
951 $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string);
952
953 if ('UTF-8' != $charset) {
954 $string = twig_convert_encoding($string, $charset, 'UTF-8');
955 }
956
957 return $string;
958
959 case 'url':
960 // hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.*
961 // at that point however PHP 5.2.* support can be removed
962 if (PHP_VERSION < '5.3.0') {
963 return str_replace('%7E', '~', rawurlencode($string));
964 }
965
966 return rawurlencode($string);
967
968 default:
969 throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: html, js, url, css, and html_attr).', $strategy));
970 }
971}
972
973/* used internally */
974function twig_escape_filter_is_safe(Twig_Node $filterArgs)
975{
976 foreach ($filterArgs as $arg) {
977 if ($arg instanceof Twig_Node_Expression_Constant) {
978 return array($arg->getAttribute('value'));
979 }
980
981 return array();
982 }
983
984 return array('html');
985}
986
987if (function_exists('mb_convert_encoding')) {
988 function twig_convert_encoding($string, $to, $from)
989 {
990 return mb_convert_encoding($string, $to, $from);
991 }
992} elseif (function_exists('iconv')) {
993 function twig_convert_encoding($string, $to, $from)
994 {
995 return iconv($from, $to, $string);
996 }
997} else {
998 function twig_convert_encoding($string, $to, $from)
999 {
1000 throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
1001 }
1002}
1003
1004function _twig_escape_js_callback($matches)
1005{
1006 $char = $matches[0];
1007
1008 // \xHH
1009 if (!isset($char[1])) {
1010 return '\\x'.strtoupper(substr('00'.bin2hex($char), -2));
1011 }
1012
1013 // \uHHHH
1014 $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
1015
1016 return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4));
1017}
1018
1019function _twig_escape_css_callback($matches)
1020{
1021 $char = $matches[0];
1022
1023 // \xHH
1024 if (!isset($char[1])) {
1025 $hex = ltrim(strtoupper(bin2hex($char)), '0');
1026 if (0 === strlen($hex)) {
1027 $hex = '0';
1028 }
1029
1030 return '\\'.$hex.' ';
1031 }
1032
1033 // \uHHHH
1034 $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
1035
1036 return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' ';
1037}
1038
1039/**
1040 * This function is adapted from code coming from Zend Framework.
1041 *
1042 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
1043 * @license http://framework.zend.com/license/new-bsd New BSD License
1044 */
1045function _twig_escape_html_attr_callback($matches)
1046{
1047 /*
1048 * While HTML supports far more named entities, the lowest common denominator
1049 * has become HTML5's XML Serialisation which is restricted to the those named
1050 * entities that XML supports. Using HTML entities would result in this error:
1051 * XML Parsing Error: undefined entity
1052 */
1053 static $entityMap = array(
1054 34 => 'quot', /* quotation mark */
1055 38 => 'amp', /* ampersand */
1056 60 => 'lt', /* less-than sign */
1057 62 => 'gt', /* greater-than sign */
1058 );
1059
1060 $chr = $matches[0];
1061 $ord = ord($chr);
1062
1063 /**
1064 * The following replaces characters undefined in HTML with the
1065 * hex entity for the Unicode replacement character.
1066 */
1067 if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") || ($ord >= 0x7f && $ord <= 0x9f)) {
1068 return '&#xFFFD;';
1069 }
1070
1071 /**
1072 * Check if the current character to escape has a name entity we should
1073 * replace it with while grabbing the hex value of the character.
1074 */
1075 if (strlen($chr) == 1) {
1076 $hex = strtoupper(substr('00'.bin2hex($chr), -2));
1077 } else {
1078 $chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8');
1079 $hex = strtoupper(substr('0000'.bin2hex($chr), -4));
1080 }
1081
1082 $int = hexdec($hex);
1083 if (array_key_exists($int, $entityMap)) {
1084 return sprintf('&%s;', $entityMap[$int]);
1085 }
1086
1087 /**
1088 * Per OWASP recommendations, we'll use hex entities for any other
1089 * characters where a named entity does not exist.
1090 */
1091
1092 return sprintf('&#x%s;', $hex);
1093}
1094
1095// add multibyte extensions if possible
1096if (function_exists('mb_get_info')) {
1097 /**
1098 * Returns the length of a variable.
1099 *
1100 * @param Twig_Environment $env A Twig_Environment instance
1101 * @param mixed $thing A variable
1102 *
1103 * @return integer The length of the value
1104 */
1105 function twig_length_filter(Twig_Environment $env, $thing)
1106 {
1107 return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
1108 }
1109
1110 /**
1111 * Converts a string to uppercase.
1112 *
1113 * @param Twig_Environment $env A Twig_Environment instance
1114 * @param string $string A string
1115 *
1116 * @return string The uppercased string
1117 */
1118 function twig_upper_filter(Twig_Environment $env, $string)
1119 {
1120 if (null !== ($charset = $env->getCharset())) {
1121 return mb_strtoupper($string, $charset);
1122 }
1123
1124 return strtoupper($string);
1125 }
1126
1127 /**
1128 * Converts a string to lowercase.
1129 *
1130 * @param Twig_Environment $env A Twig_Environment instance
1131 * @param string $string A string
1132 *
1133 * @return string The lowercased string
1134 */
1135 function twig_lower_filter(Twig_Environment $env, $string)
1136 {
1137 if (null !== ($charset = $env->getCharset())) {
1138 return mb_strtolower($string, $charset);
1139 }
1140
1141 return strtolower($string);
1142 }
1143
1144 /**
1145 * Returns a titlecased string.
1146 *
1147 * @param Twig_Environment $env A Twig_Environment instance
1148 * @param string $string A string
1149 *
1150 * @return string The titlecased string
1151 */
1152 function twig_title_string_filter(Twig_Environment $env, $string)
1153 {
1154 if (null !== ($charset = $env->getCharset())) {
1155 return mb_convert_case($string, MB_CASE_TITLE, $charset);
1156 }
1157
1158 return ucwords(strtolower($string));
1159 }
1160
1161 /**
1162 * Returns a capitalized string.
1163 *
1164 * @param Twig_Environment $env A Twig_Environment instance
1165 * @param string $string A string
1166 *
1167 * @return string The capitalized string
1168 */
1169 function twig_capitalize_string_filter(Twig_Environment $env, $string)
1170 {
1171 if (null !== ($charset = $env->getCharset())) {
1172 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
1173 mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
1174 }
1175
1176 return ucfirst(strtolower($string));
1177 }
1178}
1179// and byte fallback
1180else {
1181 /**
1182 * Returns the length of a variable.
1183 *
1184 * @param Twig_Environment $env A Twig_Environment instance
1185 * @param mixed $thing A variable
1186 *
1187 * @return integer The length of the value
1188 */
1189 function twig_length_filter(Twig_Environment $env, $thing)
1190 {
1191 return is_scalar($thing) ? strlen($thing) : count($thing);
1192 }
1193
1194 /**
1195 * Returns a titlecased string.
1196 *
1197 * @param Twig_Environment $env A Twig_Environment instance
1198 * @param string $string A string
1199 *
1200 * @return string The titlecased string
1201 */
1202 function twig_title_string_filter(Twig_Environment $env, $string)
1203 {
1204 return ucwords(strtolower($string));
1205 }
1206
1207 /**
1208 * Returns a capitalized string.
1209 *
1210 * @param Twig_Environment $env A Twig_Environment instance
1211 * @param string $string A string
1212 *
1213 * @return string The capitalized string
1214 */
1215 function twig_capitalize_string_filter(Twig_Environment $env, $string)
1216 {
1217 return ucfirst(strtolower($string));
1218 }
1219}
1220
1221/* used internally */
1222function twig_ensure_traversable($seq)
1223{
1224 if ($seq instanceof Traversable || is_array($seq)) {
1225 return $seq;
1226 }
1227
1228 return array();
1229}
1230
1231/**
1232 * Checks if a variable is empty.
1233 *
1234 * <pre>
1235 * {# evaluates to true if the foo variable is null, false, or the empty string #}
1236 * {% if foo is empty %}
1237 * {# ... #}
1238 * {% endif %}
1239 * </pre>
1240 *
1241 * @param mixed $value A variable
1242 *
1243 * @return Boolean true if the value is empty, false otherwise
1244 */
1245function twig_test_empty($value)
1246{
1247 if ($value instanceof Countable) {
1248 return 0 == count($value);
1249 }
1250
1251 return '' === $value || false === $value || null === $value || array() === $value;
1252}
1253
1254/**
1255 * Checks if a variable is traversable.
1256 *
1257 * <pre>
1258 * {# evaluates to true if the foo variable is an array or a traversable object #}
1259 * {% if foo is traversable %}
1260 * {# ... #}
1261 * {% endif %}
1262 * </pre>
1263 *
1264 * @param mixed $value A variable
1265 *
1266 * @return Boolean true if the value is traversable
1267 */
1268function twig_test_iterable($value)
1269{
1270 return $value instanceof Traversable || is_array($value);
1271}
1272
1273/**
1274 * Renders a template.
1275 *
1276 * @param string $template The template to render
1277 * @param array $variables The variables to pass to the template
1278 * @param Boolean $with_context Whether to pass the current context variables or not
1279 * @param Boolean $ignore_missing Whether to ignore missing templates or not
1280 * @param Boolean $sandboxed Whether to sandbox the template or not
1281 *
1282 * @return string The rendered template
1283 */
1284function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false)
1285{
1286 if ($withContext) {
1287 $variables = array_merge($context, $variables);
1288 }
1289
1290 if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) {
1291 $sandbox = $env->getExtension('sandbox');
1292 if (!$alreadySandboxed = $sandbox->isSandboxed()) {
1293 $sandbox->enableSandbox();
1294 }
1295 }
1296
1297 try {
1298 return $env->resolveTemplate($template)->render($variables);
1299 } catch (Twig_Error_Loader $e) {
1300 if (!$ignoreMissing) {
1301 throw $e;
1302 }
1303 }
1304
1305 if ($isSandboxed && !$alreadySandboxed) {
1306 $sandbox->disableSandbox();
1307 }
1308}
1309
1310/**
1311 * Provides the ability to get constants from instances as well as class/global constants.
1312 *
1313 * @param string $constant The name of the constant
1314 * @param null|object $object The object to get the constant from
1315 *
1316 * @return string
1317 */
1318function twig_constant($constant, $object = null)
1319{
1320 if (null !== $object) {
1321 $constant = get_class($object).'::'.$constant;
1322 }
1323
1324 return constant($constant);
1325}
1326
1327/**
1328 * Batches item.
1329 *
1330 * @param array $items An array of items
1331 * @param integer $size The size of the batch
1332 * @param string $fill A string to fill missing items
1333 *
1334 * @return array
1335 */
1336function twig_array_batch($items, $size, $fill = null)
1337{
1338 if ($items instanceof Traversable) {
1339 $items = iterator_to_array($items, false);
1340 }
1341
1342 $size = ceil($size);
1343
1344 $result = array_chunk($items, $size, true);
1345
1346 if (null !== $fill) {
1347 $last = count($result) - 1;
1348 $result[$last] = array_merge(
1349 $result[$last],
1350 array_fill(0, $size - count($result[$last]), $fill)
1351 );
1352 }
1353
1354 return $result;
1355}
diff --git a/vendor/twig/twig/lib/Twig/Extension/Debug.php b/vendor/twig/twig/lib/Twig/Extension/Debug.php
new file mode 100644
index 00000000..e3a85bfe
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Extension/Debug.php
@@ -0,0 +1,71 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Extension_Debug extends Twig_Extension
12{
13 /**
14 * Returns a list of global functions to add to the existing list.
15 *
16 * @return array An array of global functions
17 */
18 public function getFunctions()
19 {
20 // dump is safe if var_dump is overridden by xdebug
21 $isDumpOutputHtmlSafe = extension_loaded('xdebug')
22 // false means that it was not set (and the default is on) or it explicitly enabled
23 && (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
24 // false means that it was not set (and the default is on) or it explicitly enabled
25 // xdebug.overload_var_dump produces HTML only when html_errors is also enabled
26 && (false === ini_get('html_errors') || ini_get('html_errors'))
27 || 'cli' === php_sapi_name()
28 ;
29
30 return array(
31 new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
32 );
33 }
34
35 /**
36 * Returns the name of the extension.
37 *
38 * @return string The extension name
39 */
40 public function getName()
41 {
42 return 'debug';
43 }
44}
45
46function twig_var_dump(Twig_Environment $env, $context)
47{
48 if (!$env->isDebug()) {
49 return;
50 }
51
52 ob_start();
53
54 $count = func_num_args();
55 if (2 === $count) {
56 $vars = array();
57 foreach ($context as $key => $value) {
58 if (!$value instanceof Twig_Template) {
59 $vars[$key] = $value;
60 }
61 }
62
63 var_dump($vars);
64 } else {
65 for ($i = 2; $i < $count; $i++) {
66 var_dump(func_get_arg($i));
67 }
68 }
69
70 return ob_get_clean();
71}
diff --git a/vendor/twig/twig/lib/Twig/Extension/Escaper.php b/vendor/twig/twig/lib/Twig/Extension/Escaper.php
new file mode 100644
index 00000000..c9a7f68e
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Extension/Escaper.php
@@ -0,0 +1,107 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Extension_Escaper extends Twig_Extension
12{
13 protected $defaultStrategy;
14
15 public function __construct($defaultStrategy = 'html')
16 {
17 $this->setDefaultStrategy($defaultStrategy);
18 }
19
20 /**
21 * Returns the token parser instances to add to the existing list.
22 *
23 * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
24 */
25 public function getTokenParsers()
26 {
27 return array(new Twig_TokenParser_AutoEscape());
28 }
29
30 /**
31 * Returns the node visitor instances to add to the existing list.
32 *
33 * @return array An array of Twig_NodeVisitorInterface instances
34 */
35 public function getNodeVisitors()
36 {
37 return array(new Twig_NodeVisitor_Escaper());
38 }
39
40 /**
41 * Returns a list of filters to add to the existing list.
42 *
43 * @return array An array of filters
44 */
45 public function getFilters()
46 {
47 return array(
48 new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
49 );
50 }
51
52 /**
53 * Sets the default strategy to use when not defined by the user.
54 *
55 * The strategy can be a valid PHP callback that takes the template
56 * "filename" as an argument and returns the strategy to use.
57 *
58 * @param mixed $defaultStrategy An escaping strategy
59 */
60 public function setDefaultStrategy($defaultStrategy)
61 {
62 // for BC
63 if (true === $defaultStrategy) {
64 $defaultStrategy = 'html';
65 }
66
67 $this->defaultStrategy = $defaultStrategy;
68 }
69
70 /**
71 * Gets the default strategy to use when not defined by the user.
72 *
73 * @param string $filename The template "filename"
74 *
75 * @return string The default strategy to use for the template
76 */
77 public function getDefaultStrategy($filename)
78 {
79 // disable string callables to avoid calling a function named html or js,
80 // or any other upcoming escaping strategy
81 if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) {
82 return call_user_func($this->defaultStrategy, $filename);
83 }
84
85 return $this->defaultStrategy;
86 }
87
88 /**
89 * Returns the name of the extension.
90 *
91 * @return string The extension name
92 */
93 public function getName()
94 {
95 return 'escaper';
96 }
97}
98
99/**
100 * Marks a variable as being safe.
101 *
102 * @param string $string A PHP variable
103 */
104function twig_raw_filter($string)
105{
106 return $string;
107}
diff --git a/vendor/twig/twig/lib/Twig/Extension/Optimizer.php b/vendor/twig/twig/lib/Twig/Extension/Optimizer.php
new file mode 100644
index 00000000..013fcb62
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Extension/Optimizer.php
@@ -0,0 +1,35 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Extension_Optimizer extends Twig_Extension
12{
13 protected $optimizers;
14
15 public function __construct($optimizers = -1)
16 {
17 $this->optimizers = $optimizers;
18 }
19
20 /**
21 * {@inheritdoc}
22 */
23 public function getNodeVisitors()
24 {
25 return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
26 }
27
28 /**
29 * {@inheritdoc}
30 */
31 public function getName()
32 {
33 return 'optimizer';
34 }
35}
diff --git a/vendor/twig/twig/lib/Twig/Extension/Sandbox.php b/vendor/twig/twig/lib/Twig/Extension/Sandbox.php
new file mode 100644
index 00000000..bf76c11a
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Extension/Sandbox.php
@@ -0,0 +1,112 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Extension_Sandbox extends Twig_Extension
12{
13 protected $sandboxedGlobally;
14 protected $sandboxed;
15 protected $policy;
16
17 public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
18 {
19 $this->policy = $policy;
20 $this->sandboxedGlobally = $sandboxed;
21 }
22
23 /**
24 * Returns the token parser instances to add to the existing list.
25 *
26 * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
27 */
28 public function getTokenParsers()
29 {
30 return array(new Twig_TokenParser_Sandbox());
31 }
32
33 /**
34 * Returns the node visitor instances to add to the existing list.
35 *
36 * @return array An array of Twig_NodeVisitorInterface instances
37 */
38 public function getNodeVisitors()
39 {
40 return array(new Twig_NodeVisitor_Sandbox());
41 }
42
43 public function enableSandbox()
44 {
45 $this->sandboxed = true;
46 }
47
48 public function disableSandbox()
49 {
50 $this->sandboxed = false;
51 }
52
53 public function isSandboxed()
54 {
55 return $this->sandboxedGlobally || $this->sandboxed;
56 }
57
58 public function isSandboxedGlobally()
59 {
60 return $this->sandboxedGlobally;
61 }
62
63 public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
64 {
65 $this->policy = $policy;
66 }
67
68 public function getSecurityPolicy()
69 {
70 return $this->policy;
71 }
72
73 public function checkSecurity($tags, $filters, $functions)
74 {
75 if ($this->isSandboxed()) {
76 $this->policy->checkSecurity($tags, $filters, $functions);
77 }
78 }
79
80 public function checkMethodAllowed($obj, $method)
81 {
82 if ($this->isSandboxed()) {
83 $this->policy->checkMethodAllowed($obj, $method);
84 }
85 }
86
87 public function checkPropertyAllowed($obj, $method)
88 {
89 if ($this->isSandboxed()) {
90 $this->policy->checkPropertyAllowed($obj, $method);
91 }
92 }
93
94 public function ensureToStringAllowed($obj)
95 {
96 if (is_object($obj)) {
97 $this->policy->checkMethodAllowed($obj, '__toString');
98 }
99
100 return $obj;
101 }
102
103 /**
104 * Returns the name of the extension.
105 *
106 * @return string The extension name
107 */
108 public function getName()
109 {
110 return 'sandbox';
111 }
112}
diff --git a/vendor/twig/twig/lib/Twig/Extension/Staging.php b/vendor/twig/twig/lib/Twig/Extension/Staging.php
new file mode 100644
index 00000000..8ab0f459
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Extension/Staging.php
@@ -0,0 +1,113 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
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 * Internal class.
14 *
15 * This class is used by Twig_Environment as a staging area and must not be used directly.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19class Twig_Extension_Staging extends Twig_Extension
20{
21 protected $functions = array();
22 protected $filters = array();
23 protected $visitors = array();
24 protected $tokenParsers = array();
25 protected $globals = array();
26 protected $tests = array();
27
28 public function addFunction($name, $function)
29 {
30 $this->functions[$name] = $function;
31 }
32
33 /**
34 * {@inheritdoc}
35 */
36 public function getFunctions()
37 {
38 return $this->functions;
39 }
40
41 public function addFilter($name, $filter)
42 {
43 $this->filters[$name] = $filter;
44 }
45
46 /**
47 * {@inheritdoc}
48 */
49 public function getFilters()
50 {
51 return $this->filters;
52 }
53
54 public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
55 {
56 $this->visitors[] = $visitor;
57 }
58
59 /**
60 * {@inheritdoc}
61 */
62 public function getNodeVisitors()
63 {
64 return $this->visitors;
65 }
66
67 public function addTokenParser(Twig_TokenParserInterface $parser)
68 {
69 $this->tokenParsers[] = $parser;
70 }
71
72 /**
73 * {@inheritdoc}
74 */
75 public function getTokenParsers()
76 {
77 return $this->tokenParsers;
78 }
79
80 public function addGlobal($name, $value)
81 {
82 $this->globals[$name] = $value;
83 }
84
85 /**
86 * {@inheritdoc}
87 */
88 public function getGlobals()
89 {
90 return $this->globals;
91 }
92
93 public function addTest($name, $test)
94 {
95 $this->tests[$name] = $test;
96 }
97
98 /**
99 * {@inheritdoc}
100 */
101 public function getTests()
102 {
103 return $this->tests;
104 }
105
106 /**
107 * {@inheritdoc}
108 */
109 public function getName()
110 {
111 return 'staging';
112 }
113}
diff --git a/vendor/twig/twig/lib/Twig/Extension/StringLoader.php b/vendor/twig/twig/lib/Twig/Extension/StringLoader.php
new file mode 100644
index 00000000..20f3f994
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Extension/StringLoader.php
@@ -0,0 +1,64 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Extension_StringLoader extends Twig_Extension
12{
13 /**
14 * {@inheritdoc}
15 */
16 public function getFunctions()
17 {
18 return array(
19 new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
20 );
21 }
22
23 /**
24 * {@inheritdoc}
25 */
26 public function getName()
27 {
28 return 'string_loader';
29 }
30}
31
32/**
33 * Loads a template from a string.
34 *
35 * <pre>
36 * {{ include(template_from_string("Hello {{ name }}")) }}
37 * </pre>
38 *
39 * @param Twig_Environment $env A Twig_Environment instance
40 * @param string $template A template as a string
41 *
42 * @return Twig_Template A Twig_Template instance
43 */
44function twig_template_from_string(Twig_Environment $env, $template)
45{
46 static $loader;
47
48 if (null === $loader) {
49 $loader = new Twig_Loader_String();
50 }
51
52 $current = $env->getLoader();
53 $env->setLoader($loader);
54 try {
55 $template = $env->loadTemplate($template);
56 } catch (Exception $e) {
57 $env->setLoader($current);
58
59 throw $e;
60 }
61 $env->setLoader($current);
62
63 return $template;
64}
diff --git a/vendor/twig/twig/lib/Twig/ExtensionInterface.php b/vendor/twig/twig/lib/Twig/ExtensionInterface.php
new file mode 100644
index 00000000..f189e9d9
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/ExtensionInterface.php
@@ -0,0 +1,83 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Interface implemented by extension classes.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17interface Twig_ExtensionInterface
18{
19 /**
20 * Initializes the runtime environment.
21 *
22 * This is where you can load some file that contains filter functions for instance.
23 *
24 * @param Twig_Environment $environment The current Twig_Environment instance
25 */
26 public function initRuntime(Twig_Environment $environment);
27
28 /**
29 * Returns the token parser instances to add to the existing list.
30 *
31 * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
32 */
33 public function getTokenParsers();
34
35 /**
36 * Returns the node visitor instances to add to the existing list.
37 *
38 * @return array An array of Twig_NodeVisitorInterface instances
39 */
40 public function getNodeVisitors();
41
42 /**
43 * Returns a list of filters to add to the existing list.
44 *
45 * @return array An array of filters
46 */
47 public function getFilters();
48
49 /**
50 * Returns a list of tests to add to the existing list.
51 *
52 * @return array An array of tests
53 */
54 public function getTests();
55
56 /**
57 * Returns a list of functions to add to the existing list.
58 *
59 * @return array An array of functions
60 */
61 public function getFunctions();
62
63 /**
64 * Returns a list of operators to add to the existing list.
65 *
66 * @return array An array of operators
67 */
68 public function getOperators();
69
70 /**
71 * Returns a list of global variables to add to the existing list.
72 *
73 * @return array An array of global variables
74 */
75 public function getGlobals();
76
77 /**
78 * Returns the name of the extension.
79 *
80 * @return string The extension name
81 */
82 public function getName();
83}
diff --git a/vendor/twig/twig/lib/Twig/Filter.php b/vendor/twig/twig/lib/Twig/Filter.php
new file mode 100644
index 00000000..5cfbb662
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Filter.php
@@ -0,0 +1,81 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Represents a template filter.
14 *
15 * Use Twig_SimpleFilter instead.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @deprecated since 1.12 (to be removed in 2.0)
19 */
20abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
21{
22 protected $options;
23 protected $arguments = array();
24
25 public function __construct(array $options = array())
26 {
27 $this->options = array_merge(array(
28 'needs_environment' => false,
29 'needs_context' => false,
30 'pre_escape' => null,
31 'preserves_safety' => null,
32 'callable' => null,
33 ), $options);
34 }
35
36 public function setArguments($arguments)
37 {
38 $this->arguments = $arguments;
39 }
40
41 public function getArguments()
42 {
43 return $this->arguments;
44 }
45
46 public function needsEnvironment()
47 {
48 return $this->options['needs_environment'];
49 }
50
51 public function needsContext()
52 {
53 return $this->options['needs_context'];
54 }
55
56 public function getSafe(Twig_Node $filterArgs)
57 {
58 if (isset($this->options['is_safe'])) {
59 return $this->options['is_safe'];
60 }
61
62 if (isset($this->options['is_safe_callback'])) {
63 return call_user_func($this->options['is_safe_callback'], $filterArgs);
64 }
65 }
66
67 public function getPreservesSafety()
68 {
69 return $this->options['preserves_safety'];
70 }
71
72 public function getPreEscape()
73 {
74 return $this->options['pre_escape'];
75 }
76
77 public function getCallable()
78 {
79 return $this->options['callable'];
80 }
81}
diff --git a/vendor/twig/twig/lib/Twig/Filter/Function.php b/vendor/twig/twig/lib/Twig/Filter/Function.php
new file mode 100644
index 00000000..ad374a55
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Filter/Function.php
@@ -0,0 +1,37 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Represents a function template filter.
14 *
15 * Use Twig_SimpleFilter instead.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @deprecated since 1.12 (to be removed in 2.0)
19 */
20class Twig_Filter_Function extends Twig_Filter
21{
22 protected $function;
23
24 public function __construct($function, array $options = array())
25 {
26 $options['callable'] = $function;
27
28 parent::__construct($options);
29
30 $this->function = $function;
31 }
32
33 public function compile()
34 {
35 return $this->function;
36 }
37}
diff --git a/vendor/twig/twig/lib/Twig/Filter/Method.php b/vendor/twig/twig/lib/Twig/Filter/Method.php
new file mode 100644
index 00000000..63c8c3be
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Filter/Method.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Represents a method template filter.
14 *
15 * Use Twig_SimpleFilter instead.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @deprecated since 1.12 (to be removed in 2.0)
19 */
20class Twig_Filter_Method extends Twig_Filter
21{
22 protected $extension;
23 protected $method;
24
25 public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
26 {
27 $options['callable'] = array($extension, $method);
28
29 parent::__construct($options);
30
31 $this->extension = $extension;
32 $this->method = $method;
33 }
34
35 public function compile()
36 {
37 return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
38 }
39}
diff --git a/vendor/twig/twig/lib/Twig/Filter/Node.php b/vendor/twig/twig/lib/Twig/Filter/Node.php
new file mode 100644
index 00000000..8744c5e0
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Filter/Node.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Represents a template filter as a node.
14 *
15 * Use Twig_SimpleFilter instead.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @deprecated since 1.12 (to be removed in 2.0)
19 */
20class Twig_Filter_Node extends Twig_Filter
21{
22 protected $class;
23
24 public function __construct($class, array $options = array())
25 {
26 parent::__construct($options);
27
28 $this->class = $class;
29 }
30
31 public function getClass()
32 {
33 return $this->class;
34 }
35
36 public function compile()
37 {
38 }
39}
diff --git a/vendor/twig/twig/lib/Twig/FilterCallableInterface.php b/vendor/twig/twig/lib/Twig/FilterCallableInterface.php
new file mode 100644
index 00000000..145534df
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/FilterCallableInterface.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
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 * Represents a callable template filter.
14 *
15 * Use Twig_SimpleFilter instead.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @deprecated since 1.12 (to be removed in 2.0)
19 */
20interface Twig_FilterCallableInterface
21{
22 public function getCallable();
23}
diff --git a/vendor/twig/twig/lib/Twig/FilterInterface.php b/vendor/twig/twig/lib/Twig/FilterInterface.php
new file mode 100644
index 00000000..5319ecc9
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/FilterInterface.php
@@ -0,0 +1,42 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a template filter.
14 *
15 * Use Twig_SimpleFilter instead.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @deprecated since 1.12 (to be removed in 2.0)
19 */
20interface Twig_FilterInterface
21{
22 /**
23 * Compiles a filter.
24 *
25 * @return string The PHP code for the filter
26 */
27 public function compile();
28
29 public function needsEnvironment();
30
31 public function needsContext();
32
33 public function getSafe(Twig_Node $filterArgs);
34
35 public function getPreservesSafety();
36
37 public function getPreEscape();
38
39 public function setArguments($arguments);
40
41 public function getArguments();
42}
diff --git a/vendor/twig/twig/lib/Twig/Function.php b/vendor/twig/twig/lib/Twig/Function.php
new file mode 100644
index 00000000..b5ffb2b0
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Function.php
@@ -0,0 +1,71 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a template function.
14 *
15 * Use Twig_SimpleFunction instead.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @deprecated since 1.12 (to be removed in 2.0)
19 */
20abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
21{
22 protected $options;
23 protected $arguments = array();
24
25 public function __construct(array $options = array())
26 {
27 $this->options = array_merge(array(
28 'needs_environment' => false,
29 'needs_context' => false,
30 'callable' => null,
31 ), $options);
32 }
33
34 public function setArguments($arguments)
35 {
36 $this->arguments = $arguments;
37 }
38
39 public function getArguments()
40 {
41 return $this->arguments;
42 }
43
44 public function needsEnvironment()
45 {
46 return $this->options['needs_environment'];
47 }
48
49 public function needsContext()
50 {
51 return $this->options['needs_context'];
52 }
53
54 public function getSafe(Twig_Node $functionArgs)
55 {
56 if (isset($this->options['is_safe'])) {
57 return $this->options['is_safe'];
58 }
59
60 if (isset($this->options['is_safe_callback'])) {
61 return call_user_func($this->options['is_safe_callback'], $functionArgs);
62 }
63
64 return array();
65 }
66
67 public function getCallable()
68 {
69 return $this->options['callable'];
70 }
71}
diff --git a/vendor/twig/twig/lib/Twig/Function/Function.php b/vendor/twig/twig/lib/Twig/Function/Function.php
new file mode 100644
index 00000000..d1e1b96a
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Function/Function.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2010 Arnaud Le Blanc
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a function template function.
15 *
16 * Use Twig_SimpleFunction instead.
17 *
18 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19 * @deprecated since 1.12 (to be removed in 2.0)
20 */
21class Twig_Function_Function extends Twig_Function
22{
23 protected $function;
24
25 public function __construct($function, array $options = array())
26 {
27 $options['callable'] = $function;
28
29 parent::__construct($options);
30
31 $this->function = $function;
32 }
33
34 public function compile()
35 {
36 return $this->function;
37 }
38}
diff --git a/vendor/twig/twig/lib/Twig/Function/Method.php b/vendor/twig/twig/lib/Twig/Function/Method.php
new file mode 100644
index 00000000..67039a95
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Function/Method.php
@@ -0,0 +1,40 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2010 Arnaud Le Blanc
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a method template function.
15 *
16 * Use Twig_SimpleFunction instead.
17 *
18 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19 * @deprecated since 1.12 (to be removed in 2.0)
20 */
21class Twig_Function_Method extends Twig_Function
22{
23 protected $extension;
24 protected $method;
25
26 public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
27 {
28 $options['callable'] = array($extension, $method);
29
30 parent::__construct($options);
31
32 $this->extension = $extension;
33 $this->method = $method;
34 }
35
36 public function compile()
37 {
38 return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
39 }
40}
diff --git a/vendor/twig/twig/lib/Twig/Function/Node.php b/vendor/twig/twig/lib/Twig/Function/Node.php
new file mode 100644
index 00000000..06a0d0db
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Function/Node.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Represents a template function as a node.
14 *
15 * Use Twig_SimpleFunction instead.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @deprecated since 1.12 (to be removed in 2.0)
19 */
20class Twig_Function_Node extends Twig_Function
21{
22 protected $class;
23
24 public function __construct($class, array $options = array())
25 {
26 parent::__construct($options);
27
28 $this->class = $class;
29 }
30
31 public function getClass()
32 {
33 return $this->class;
34 }
35
36 public function compile()
37 {
38 }
39}
diff --git a/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php b/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php
new file mode 100644
index 00000000..0aab4f5e
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
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 * Represents a callable template function.
14 *
15 * Use Twig_SimpleFunction instead.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @deprecated since 1.12 (to be removed in 2.0)
19 */
20interface Twig_FunctionCallableInterface
21{
22 public function getCallable();
23}
diff --git a/vendor/twig/twig/lib/Twig/FunctionInterface.php b/vendor/twig/twig/lib/Twig/FunctionInterface.php
new file mode 100644
index 00000000..67f4f89c
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/FunctionInterface.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 * (c) 2010 Arnaud Le Blanc
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a template function.
15 *
16 * Use Twig_SimpleFunction instead.
17 *
18 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19 * @deprecated since 1.12 (to be removed in 2.0)
20 */
21interface Twig_FunctionInterface
22{
23 /**
24 * Compiles a function.
25 *
26 * @return string The PHP code for the function
27 */
28 public function compile();
29
30 public function needsEnvironment();
31
32 public function needsContext();
33
34 public function getSafe(Twig_Node $filterArgs);
35
36 public function setArguments($arguments);
37
38 public function getArguments();
39}
diff --git a/vendor/twig/twig/lib/Twig/Lexer.php b/vendor/twig/twig/lib/Twig/Lexer.php
new file mode 100644
index 00000000..000b038e
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Lexer.php
@@ -0,0 +1,408 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Lexes a template string.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Lexer implements Twig_LexerInterface
19{
20 protected $tokens;
21 protected $code;
22 protected $cursor;
23 protected $lineno;
24 protected $end;
25 protected $state;
26 protected $states;
27 protected $brackets;
28 protected $env;
29 protected $filename;
30 protected $options;
31 protected $regexes;
32 protected $position;
33 protected $positions;
34 protected $currentVarBlockLine;
35
36 const STATE_DATA = 0;
37 const STATE_BLOCK = 1;
38 const STATE_VAR = 2;
39 const STATE_STRING = 3;
40 const STATE_INTERPOLATION = 4;
41
42 const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
43 const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
44 const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
45 const REGEX_DQ_STRING_DELIM = '/"/A';
46 const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
47 const PUNCTUATION = '()[]{}?:.,|';
48
49 public function __construct(Twig_Environment $env, array $options = array())
50 {
51 $this->env = $env;
52
53 $this->options = array_merge(array(
54 'tag_comment' => array('{#', '#}'),
55 'tag_block' => array('{%', '%}'),
56 'tag_variable' => array('{{', '}}'),
57 'whitespace_trim' => '-',
58 'interpolation' => array('#{', '}'),
59 ), $options);
60
61 $this->regexes = array(
62 'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
63 'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
64 'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
65 'operator' => $this->getOperatorRegex(),
66 'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
67 'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
68 'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
69 'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
70 'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
71 'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
72 );
73 }
74
75 /**
76 * Tokenizes a source code.
77 *
78 * @param string $code The source code
79 * @param string $filename A unique identifier for the source code
80 *
81 * @return Twig_TokenStream A token stream instance
82 */
83 public function tokenize($code, $filename = null)
84 {
85 if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
86 $mbEncoding = mb_internal_encoding();
87 mb_internal_encoding('ASCII');
88 }
89
90 $this->code = str_replace(array("\r\n", "\r"), "\n", $code);
91 $this->filename = $filename;
92 $this->cursor = 0;
93 $this->lineno = 1;
94 $this->end = strlen($this->code);
95 $this->tokens = array();
96 $this->state = self::STATE_DATA;
97 $this->states = array();
98 $this->brackets = array();
99 $this->position = -1;
100
101 // find all token starts in one go
102 preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
103 $this->positions = $matches;
104
105 while ($this->cursor < $this->end) {
106 // dispatch to the lexing functions depending
107 // on the current state
108 switch ($this->state) {
109 case self::STATE_DATA:
110 $this->lexData();
111 break;
112
113 case self::STATE_BLOCK:
114 $this->lexBlock();
115 break;
116
117 case self::STATE_VAR:
118 $this->lexVar();
119 break;
120
121 case self::STATE_STRING:
122 $this->lexString();
123 break;
124
125 case self::STATE_INTERPOLATION:
126 $this->lexInterpolation();
127 break;
128 }
129 }
130
131 $this->pushToken(Twig_Token::EOF_TYPE);
132
133 if (!empty($this->brackets)) {
134 list($expect, $lineno) = array_pop($this->brackets);
135 throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
136 }
137
138 if (isset($mbEncoding)) {
139 mb_internal_encoding($mbEncoding);
140 }
141
142 return new Twig_TokenStream($this->tokens, $this->filename);
143 }
144
145 protected function lexData()
146 {
147 // if no matches are left we return the rest of the template as simple text token
148 if ($this->position == count($this->positions[0]) - 1) {
149 $this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
150 $this->cursor = $this->end;
151
152 return;
153 }
154
155 // Find the first token after the current cursor
156 $position = $this->positions[0][++$this->position];
157 while ($position[1] < $this->cursor) {
158 if ($this->position == count($this->positions[0]) - 1) {
159 return;
160 }
161 $position = $this->positions[0][++$this->position];
162 }
163
164 // push the template text first
165 $text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
166 if (isset($this->positions[2][$this->position][0])) {
167 $text = rtrim($text);
168 }
169 $this->pushToken(Twig_Token::TEXT_TYPE, $text);
170 $this->moveCursor($textContent.$position[0]);
171
172 switch ($this->positions[1][$this->position][0]) {
173 case $this->options['tag_comment'][0]:
174 $this->lexComment();
175 break;
176
177 case $this->options['tag_block'][0]:
178 // raw data?
179 if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
180 $this->moveCursor($match[0]);
181 $this->lexRawData($match[1]);
182 // {% line \d+ %}
183 } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
184 $this->moveCursor($match[0]);
185 $this->lineno = (int) $match[1];
186 } else {
187 $this->pushToken(Twig_Token::BLOCK_START_TYPE);
188 $this->pushState(self::STATE_BLOCK);
189 $this->currentVarBlockLine = $this->lineno;
190 }
191 break;
192
193 case $this->options['tag_variable'][0]:
194 $this->pushToken(Twig_Token::VAR_START_TYPE);
195 $this->pushState(self::STATE_VAR);
196 $this->currentVarBlockLine = $this->lineno;
197 break;
198 }
199 }
200
201 protected function lexBlock()
202 {
203 if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
204 $this->pushToken(Twig_Token::BLOCK_END_TYPE);
205 $this->moveCursor($match[0]);
206 $this->popState();
207 } else {
208 $this->lexExpression();
209 }
210 }
211
212 protected function lexVar()
213 {
214 if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
215 $this->pushToken(Twig_Token::VAR_END_TYPE);
216 $this->moveCursor($match[0]);
217 $this->popState();
218 } else {
219 $this->lexExpression();
220 }
221 }
222
223 protected function lexExpression()
224 {
225 // whitespace
226 if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
227 $this->moveCursor($match[0]);
228
229 if ($this->cursor >= $this->end) {
230 throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
231 }
232 }
233
234 // operators
235 if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
236 $this->pushToken(Twig_Token::OPERATOR_TYPE, $match[0]);
237 $this->moveCursor($match[0]);
238 }
239 // names
240 elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
241 $this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
242 $this->moveCursor($match[0]);
243 }
244 // numbers
245 elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
246 $number = (float) $match[0]; // floats
247 if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
248 $number = (int) $match[0]; // integers lower than the maximum
249 }
250 $this->pushToken(Twig_Token::NUMBER_TYPE, $number);
251 $this->moveCursor($match[0]);
252 }
253 // punctuation
254 elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
255 // opening bracket
256 if (false !== strpos('([{', $this->code[$this->cursor])) {
257 $this->brackets[] = array($this->code[$this->cursor], $this->lineno);
258 }
259 // closing bracket
260 elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
261 if (empty($this->brackets)) {
262 throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
263 }
264
265 list($expect, $lineno) = array_pop($this->brackets);
266 if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
267 throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
268 }
269 }
270
271 $this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
272 ++$this->cursor;
273 }
274 // strings
275 elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
276 $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
277 $this->moveCursor($match[0]);
278 }
279 // opening double quoted string
280 elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
281 $this->brackets[] = array('"', $this->lineno);
282 $this->pushState(self::STATE_STRING);
283 $this->moveCursor($match[0]);
284 }
285 // unlexable
286 else {
287 throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
288 }
289 }
290
291 protected function lexRawData($tag)
292 {
293 if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
294 throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
295 }
296
297 $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
298 $this->moveCursor($text.$match[0][0]);
299
300 if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
301 $text = rtrim($text);
302 }
303
304 $this->pushToken(Twig_Token::TEXT_TYPE, $text);
305 }
306
307 protected function lexComment()
308 {
309 if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
310 throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
311 }
312
313 $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
314 }
315
316 protected function lexString()
317 {
318 if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
319 $this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
320 $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
321 $this->moveCursor($match[0]);
322 $this->pushState(self::STATE_INTERPOLATION);
323
324 } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
325 $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
326 $this->moveCursor($match[0]);
327
328 } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
329
330 list($expect, $lineno) = array_pop($this->brackets);
331 if ($this->code[$this->cursor] != '"') {
332 throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
333 }
334
335 $this->popState();
336 ++$this->cursor;
337 }
338 }
339
340 protected function lexInterpolation()
341 {
342 $bracket = end($this->brackets);
343 if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
344 array_pop($this->brackets);
345 $this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
346 $this->moveCursor($match[0]);
347 $this->popState();
348 } else {
349 $this->lexExpression();
350 }
351 }
352
353 protected function pushToken($type, $value = '')
354 {
355 // do not push empty text tokens
356 if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
357 return;
358 }
359
360 $this->tokens[] = new Twig_Token($type, $value, $this->lineno);
361 }
362
363 protected function moveCursor($text)
364 {
365 $this->cursor += strlen($text);
366 $this->lineno += substr_count($text, "\n");
367 }
368
369 protected function getOperatorRegex()
370 {
371 $operators = array_merge(
372 array('='),
373 array_keys($this->env->getUnaryOperators()),
374 array_keys($this->env->getBinaryOperators())
375 );
376
377 $operators = array_combine($operators, array_map('strlen', $operators));
378 arsort($operators);
379
380 $regex = array();
381 foreach ($operators as $operator => $length) {
382 // an operator that ends with a character must be followed by
383 // a whitespace or a parenthesis
384 if (ctype_alpha($operator[$length - 1])) {
385 $regex[] = preg_quote($operator, '/').'(?=[\s()])';
386 } else {
387 $regex[] = preg_quote($operator, '/');
388 }
389 }
390
391 return '/'.implode('|', $regex).'/A';
392 }
393
394 protected function pushState($state)
395 {
396 $this->states[] = $this->state;
397 $this->state = $state;
398 }
399
400 protected function popState()
401 {
402 if (0 === count($this->states)) {
403 throw new Exception('Cannot pop state without a previous state');
404 }
405
406 $this->state = array_pop($this->states);
407 }
408}
diff --git a/vendor/twig/twig/lib/Twig/LexerInterface.php b/vendor/twig/twig/lib/Twig/LexerInterface.php
new file mode 100644
index 00000000..4b83f81b
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/LexerInterface.php
@@ -0,0 +1,29 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Interface implemented by lexer classes.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18interface Twig_LexerInterface
19{
20 /**
21 * Tokenizes a source code.
22 *
23 * @param string $code The source code
24 * @param string $filename A unique identifier for the source code
25 *
26 * @return Twig_TokenStream A token stream instance
27 */
28 public function tokenize($code, $filename = null);
29}
diff --git a/vendor/twig/twig/lib/Twig/Loader/Array.php b/vendor/twig/twig/lib/Twig/Loader/Array.php
new file mode 100644
index 00000000..89087aea
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Loader/Array.php
@@ -0,0 +1,98 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Loads a template from an array.
14 *
15 * When using this loader with a cache mechanism, you should know that a new cache
16 * key is generated each time a template content "changes" (the cache key being the
17 * source code of the template). If you don't want to see your cache grows out of
18 * control, you need to take care of clearing the old cache file by yourself.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 */
22class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
23{
24 protected $templates;
25
26 /**
27 * Constructor.
28 *
29 * @param array $templates An array of templates (keys are the names, and values are the source code)
30 *
31 * @see Twig_Loader
32 */
33 public function __construct(array $templates)
34 {
35 $this->templates = array();
36 foreach ($templates as $name => $template) {
37 $this->templates[$name] = $template;
38 }
39 }
40
41 /**
42 * Adds or overrides a template.
43 *
44 * @param string $name The template name
45 * @param string $template The template source
46 */
47 public function setTemplate($name, $template)
48 {
49 $this->templates[(string) $name] = $template;
50 }
51
52 /**
53 * {@inheritdoc}
54 */
55 public function getSource($name)
56 {
57 $name = (string) $name;
58 if (!isset($this->templates[$name])) {
59 throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
60 }
61
62 return $this->templates[$name];
63 }
64
65 /**
66 * {@inheritdoc}
67 */
68 public function exists($name)
69 {
70 return isset($this->templates[(string) $name]);
71 }
72
73 /**
74 * {@inheritdoc}
75 */
76 public function getCacheKey($name)
77 {
78 $name = (string) $name;
79 if (!isset($this->templates[$name])) {
80 throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
81 }
82
83 return $this->templates[$name];
84 }
85
86 /**
87 * {@inheritdoc}
88 */
89 public function isFresh($name, $time)
90 {
91 $name = (string) $name;
92 if (!isset($this->templates[$name])) {
93 throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
94 }
95
96 return true;
97 }
98}
diff --git a/vendor/twig/twig/lib/Twig/Loader/Chain.php b/vendor/twig/twig/lib/Twig/Loader/Chain.php
new file mode 100644
index 00000000..1f1cf065
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Loader/Chain.php
@@ -0,0 +1,139 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Loads templates from other loaders.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
18{
19 private $hasSourceCache = array();
20 protected $loaders;
21
22 /**
23 * Constructor.
24 *
25 * @param Twig_LoaderInterface[] $loaders An array of loader instances
26 */
27 public function __construct(array $loaders = array())
28 {
29 $this->loaders = array();
30 foreach ($loaders as $loader) {
31 $this->addLoader($loader);
32 }
33 }
34
35 /**
36 * Adds a loader instance.
37 *
38 * @param Twig_LoaderInterface $loader A Loader instance
39 */
40 public function addLoader(Twig_LoaderInterface $loader)
41 {
42 $this->loaders[] = $loader;
43 $this->hasSourceCache = array();
44 }
45
46 /**
47 * {@inheritdoc}
48 */
49 public function getSource($name)
50 {
51 $exceptions = array();
52 foreach ($this->loaders as $loader) {
53 if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
54 continue;
55 }
56
57 try {
58 return $loader->getSource($name);
59 } catch (Twig_Error_Loader $e) {
60 $exceptions[] = $e->getMessage();
61 }
62 }
63
64 throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions)));
65 }
66
67 /**
68 * {@inheritdoc}
69 */
70 public function exists($name)
71 {
72 $name = (string) $name;
73
74 if (isset($this->hasSourceCache[$name])) {
75 return $this->hasSourceCache[$name];
76 }
77
78 foreach ($this->loaders as $loader) {
79 if ($loader instanceof Twig_ExistsLoaderInterface) {
80 if ($loader->exists($name)) {
81 return $this->hasSourceCache[$name] = true;
82 }
83
84 continue;
85 }
86
87 try {
88 $loader->getSource($name);
89
90 return $this->hasSourceCache[$name] = true;
91 } catch (Twig_Error_Loader $e) {
92 }
93 }
94
95 return $this->hasSourceCache[$name] = false;
96 }
97
98 /**
99 * {@inheritdoc}
100 */
101 public function getCacheKey($name)
102 {
103 $exceptions = array();
104 foreach ($this->loaders as $loader) {
105 if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
106 continue;
107 }
108
109 try {
110 return $loader->getCacheKey($name);
111 } catch (Twig_Error_Loader $e) {
112 $exceptions[] = get_class($loader).': '.$e->getMessage();
113 }
114 }
115
116 throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
117 }
118
119 /**
120 * {@inheritdoc}
121 */
122 public function isFresh($name, $time)
123 {
124 $exceptions = array();
125 foreach ($this->loaders as $loader) {
126 if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
127 continue;
128 }
129
130 try {
131 return $loader->isFresh($name, $time);
132 } catch (Twig_Error_Loader $e) {
133 $exceptions[] = get_class($loader).': '.$e->getMessage();
134 }
135 }
136
137 throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
138 }
139}
diff --git a/vendor/twig/twig/lib/Twig/Loader/Filesystem.php b/vendor/twig/twig/lib/Twig/Loader/Filesystem.php
new file mode 100644
index 00000000..d47781ab
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Loader/Filesystem.php
@@ -0,0 +1,226 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Loads template from the filesystem.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
18{
19 /** Identifier of the main namespace. */
20 const MAIN_NAMESPACE = '__main__';
21
22 protected $paths;
23 protected $cache;
24
25 /**
26 * Constructor.
27 *
28 * @param string|array $paths A path or an array of paths where to look for templates
29 */
30 public function __construct($paths = array())
31 {
32 if ($paths) {
33 $this->setPaths($paths);
34 }
35 }
36
37 /**
38 * Returns the paths to the templates.
39 *
40 * @param string $namespace A path namespace
41 *
42 * @return array The array of paths where to look for templates
43 */
44 public function getPaths($namespace = self::MAIN_NAMESPACE)
45 {
46 return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
47 }
48
49 /**
50 * Returns the path namespaces.
51 *
52 * The main namespace is always defined.
53 *
54 * @return array The array of defined namespaces
55 */
56 public function getNamespaces()
57 {
58 return array_keys($this->paths);
59 }
60
61 /**
62 * Sets the paths where templates are stored.
63 *
64 * @param string|array $paths A path or an array of paths where to look for templates
65 * @param string $namespace A path namespace
66 */
67 public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
68 {
69 if (!is_array($paths)) {
70 $paths = array($paths);
71 }
72
73 $this->paths[$namespace] = array();
74 foreach ($paths as $path) {
75 $this->addPath($path, $namespace);
76 }
77 }
78
79 /**
80 * Adds a path where templates are stored.
81 *
82 * @param string $path A path where to look for templates
83 * @param string $namespace A path name
84 *
85 * @throws Twig_Error_Loader
86 */
87 public function addPath($path, $namespace = self::MAIN_NAMESPACE)
88 {
89 // invalidate the cache
90 $this->cache = array();
91
92 if (!is_dir($path)) {
93 throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
94 }
95
96 $this->paths[$namespace][] = rtrim($path, '/\\');
97 }
98
99 /**
100 * Prepends a path where templates are stored.
101 *
102 * @param string $path A path where to look for templates
103 * @param string $namespace A path name
104 *
105 * @throws Twig_Error_Loader
106 */
107 public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
108 {
109 // invalidate the cache
110 $this->cache = array();
111
112 if (!is_dir($path)) {
113 throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
114 }
115
116 $path = rtrim($path, '/\\');
117
118 if (!isset($this->paths[$namespace])) {
119 $this->paths[$namespace][] = $path;
120 } else {
121 array_unshift($this->paths[$namespace], $path);
122 }
123 }
124
125 /**
126 * {@inheritdoc}
127 */
128 public function getSource($name)
129 {
130 return file_get_contents($this->findTemplate($name));
131 }
132
133 /**
134 * {@inheritdoc}
135 */
136 public function getCacheKey($name)
137 {
138 return $this->findTemplate($name);
139 }
140
141 /**
142 * {@inheritdoc}
143 */
144 public function exists($name)
145 {
146 $name = (string) $name;
147 if (isset($this->cache[$name])) {
148 return true;
149 }
150
151 try {
152 $this->findTemplate($name);
153
154 return true;
155 } catch (Twig_Error_Loader $exception) {
156 return false;
157 }
158 }
159
160 /**
161 * {@inheritdoc}
162 */
163 public function isFresh($name, $time)
164 {
165 return filemtime($this->findTemplate($name)) <= $time;
166 }
167
168 protected function findTemplate($name)
169 {
170 $name = (string) $name;
171
172 // normalize name
173 $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'));
174
175 if (isset($this->cache[$name])) {
176 return $this->cache[$name];
177 }
178
179 $this->validateName($name);
180
181 $namespace = self::MAIN_NAMESPACE;
182 if (isset($name[0]) && '@' == $name[0]) {
183 if (false === $pos = strpos($name, '/')) {
184 throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
185 }
186
187 $namespace = substr($name, 1, $pos - 1);
188
189 $name = substr($name, $pos + 1);
190 }
191
192 if (!isset($this->paths[$namespace])) {
193 throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
194 }
195
196 foreach ($this->paths[$namespace] as $path) {
197 if (is_file($path.'/'.$name)) {
198 return $this->cache[$name] = $path.'/'.$name;
199 }
200 }
201
202 throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
203 }
204
205 protected function validateName($name)
206 {
207 if (false !== strpos($name, "\0")) {
208 throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
209 }
210
211 $name = ltrim($name, '/');
212 $parts = explode('/', $name);
213 $level = 0;
214 foreach ($parts as $part) {
215 if ('..' === $part) {
216 --$level;
217 } elseif ('.' !== $part) {
218 ++$level;
219 }
220
221 if ($level < 0) {
222 throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
223 }
224 }
225 }
226}
diff --git a/vendor/twig/twig/lib/Twig/Loader/String.php b/vendor/twig/twig/lib/Twig/Loader/String.php
new file mode 100644
index 00000000..8ad9856c
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Loader/String.php
@@ -0,0 +1,59 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Loads a template from a string.
14 *
15 * This loader should only be used for unit testing as it has many limitations
16 * (for instance, the include or extends tag does not make any sense for a string
17 * loader).
18 *
19 * When using this loader with a cache mechanism, you should know that a new cache
20 * key is generated each time a template content "changes" (the cache key being the
21 * source code of the template). If you don't want to see your cache grows out of
22 * control, you need to take care of clearing the old cache file by yourself.
23 *
24 * @author Fabien Potencier <fabien@symfony.com>
25 */
26class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
27{
28 /**
29 * {@inheritdoc}
30 */
31 public function getSource($name)
32 {
33 return $name;
34 }
35
36 /**
37 * {@inheritdoc}
38 */
39 public function exists($name)
40 {
41 return true;
42 }
43
44 /**
45 * {@inheritdoc}
46 */
47 public function getCacheKey($name)
48 {
49 return $name;
50 }
51
52 /**
53 * {@inheritdoc}
54 */
55 public function isFresh($name, $time)
56 {
57 return true;
58 }
59}
diff --git a/vendor/twig/twig/lib/Twig/LoaderInterface.php b/vendor/twig/twig/lib/Twig/LoaderInterface.php
new file mode 100644
index 00000000..927786d1
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/LoaderInterface.php
@@ -0,0 +1,52 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Interface all loaders must implement.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17interface Twig_LoaderInterface
18{
19 /**
20 * Gets the source code of a template, given its name.
21 *
22 * @param string $name The name of the template to load
23 *
24 * @return string The template source code
25 *
26 * @throws Twig_Error_Loader When $name is not found
27 */
28 public function getSource($name);
29
30 /**
31 * Gets the cache key to use for the cache for a given template name.
32 *
33 * @param string $name The name of the template to load
34 *
35 * @return string The cache key
36 *
37 * @throws Twig_Error_Loader When $name is not found
38 */
39 public function getCacheKey($name);
40
41 /**
42 * Returns true if the template is still fresh.
43 *
44 * @param string $name The template name
45 * @param timestamp $time The last modification time of the cached template
46 *
47 * @return Boolean true if the template is fresh, false otherwise
48 *
49 * @throws Twig_Error_Loader When $name is not found
50 */
51 public function isFresh($name, $time);
52}
diff --git a/vendor/twig/twig/lib/Twig/Markup.php b/vendor/twig/twig/lib/Twig/Markup.php
new file mode 100644
index 00000000..69871fcb
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Markup.php
@@ -0,0 +1,37 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Marks a content as safe.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Markup implements Countable
18{
19 protected $content;
20 protected $charset;
21
22 public function __construct($content, $charset)
23 {
24 $this->content = (string) $content;
25 $this->charset = $charset;
26 }
27
28 public function __toString()
29 {
30 return $this->content;
31 }
32
33 public function count()
34 {
35 return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
36 }
37}
diff --git a/vendor/twig/twig/lib/Twig/Node.php b/vendor/twig/twig/lib/Twig/Node.php
new file mode 100644
index 00000000..931b4635
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node.php
@@ -0,0 +1,226 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a node in the AST.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node implements Twig_NodeInterface
19{
20 protected $nodes;
21 protected $attributes;
22 protected $lineno;
23 protected $tag;
24
25 /**
26 * Constructor.
27 *
28 * The nodes are automatically made available as properties ($this->node).
29 * The attributes are automatically made available as array items ($this['name']).
30 *
31 * @param array $nodes An array of named nodes
32 * @param array $attributes An array of attributes (should not be nodes)
33 * @param integer $lineno The line number
34 * @param string $tag The tag name associated with the Node
35 */
36 public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
37 {
38 $this->nodes = $nodes;
39 $this->attributes = $attributes;
40 $this->lineno = $lineno;
41 $this->tag = $tag;
42 }
43
44 public function __toString()
45 {
46 $attributes = array();
47 foreach ($this->attributes as $name => $value) {
48 $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
49 }
50
51 $repr = array(get_class($this).'('.implode(', ', $attributes));
52
53 if (count($this->nodes)) {
54 foreach ($this->nodes as $name => $node) {
55 $len = strlen($name) + 4;
56 $noderepr = array();
57 foreach (explode("\n", (string) $node) as $line) {
58 $noderepr[] = str_repeat(' ', $len).$line;
59 }
60
61 $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
62 }
63
64 $repr[] = ')';
65 } else {
66 $repr[0] .= ')';
67 }
68
69 return implode("\n", $repr);
70 }
71
72 public function toXml($asDom = false)
73 {
74 $dom = new DOMDocument('1.0', 'UTF-8');
75 $dom->formatOutput = true;
76 $dom->appendChild($xml = $dom->createElement('twig'));
77
78 $xml->appendChild($node = $dom->createElement('node'));
79 $node->setAttribute('class', get_class($this));
80
81 foreach ($this->attributes as $name => $value) {
82 $node->appendChild($attribute = $dom->createElement('attribute'));
83 $attribute->setAttribute('name', $name);
84 $attribute->appendChild($dom->createTextNode($value));
85 }
86
87 foreach ($this->nodes as $name => $n) {
88 if (null === $n) {
89 continue;
90 }
91
92 $child = $n->toXml(true)->getElementsByTagName('node')->item(0);
93 $child = $dom->importNode($child, true);
94 $child->setAttribute('name', $name);
95
96 $node->appendChild($child);
97 }
98
99 return $asDom ? $dom : $dom->saveXml();
100 }
101
102 public function compile(Twig_Compiler $compiler)
103 {
104 foreach ($this->nodes as $node) {
105 $node->compile($compiler);
106 }
107 }
108
109 public function getLine()
110 {
111 return $this->lineno;
112 }
113
114 public function getNodeTag()
115 {
116 return $this->tag;
117 }
118
119 /**
120 * Returns true if the attribute is defined.
121 *
122 * @param string The attribute name
123 *
124 * @return Boolean true if the attribute is defined, false otherwise
125 */
126 public function hasAttribute($name)
127 {
128 return array_key_exists($name, $this->attributes);
129 }
130
131 /**
132 * Gets an attribute.
133 *
134 * @param string The attribute name
135 *
136 * @return mixed The attribute value
137 */
138 public function getAttribute($name)
139 {
140 if (!array_key_exists($name, $this->attributes)) {
141 throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
142 }
143
144 return $this->attributes[$name];
145 }
146
147 /**
148 * Sets an attribute.
149 *
150 * @param string The attribute name
151 * @param mixed The attribute value
152 */
153 public function setAttribute($name, $value)
154 {
155 $this->attributes[$name] = $value;
156 }
157
158 /**
159 * Removes an attribute.
160 *
161 * @param string The attribute name
162 */
163 public function removeAttribute($name)
164 {
165 unset($this->attributes[$name]);
166 }
167
168 /**
169 * Returns true if the node with the given identifier exists.
170 *
171 * @param string The node name
172 *
173 * @return Boolean true if the node with the given name exists, false otherwise
174 */
175 public function hasNode($name)
176 {
177 return array_key_exists($name, $this->nodes);
178 }
179
180 /**
181 * Gets a node by name.
182 *
183 * @param string The node name
184 *
185 * @return Twig_Node A Twig_Node instance
186 */
187 public function getNode($name)
188 {
189 if (!array_key_exists($name, $this->nodes)) {
190 throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
191 }
192
193 return $this->nodes[$name];
194 }
195
196 /**
197 * Sets a node.
198 *
199 * @param string The node name
200 * @param Twig_Node A Twig_Node instance
201 */
202 public function setNode($name, $node = null)
203 {
204 $this->nodes[$name] = $node;
205 }
206
207 /**
208 * Removes a node by name.
209 *
210 * @param string The node name
211 */
212 public function removeNode($name)
213 {
214 unset($this->nodes[$name]);
215 }
216
217 public function count()
218 {
219 return count($this->nodes);
220 }
221
222 public function getIterator()
223 {
224 return new ArrayIterator($this->nodes);
225 }
226}
diff --git a/vendor/twig/twig/lib/Twig/Node/AutoEscape.php b/vendor/twig/twig/lib/Twig/Node/AutoEscape.php
new file mode 100644
index 00000000..8f190e0b
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/AutoEscape.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Represents an autoescape node.
14 *
15 * The value is the escaping strategy (can be html, js, ...)
16 *
17 * The true value is equivalent to html.
18 *
19 * If autoescaping is disabled, then the value is false.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 */
23class Twig_Node_AutoEscape extends Twig_Node
24{
25 public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
26 {
27 parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
28 }
29
30 /**
31 * Compiles the node to PHP.
32 *
33 * @param Twig_Compiler A Twig_Compiler instance
34 */
35 public function compile(Twig_Compiler $compiler)
36 {
37 $compiler->subcompile($this->getNode('body'));
38 }
39}
diff --git a/vendor/twig/twig/lib/Twig/Node/Block.php b/vendor/twig/twig/lib/Twig/Node/Block.php
new file mode 100644
index 00000000..50eb67ed
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Block.php
@@ -0,0 +1,44 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a block node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_Block extends Twig_Node
19{
20 public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
21 {
22 parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
23 }
24
25 /**
26 * Compiles the node to PHP.
27 *
28 * @param Twig_Compiler A Twig_Compiler instance
29 */
30 public function compile(Twig_Compiler $compiler)
31 {
32 $compiler
33 ->addDebugInfo($this)
34 ->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n")
35 ->indent()
36 ;
37
38 $compiler
39 ->subcompile($this->getNode('body'))
40 ->outdent()
41 ->write("}\n\n")
42 ;
43 }
44}
diff --git a/vendor/twig/twig/lib/Twig/Node/BlockReference.php b/vendor/twig/twig/lib/Twig/Node/BlockReference.php
new file mode 100644
index 00000000..013e369e
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/BlockReference.php
@@ -0,0 +1,37 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a block call node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
19{
20 public function __construct($name, $lineno, $tag = null)
21 {
22 parent::__construct(array(), array('name' => $name), $lineno, $tag);
23 }
24
25 /**
26 * Compiles the node to PHP.
27 *
28 * @param Twig_Compiler A Twig_Compiler instance
29 */
30 public function compile(Twig_Compiler $compiler)
31 {
32 $compiler
33 ->addDebugInfo($this)
34 ->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
35 ;
36 }
37}
diff --git a/vendor/twig/twig/lib/Twig/Node/Body.php b/vendor/twig/twig/lib/Twig/Node/Body.php
new file mode 100644
index 00000000..3ffb1342
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Body.php
@@ -0,0 +1,19 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Represents a body node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Body extends Twig_Node
18{
19}
diff --git a/vendor/twig/twig/lib/Twig/Node/Do.php b/vendor/twig/twig/lib/Twig/Node/Do.php
new file mode 100644
index 00000000..c528066b
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Do.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Represents a do node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Do extends Twig_Node
18{
19 public function __construct(Twig_Node_Expression $expr, $lineno, $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 A Twig_Compiler instance
28 */
29 public function compile(Twig_Compiler $compiler)
30 {
31 $compiler
32 ->addDebugInfo($this)
33 ->write('')
34 ->subcompile($this->getNode('expr'))
35 ->raw(";\n")
36 ;
37 }
38}
diff --git a/vendor/twig/twig/lib/Twig/Node/Embed.php b/vendor/twig/twig/lib/Twig/Node/Embed.php
new file mode 100644
index 00000000..4c9456dc
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Embed.php
@@ -0,0 +1,38 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
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 * Represents an embed node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Embed extends Twig_Node_Include
18{
19 // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
20 public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
21 {
22 parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
23
24 $this->setAttribute('filename', $filename);
25 $this->setAttribute('index', $index);
26 }
27
28 protected function addGetTemplate(Twig_Compiler $compiler)
29 {
30 $compiler
31 ->write("\$this->env->loadTemplate(")
32 ->string($this->getAttribute('filename'))
33 ->raw(', ')
34 ->string($this->getAttribute('index'))
35 ->raw(")")
36 ;
37 }
38}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression.php b/vendor/twig/twig/lib/Twig/Node/Expression.php
new file mode 100644
index 00000000..a7382e7d
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression.php
@@ -0,0 +1,20 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Abstract class for all nodes that represents an expression.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18abstract class Twig_Node_Expression extends Twig_Node
19{
20}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Array.php b/vendor/twig/twig/lib/Twig/Node/Expression/Array.php
new file mode 100644
index 00000000..1da785fe
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Array.php
@@ -0,0 +1,86 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Array extends Twig_Node_Expression
12{
13 protected $index;
14
15 public function __construct(array $elements, $lineno)
16 {
17 parent::__construct($elements, array(), $lineno);
18
19 $this->index = -1;
20 foreach ($this->getKeyValuePairs() as $pair) {
21 if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
22 $this->index = $pair['key']->getAttribute('value');
23 }
24 }
25 }
26
27 public function getKeyValuePairs()
28 {
29 $pairs = array();
30
31 foreach (array_chunk($this->nodes, 2) as $pair) {
32 $pairs[] = array(
33 'key' => $pair[0],
34 'value' => $pair[1],
35 );
36 }
37
38 return $pairs;
39 }
40
41 public function hasElement(Twig_Node_Expression $key)
42 {
43 foreach ($this->getKeyValuePairs() as $pair) {
44 // we compare the string representation of the keys
45 // to avoid comparing the line numbers which are not relevant here.
46 if ((string) $key == (string) $pair['key']) {
47 return true;
48 }
49 }
50
51 return false;
52 }
53
54 public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
55 {
56 if (null === $key) {
57 $key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine());
58 }
59
60 array_push($this->nodes, $key, $value);
61 }
62
63 /**
64 * Compiles the node to PHP.
65 *
66 * @param Twig_Compiler A Twig_Compiler instance
67 */
68 public function compile(Twig_Compiler $compiler)
69 {
70 $compiler->raw('array(');
71 $first = true;
72 foreach ($this->getKeyValuePairs() as $pair) {
73 if (!$first) {
74 $compiler->raw(', ');
75 }
76 $first = false;
77
78 $compiler
79 ->subcompile($pair['key'])
80 ->raw(' => ')
81 ->subcompile($pair['value'])
82 ;
83 }
84 $compiler->raw(')');
85 }
86}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php b/vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php
new file mode 100644
index 00000000..2ddea78c
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
14{
15 /**
16 * Compiles the node to PHP.
17 *
18 * @param Twig_Compiler A Twig_Compiler instance
19 */
20 public function compile(Twig_Compiler $compiler)
21 {
22 $compiler
23 ->raw('$context[')
24 ->string($this->getAttribute('name'))
25 ->raw(']')
26 ;
27 }
28}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary.php
new file mode 100644
index 00000000..9dd5de2c
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary.php
@@ -0,0 +1,40 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
13{
14 public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
15 {
16 parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
17 }
18
19 /**
20 * Compiles the node to PHP.
21 *
22 * @param Twig_Compiler A Twig_Compiler instance
23 */
24 public function compile(Twig_Compiler $compiler)
25 {
26 $compiler
27 ->raw('(')
28 ->subcompile($this->getNode('left'))
29 ->raw(' ')
30 ;
31 $this->operator($compiler);
32 $compiler
33 ->raw(' ')
34 ->subcompile($this->getNode('right'))
35 ->raw(')')
36 ;
37 }
38
39 abstract public function operator(Twig_Compiler $compiler);
40}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php
new file mode 100644
index 00000000..0ef8e117
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('+');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php
new file mode 100644
index 00000000..d5752ebb
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('&&');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php
new file mode 100644
index 00000000..9a46d845
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('&');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php
new file mode 100644
index 00000000..058a20bf
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('|');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php
new file mode 100644
index 00000000..f4da73d4
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('^');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php
new file mode 100644
index 00000000..f9a64627
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('.');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.php
new file mode 100644
index 00000000..e0797a61
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('/');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php
new file mode 100644
index 00000000..7b1236d0
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php
@@ -0,0 +1,17 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary
12{
13 public function operator(Twig_Compiler $compiler)
14 {
15 return $compiler->raw('==');
16 }
17}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php
new file mode 100644
index 00000000..7fbd0556
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php
@@ -0,0 +1,29 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
12{
13 /**
14 * Compiles the node to PHP.
15 *
16 * @param Twig_Compiler A Twig_Compiler instance
17 */
18 public function compile(Twig_Compiler $compiler)
19 {
20 $compiler->raw('intval(floor(');
21 parent::compile($compiler);
22 $compiler->raw('))');
23 }
24
25 public function operator(Twig_Compiler $compiler)
26 {
27 return $compiler->raw('/');
28 }
29}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php
new file mode 100644
index 00000000..a110bd92
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php
@@ -0,0 +1,17 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary
12{
13 public function operator(Twig_Compiler $compiler)
14 {
15 return $compiler->raw('>');
16 }
17}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php
new file mode 100644
index 00000000..3754fed2
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php
@@ -0,0 +1,17 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Binary
12{
13 public function operator(Twig_Compiler $compiler)
14 {
15 return $compiler->raw('>=');
16 }
17}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.php
new file mode 100644
index 00000000..788f9377
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
12{
13 /**
14 * Compiles the node to PHP.
15 *
16 * @param Twig_Compiler A Twig_Compiler instance
17 */
18 public function compile(Twig_Compiler $compiler)
19 {
20 $compiler
21 ->raw('twig_in_filter(')
22 ->subcompile($this->getNode('left'))
23 ->raw(', ')
24 ->subcompile($this->getNode('right'))
25 ->raw(')')
26 ;
27 }
28
29 public function operator(Twig_Compiler $compiler)
30 {
31 return $compiler->raw('in');
32 }
33}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php
new file mode 100644
index 00000000..45fd3004
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php
@@ -0,0 +1,17 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary
12{
13 public function operator(Twig_Compiler $compiler)
14 {
15 return $compiler->raw('<');
16 }
17}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php
new file mode 100644
index 00000000..e38e257c
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php
@@ -0,0 +1,17 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary
12{
13 public function operator(Twig_Compiler $compiler)
14 {
15 return $compiler->raw('<=');
16 }
17}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php
new file mode 100644
index 00000000..9924114f
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('%');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php
new file mode 100644
index 00000000..c91529ca
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('*');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php
new file mode 100644
index 00000000..26867ba2
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php
@@ -0,0 +1,17 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary
12{
13 public function operator(Twig_Compiler $compiler)
14 {
15 return $compiler->raw('!=');
16 }
17}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php
new file mode 100644
index 00000000..f347b7b6
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
12{
13 /**
14 * Compiles the node to PHP.
15 *
16 * @param Twig_Compiler A Twig_Compiler instance
17 */
18 public function compile(Twig_Compiler $compiler)
19 {
20 $compiler
21 ->raw('!twig_in_filter(')
22 ->subcompile($this->getNode('left'))
23 ->raw(', ')
24 ->subcompile($this->getNode('right'))
25 ->raw(')')
26 ;
27 }
28
29 public function operator(Twig_Compiler $compiler)
30 {
31 return $compiler->raw('not in');
32 }
33}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php
new file mode 100644
index 00000000..adba49c6
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('||');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.php
new file mode 100644
index 00000000..b2c59040
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
12{
13 /**
14 * Compiles the node to PHP.
15 *
16 * @param Twig_Compiler A Twig_Compiler instance
17 */
18 public function compile(Twig_Compiler $compiler)
19 {
20 $compiler
21 ->raw('pow(')
22 ->subcompile($this->getNode('left'))
23 ->raw(', ')
24 ->subcompile($this->getNode('right'))
25 ->raw(')')
26 ;
27 }
28
29 public function operator(Twig_Compiler $compiler)
30 {
31 return $compiler->raw('**');
32 }
33}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.php
new file mode 100644
index 00000000..bea4f2a6
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
12{
13 /**
14 * Compiles the node to PHP.
15 *
16 * @param Twig_Compiler A Twig_Compiler instance
17 */
18 public function compile(Twig_Compiler $compiler)
19 {
20 $compiler
21 ->raw('range(')
22 ->subcompile($this->getNode('left'))
23 ->raw(', ')
24 ->subcompile($this->getNode('right'))
25 ->raw(')')
26 ;
27 }
28
29 public function operator(Twig_Compiler $compiler)
30 {
31 return $compiler->raw('..');
32 }
33}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php
new file mode 100644
index 00000000..d4463991
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 return $compiler->raw('-');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.php b/vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.php
new file mode 100644
index 00000000..647196eb
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.php
@@ -0,0 +1,51 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a block call node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
19{
20 public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null)
21 {
22 parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag);
23 }
24
25 /**
26 * Compiles the node to PHP.
27 *
28 * @param Twig_Compiler A Twig_Compiler instance
29 */
30 public function compile(Twig_Compiler $compiler)
31 {
32 if ($this->getAttribute('as_string')) {
33 $compiler->raw('(string) ');
34 }
35
36 if ($this->getAttribute('output')) {
37 $compiler
38 ->addDebugInfo($this)
39 ->write("\$this->displayBlock(")
40 ->subcompile($this->getNode('name'))
41 ->raw(", \$context, \$blocks);\n")
42 ;
43 } else {
44 $compiler
45 ->raw("\$this->renderBlock(")
46 ->subcompile($this->getNode('name'))
47 ->raw(", \$context, \$blocks)")
48 ;
49 }
50 }
51}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Call.php b/vendor/twig/twig/lib/Twig/Node/Expression/Call.php
new file mode 100644
index 00000000..dba9b0e6
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Call.php
@@ -0,0 +1,178 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
12{
13 protected function compileCallable(Twig_Compiler $compiler)
14 {
15 $callable = $this->getAttribute('callable');
16
17 $closingParenthesis = false;
18 if ($callable) {
19 if (is_string($callable)) {
20 $compiler->raw($callable);
21 } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {
22 $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
23 } else {
24 $type = ucfirst($this->getAttribute('type'));
25 $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
26 $closingParenthesis = true;
27 }
28 } else {
29 $compiler->raw($this->getAttribute('thing')->compile());
30 }
31
32 $this->compileArguments($compiler);
33
34 if ($closingParenthesis) {
35 $compiler->raw(')');
36 }
37 }
38
39 protected function compileArguments(Twig_Compiler $compiler)
40 {
41 $compiler->raw('(');
42
43 $first = true;
44
45 if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
46 $compiler->raw('$this->env');
47 $first = false;
48 }
49
50 if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
51 if (!$first) {
52 $compiler->raw(', ');
53 }
54 $compiler->raw('$context');
55 $first = false;
56 }
57
58 if ($this->hasAttribute('arguments')) {
59 foreach ($this->getAttribute('arguments') as $argument) {
60 if (!$first) {
61 $compiler->raw(', ');
62 }
63 $compiler->string($argument);
64 $first = false;
65 }
66 }
67
68 if ($this->hasNode('node')) {
69 if (!$first) {
70 $compiler->raw(', ');
71 }
72 $compiler->subcompile($this->getNode('node'));
73 $first = false;
74 }
75
76 if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) {
77 $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
78
79 $arguments = $this->getArguments($callable, $this->getNode('arguments'));
80
81 foreach ($arguments as $node) {
82 if (!$first) {
83 $compiler->raw(', ');
84 }
85 $compiler->subcompile($node);
86 $first = false;
87 }
88 }
89
90 $compiler->raw(')');
91 }
92
93 protected function getArguments($callable, $arguments)
94 {
95 $parameters = array();
96 $named = false;
97 foreach ($arguments as $name => $node) {
98 if (!is_int($name)) {
99 $named = true;
100 $name = $this->normalizeName($name);
101 } elseif ($named) {
102 throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
103 }
104
105 $parameters[$name] = $node;
106 }
107
108 if (!$named) {
109 return $parameters;
110 }
111
112 if (!$callable) {
113 throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
114 }
115
116 // manage named arguments
117 if (is_array($callable)) {
118 $r = new ReflectionMethod($callable[0], $callable[1]);
119 } elseif (is_object($callable) && !$callable instanceof Closure) {
120 $r = new ReflectionObject($callable);
121 $r = $r->getMethod('__invoke');
122 } else {
123 $r = new ReflectionFunction($callable);
124 }
125
126 $definition = $r->getParameters();
127 if ($this->hasNode('node')) {
128 array_shift($definition);
129 }
130 if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
131 array_shift($definition);
132 }
133 if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
134 array_shift($definition);
135 }
136 if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
137 foreach ($this->getAttribute('arguments') as $argument) {
138 array_shift($definition);
139 }
140 }
141
142 $arguments = array();
143 $pos = 0;
144 foreach ($definition as $param) {
145 $name = $this->normalizeName($param->name);
146
147 if (array_key_exists($name, $parameters)) {
148 if (array_key_exists($pos, $parameters)) {
149 throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
150 }
151
152 $arguments[] = $parameters[$name];
153 unset($parameters[$name]);
154 } elseif (array_key_exists($pos, $parameters)) {
155 $arguments[] = $parameters[$pos];
156 unset($parameters[$pos]);
157 ++$pos;
158 } elseif ($param->isDefaultValueAvailable()) {
159 $arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
160 } elseif ($param->isOptional()) {
161 break;
162 } else {
163 throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
164 }
165 }
166
167 if (!empty($parameters)) {
168 throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '' , implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name')));
169 }
170
171 return $arguments;
172 }
173
174 protected function normalizeName($name)
175 {
176 return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
177 }
178}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php b/vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php
new file mode 100644
index 00000000..edcb1e2d
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php
@@ -0,0 +1,31 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Conditional extends Twig_Node_Expression
13{
14 public function __construct(Twig_Node_Expression $expr1, Twig_Node_Expression $expr2, Twig_Node_Expression $expr3, $lineno)
15 {
16 parent::__construct(array('expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno);
17 }
18
19 public function compile(Twig_Compiler $compiler)
20 {
21 $compiler
22 ->raw('((')
23 ->subcompile($this->getNode('expr1'))
24 ->raw(') ? (')
25 ->subcompile($this->getNode('expr2'))
26 ->raw(') : (')
27 ->subcompile($this->getNode('expr3'))
28 ->raw('))')
29 ;
30 }
31}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Constant.php b/vendor/twig/twig/lib/Twig/Node/Expression/Constant.php
new file mode 100644
index 00000000..a91dc698
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Constant.php
@@ -0,0 +1,23 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Constant extends Twig_Node_Expression
13{
14 public function __construct($value, $lineno)
15 {
16 parent::__construct(array(), array('value' => $value), $lineno);
17 }
18
19 public function compile(Twig_Compiler $compiler)
20 {
21 $compiler->repr($this->getAttribute('value'));
22 }
23}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php b/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php
new file mode 100644
index 00000000..00ac6701
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Represents an extension call node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
18{
19 public function __construct($name, $lineno, $tag = null)
20 {
21 parent::__construct(array(), array('name' => $name), $lineno, $tag);
22 }
23
24 /**
25 * Compiles the node to PHP.
26 *
27 * @param Twig_Compiler A Twig_Compiler instance
28 */
29 public function compile(Twig_Compiler $compiler)
30 {
31 $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name')));
32 }
33}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Filter.php b/vendor/twig/twig/lib/Twig/Node/Expression/Filter.php
new file mode 100644
index 00000000..207b062a
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Filter.php
@@ -0,0 +1,36 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
13{
14 public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
15 {
16 parent::__construct(array('node' => $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag);
17 }
18
19 public function compile(Twig_Compiler $compiler)
20 {
21 $name = $this->getNode('filter')->getAttribute('value');
22 $filter = $compiler->getEnvironment()->getFilter($name);
23
24 $this->setAttribute('name', $name);
25 $this->setAttribute('type', 'filter');
26 $this->setAttribute('thing', $filter);
27 $this->setAttribute('needs_environment', $filter->needsEnvironment());
28 $this->setAttribute('needs_context', $filter->needsContext());
29 $this->setAttribute('arguments', $filter->getArguments());
30 if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
31 $this->setAttribute('callable', $filter->getCallable());
32 }
33
34 $this->compileCallable($compiler);
35 }
36}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.php b/vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.php
new file mode 100644
index 00000000..1827c888
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.php
@@ -0,0 +1,43 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Returns the value or the default value when it is undefined or empty.
14 *
15 * <pre>
16 * {{ var.foo|default('foo item on var is not defined') }}
17 * </pre>
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
22{
23 public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
24 {
25 $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine());
26
27 if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
28 $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine());
29 $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
30
31 $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine());
32 } else {
33 $node = $default;
34 }
35
36 parent::__construct($node, $filterName, $arguments, $lineno, $tag);
37 }
38
39 public function compile(Twig_Compiler $compiler)
40 {
41 $compiler->subcompile($this->getNode('node'));
42 }
43}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Function.php b/vendor/twig/twig/lib/Twig/Node/Expression/Function.php
new file mode 100644
index 00000000..3e1f6b55
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Function.php
@@ -0,0 +1,35 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
12{
13 public function __construct($name, Twig_NodeInterface $arguments, $lineno)
14 {
15 parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno);
16 }
17
18 public function compile(Twig_Compiler $compiler)
19 {
20 $name = $this->getAttribute('name');
21 $function = $compiler->getEnvironment()->getFunction($name);
22
23 $this->setAttribute('name', $name);
24 $this->setAttribute('type', 'function');
25 $this->setAttribute('thing', $function);
26 $this->setAttribute('needs_environment', $function->needsEnvironment());
27 $this->setAttribute('needs_context', $function->needsContext());
28 $this->setAttribute('arguments', $function->getArguments());
29 if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
30 $this->setAttribute('callable', $function->getCallable());
31 }
32
33 $this->compileCallable($compiler);
34 }
35}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php b/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php
new file mode 100644
index 00000000..81a9b137
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php
@@ -0,0 +1,53 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
13{
14 public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno)
15 {
16 parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
17 }
18
19 public function compile(Twig_Compiler $compiler)
20 {
21 if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
22 $compiler->raw('twig_template_get_attributes($this, ');
23 } else {
24 $compiler->raw('$this->getAttribute(');
25 }
26
27 if ($this->getAttribute('ignore_strict_check')) {
28 $this->getNode('node')->setAttribute('ignore_strict_check', true);
29 }
30
31 $compiler->subcompile($this->getNode('node'));
32
33 $compiler->raw(', ')->subcompile($this->getNode('attribute'));
34
35 if (count($this->getNode('arguments')) || Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
36 $compiler->raw(', ')->subcompile($this->getNode('arguments'));
37
38 if (Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
39 $compiler->raw(', ')->repr($this->getAttribute('type'));
40 }
41
42 if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
43 $compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false'));
44 }
45
46 if ($this->getAttribute('ignore_strict_check')) {
47 $compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
48 }
49 }
50
51 $compiler->raw(')');
52 }
53}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.php b/vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.php
new file mode 100644
index 00000000..620b02bf
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_MethodCall extends Twig_Node_Expression
12{
13 public function __construct(Twig_Node_Expression $node, $method, Twig_Node_Expression_Array $arguments, $lineno)
14 {
15 parent::__construct(array('node' => $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno);
16
17 if ($node instanceof Twig_Node_Expression_Name) {
18 $node->setAttribute('always_defined', true);
19 }
20 }
21
22 public function compile(Twig_Compiler $compiler)
23 {
24 $compiler
25 ->subcompile($this->getNode('node'))
26 ->raw('->')
27 ->raw($this->getAttribute('method'))
28 ->raw('(')
29 ;
30 $first = true;
31 foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) {
32 if (!$first) {
33 $compiler->raw(', ');
34 }
35 $first = false;
36
37 $compiler->subcompile($pair['value']);
38 }
39 $compiler->raw(')');
40 }
41}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Name.php b/vendor/twig/twig/lib/Twig/Node/Expression/Name.php
new file mode 100644
index 00000000..3b8fae01
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Name.php
@@ -0,0 +1,88 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Name extends Twig_Node_Expression
13{
14 protected $specialVars = array(
15 '_self' => '$this',
16 '_context' => '$context',
17 '_charset' => '$this->env->getCharset()',
18 );
19
20 public function __construct($name, $lineno)
21 {
22 parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno);
23 }
24
25 public function compile(Twig_Compiler $compiler)
26 {
27 $name = $this->getAttribute('name');
28
29 if ($this->getAttribute('is_defined_test')) {
30 if ($this->isSpecial()) {
31 $compiler->repr(true);
32 } else {
33 $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)');
34 }
35 } elseif ($this->isSpecial()) {
36 $compiler->raw($this->specialVars[$name]);
37 } elseif ($this->getAttribute('always_defined')) {
38 $compiler
39 ->raw('$context[')
40 ->string($name)
41 ->raw(']')
42 ;
43 } else {
44 // remove the non-PHP 5.4 version when PHP 5.3 support is dropped
45 // as the non-optimized version is just a workaround for slow ternary operator
46 // when the context has a lot of variables
47 if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
48 // PHP 5.4 ternary operator performance was optimized
49 $compiler
50 ->raw('(isset($context[')
51 ->string($name)
52 ->raw(']) ? $context[')
53 ->string($name)
54 ->raw('] : ')
55 ;
56
57 if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) {
58 $compiler->raw('null)');
59 } else {
60 $compiler->raw('$this->getContext($context, ')->string($name)->raw('))');
61 }
62 } else {
63 $compiler
64 ->raw('$this->getContext($context, ')
65 ->string($name)
66 ;
67
68 if ($this->getAttribute('ignore_strict_check')) {
69 $compiler->raw(', true');
70 }
71
72 $compiler
73 ->raw(')')
74 ;
75 }
76 }
77 }
78
79 public function isSpecial()
80 {
81 return isset($this->specialVars[$this->getAttribute('name')]);
82 }
83
84 public function isSimple()
85 {
86 return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
87 }
88}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Parent.php b/vendor/twig/twig/lib/Twig/Node/Expression/Parent.php
new file mode 100644
index 00000000..dcf618c0
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Parent.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a parent node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_Expression_Parent extends Twig_Node_Expression
19{
20 public function __construct($name, $lineno, $tag = null)
21 {
22 parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag);
23 }
24
25 /**
26 * Compiles the node to PHP.
27 *
28 * @param Twig_Compiler A Twig_Compiler instance
29 */
30 public function compile(Twig_Compiler $compiler)
31 {
32 if ($this->getAttribute('output')) {
33 $compiler
34 ->addDebugInfo($this)
35 ->write("\$this->displayParentBlock(")
36 ->string($this->getAttribute('name'))
37 ->raw(", \$context, \$blocks);\n")
38 ;
39 } else {
40 $compiler
41 ->raw("\$this->renderParentBlock(")
42 ->string($this->getAttribute('name'))
43 ->raw(", \$context, \$blocks)")
44 ;
45 }
46 }
47}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/TempName.php b/vendor/twig/twig/lib/Twig/Node/Expression/TempName.php
new file mode 100644
index 00000000..e6b058e8
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/TempName.php
@@ -0,0 +1,26 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_TempName extends Twig_Node_Expression
12{
13 public function __construct($name, $lineno)
14 {
15 parent::__construct(array(), array('name' => $name), $lineno);
16 }
17
18 public function compile(Twig_Compiler $compiler)
19 {
20 $compiler
21 ->raw('$_')
22 ->raw($this->getAttribute('name'))
23 ->raw('_')
24 ;
25 }
26}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test.php
new file mode 100644
index 00000000..639f501a
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Node_Expression_Test extends Twig_Node_Expression_Call
12{
13 public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
14 {
15 parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno);
16 }
17
18 public function compile(Twig_Compiler $compiler)
19 {
20 $name = $this->getAttribute('name');
21 $test = $compiler->getEnvironment()->getTest($name);
22
23 $this->setAttribute('name', $name);
24 $this->setAttribute('type', 'test');
25 $this->setAttribute('thing', $test);
26 if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) {
27 $this->setAttribute('callable', $test->getCallable());
28 }
29
30 $this->compileCallable($compiler);
31 }
32}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php
new file mode 100644
index 00000000..de55f5f5
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Checks if a variable is the exact same value as a constant.
14 *
15 * <pre>
16 * {% if post.status is constant('Post::PUBLISHED') %}
17 * the status attribute is exactly the same as Post::PUBLISHED
18 * {% endif %}
19 * </pre>
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 */
23class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test
24{
25 public function compile(Twig_Compiler $compiler)
26 {
27 $compiler
28 ->raw('(')
29 ->subcompile($this->getNode('node'))
30 ->raw(' === constant(')
31 ;
32
33 if ($this->getNode('arguments')->hasNode(1)) {
34 $compiler
35 ->raw('get_class(')
36 ->subcompile($this->getNode('arguments')->getNode(1))
37 ->raw(')."::".')
38 ;
39 }
40
41 $compiler
42 ->subcompile($this->getNode('arguments')->getNode(0))
43 ->raw('))')
44 ;
45 }
46}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php
new file mode 100644
index 00000000..247b2e23
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php
@@ -0,0 +1,54 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Checks if a variable is defined in the current context.
14 *
15 * <pre>
16 * {# defined works with variable names and variable attributes #}
17 * {% if foo is defined %}
18 * {# ... #}
19 * {% endif %}
20 * </pre>
21 *
22 * @author Fabien Potencier <fabien@symfony.com>
23 */
24class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test
25{
26 public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
27 {
28 parent::__construct($node, $name, $arguments, $lineno);
29
30 if ($node instanceof Twig_Node_Expression_Name) {
31 $node->setAttribute('is_defined_test', true);
32 } elseif ($node instanceof Twig_Node_Expression_GetAttr) {
33 $node->setAttribute('is_defined_test', true);
34
35 $this->changeIgnoreStrictCheck($node);
36 } else {
37 throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
38 }
39 }
40
41 protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node)
42 {
43 $node->setAttribute('ignore_strict_check', true);
44
45 if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) {
46 $this->changeIgnoreStrictCheck($node->getNode('node'));
47 }
48 }
49
50 public function compile(Twig_Compiler $compiler)
51 {
52 $compiler->subcompile($this->getNode('node'));
53 }
54}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php
new file mode 100644
index 00000000..0aceb530
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Checks if a variable is divisible by a number.
14 *
15 * <pre>
16 * {% if loop.index is divisibleby(3) %}
17 * </pre>
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test
22{
23 public function compile(Twig_Compiler $compiler)
24 {
25 $compiler
26 ->raw('(0 == ')
27 ->subcompile($this->getNode('node'))
28 ->raw(' % ')
29 ->subcompile($this->getNode('arguments')->getNode(0))
30 ->raw(')')
31 ;
32 }
33}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.php
new file mode 100644
index 00000000..d7853e89
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Checks if a number is even.
14 *
15 * <pre>
16 * {{ var is even }}
17 * </pre>
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test
22{
23 public function compile(Twig_Compiler $compiler)
24 {
25 $compiler
26 ->raw('(')
27 ->subcompile($this->getNode('node'))
28 ->raw(' % 2 == 0')
29 ->raw(')')
30 ;
31 }
32}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.php
new file mode 100644
index 00000000..1c83825a
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.php
@@ -0,0 +1,31 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Checks that a variable is null.
14 *
15 * <pre>
16 * {{ var is none }}
17 * </pre>
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test
22{
23 public function compile(Twig_Compiler $compiler)
24 {
25 $compiler
26 ->raw('(null === ')
27 ->subcompile($this->getNode('node'))
28 ->raw(')')
29 ;
30 }
31}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.php
new file mode 100644
index 00000000..421c19e8
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.php
@@ -0,0 +1,32 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Checks if a number is odd.
14 *
15 * <pre>
16 * {{ var is odd }}
17 * </pre>
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
22{
23 public function compile(Twig_Compiler $compiler)
24 {
25 $compiler
26 ->raw('(')
27 ->subcompile($this->getNode('node'))
28 ->raw(' % 2 == 1')
29 ->raw(')')
30 ;
31 }
32}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php
new file mode 100644
index 00000000..b48905ee
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php
@@ -0,0 +1,29 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Checks if a variable is the same as another one (=== in PHP).
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test
18{
19 public function compile(Twig_Compiler $compiler)
20 {
21 $compiler
22 ->raw('(')
23 ->subcompile($this->getNode('node'))
24 ->raw(' === ')
25 ->subcompile($this->getNode('arguments')->getNode(0))
26 ->raw(')')
27 ;
28 }
29}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Unary.php b/vendor/twig/twig/lib/Twig/Node/Expression/Unary.php
new file mode 100644
index 00000000..c514388e
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Unary.php
@@ -0,0 +1,30 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression
13{
14 public function __construct(Twig_NodeInterface $node, $lineno)
15 {
16 parent::__construct(array('node' => $node), array(), $lineno);
17 }
18
19 public function compile(Twig_Compiler $compiler)
20 {
21 $compiler->raw('(');
22 $this->operator($compiler);
23 $compiler
24 ->subcompile($this->getNode('node'))
25 ->raw(')')
26 ;
27 }
28
29 abstract public function operator(Twig_Compiler $compiler);
30}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php
new file mode 100644
index 00000000..2a3937ec
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Unary_Neg extends Twig_Node_Expression_Unary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 $compiler->raw('-');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.php b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.php
new file mode 100644
index 00000000..f94073cf
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Unary_Not extends Twig_Node_Expression_Unary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 $compiler->raw('!');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php
new file mode 100644
index 00000000..04edb52a
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php
@@ -0,0 +1,18 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12class Twig_Node_Expression_Unary_Pos extends Twig_Node_Expression_Unary
13{
14 public function operator(Twig_Compiler $compiler)
15 {
16 $compiler->raw('+');
17 }
18}
diff --git a/vendor/twig/twig/lib/Twig/Node/Flush.php b/vendor/twig/twig/lib/Twig/Node/Flush.php
new file mode 100644
index 00000000..0467ddce
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Flush.php
@@ -0,0 +1,36 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Represents a flush node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Flush extends Twig_Node
18{
19 public function __construct($lineno, $tag)
20 {
21 parent::__construct(array(), array(), $lineno, $tag);
22 }
23
24 /**
25 * Compiles the node to PHP.
26 *
27 * @param Twig_Compiler A Twig_Compiler instance
28 */
29 public function compile(Twig_Compiler $compiler)
30 {
31 $compiler
32 ->addDebugInfo($this)
33 ->write("flush();\n")
34 ;
35 }
36}
diff --git a/vendor/twig/twig/lib/Twig/Node/For.php b/vendor/twig/twig/lib/Twig/Node/For.php
new file mode 100644
index 00000000..d1ff371d
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/For.php
@@ -0,0 +1,112 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a for node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_For extends Twig_Node
19{
20 protected $loop;
21
22 public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null)
23 {
24 $body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag)));
25
26 if (null !== $ifexpr) {
27 $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag);
28 }
29
30 parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag);
31 }
32
33 /**
34 * Compiles the node to PHP.
35 *
36 * @param Twig_Compiler A Twig_Compiler instance
37 */
38 public function compile(Twig_Compiler $compiler)
39 {
40 $compiler
41 ->addDebugInfo($this)
42 // the (array) cast bypasses a PHP 5.2.6 bug
43 ->write("\$context['_parent'] = (array) \$context;\n")
44 ->write("\$context['_seq'] = twig_ensure_traversable(")
45 ->subcompile($this->getNode('seq'))
46 ->raw(");\n")
47 ;
48
49 if (null !== $this->getNode('else')) {
50 $compiler->write("\$context['_iterated'] = false;\n");
51 }
52
53 if ($this->getAttribute('with_loop')) {
54 $compiler
55 ->write("\$context['loop'] = array(\n")
56 ->write(" 'parent' => \$context['_parent'],\n")
57 ->write(" 'index0' => 0,\n")
58 ->write(" 'index' => 1,\n")
59 ->write(" 'first' => true,\n")
60 ->write(");\n")
61 ;
62
63 if (!$this->getAttribute('ifexpr')) {
64 $compiler
65 ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
66 ->indent()
67 ->write("\$length = count(\$context['_seq']);\n")
68 ->write("\$context['loop']['revindex0'] = \$length - 1;\n")
69 ->write("\$context['loop']['revindex'] = \$length;\n")
70 ->write("\$context['loop']['length'] = \$length;\n")
71 ->write("\$context['loop']['last'] = 1 === \$length;\n")
72 ->outdent()
73 ->write("}\n")
74 ;
75 }
76 }
77
78 $this->loop->setAttribute('else', null !== $this->getNode('else'));
79 $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop'));
80 $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr'));
81
82 $compiler
83 ->write("foreach (\$context['_seq'] as ")
84 ->subcompile($this->getNode('key_target'))
85 ->raw(" => ")
86 ->subcompile($this->getNode('value_target'))
87 ->raw(") {\n")
88 ->indent()
89 ->subcompile($this->getNode('body'))
90 ->outdent()
91 ->write("}\n")
92 ;
93
94 if (null !== $this->getNode('else')) {
95 $compiler
96 ->write("if (!\$context['_iterated']) {\n")
97 ->indent()
98 ->subcompile($this->getNode('else'))
99 ->outdent()
100 ->write("}\n")
101 ;
102 }
103
104 $compiler->write("\$_parent = \$context['_parent'];\n");
105
106 // remove some "private" loop variables (needed for nested loops)
107 $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
108
109 // keep the values set in the inner context for variables defined in the outer context
110 $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n");
111 }
112}
diff --git a/vendor/twig/twig/lib/Twig/Node/ForLoop.php b/vendor/twig/twig/lib/Twig/Node/ForLoop.php
new file mode 100644
index 00000000..b8841583
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/ForLoop.php
@@ -0,0 +1,55 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Internal node used by the for node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_ForLoop extends Twig_Node
18{
19 public function __construct($lineno, $tag = null)
20 {
21 parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag);
22 }
23
24 /**
25 * Compiles the node to PHP.
26 *
27 * @param Twig_Compiler A Twig_Compiler instance
28 */
29 public function compile(Twig_Compiler $compiler)
30 {
31 if ($this->getAttribute('else')) {
32 $compiler->write("\$context['_iterated'] = true;\n");
33 }
34
35 if ($this->getAttribute('with_loop')) {
36 $compiler
37 ->write("++\$context['loop']['index0'];\n")
38 ->write("++\$context['loop']['index'];\n")
39 ->write("\$context['loop']['first'] = false;\n")
40 ;
41
42 if (!$this->getAttribute('ifexpr')) {
43 $compiler
44 ->write("if (isset(\$context['loop']['length'])) {\n")
45 ->indent()
46 ->write("--\$context['loop']['revindex0'];\n")
47 ->write("--\$context['loop']['revindex'];\n")
48 ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
49 ->outdent()
50 ->write("}\n")
51 ;
52 }
53 }
54 }
55}
diff --git a/vendor/twig/twig/lib/Twig/Node/If.php b/vendor/twig/twig/lib/Twig/Node/If.php
new file mode 100644
index 00000000..4296a8d6
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/If.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents an if node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_If extends Twig_Node
19{
20 public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null)
21 {
22 parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag);
23 }
24
25 /**
26 * Compiles the node to PHP.
27 *
28 * @param Twig_Compiler A Twig_Compiler instance
29 */
30 public function compile(Twig_Compiler $compiler)
31 {
32 $compiler->addDebugInfo($this);
33 for ($i = 0; $i < count($this->getNode('tests')); $i += 2) {
34 if ($i > 0) {
35 $compiler
36 ->outdent()
37 ->write("} elseif (")
38 ;
39 } else {
40 $compiler
41 ->write('if (')
42 ;
43 }
44
45 $compiler
46 ->subcompile($this->getNode('tests')->getNode($i))
47 ->raw(") {\n")
48 ->indent()
49 ->subcompile($this->getNode('tests')->getNode($i + 1))
50 ;
51 }
52
53 if ($this->hasNode('else') && null !== $this->getNode('else')) {
54 $compiler
55 ->outdent()
56 ->write("} else {\n")
57 ->indent()
58 ->subcompile($this->getNode('else'))
59 ;
60 }
61
62 $compiler
63 ->outdent()
64 ->write("}\n");
65 }
66}
diff --git a/vendor/twig/twig/lib/Twig/Node/Import.php b/vendor/twig/twig/lib/Twig/Node/Import.php
new file mode 100644
index 00000000..99efc091
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Import.php
@@ -0,0 +1,50 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Represents an import node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Import extends Twig_Node
18{
19 public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null)
20 {
21 parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag);
22 }
23
24 /**
25 * Compiles the node to PHP.
26 *
27 * @param Twig_Compiler A Twig_Compiler instance
28 */
29 public function compile(Twig_Compiler $compiler)
30 {
31 $compiler
32 ->addDebugInfo($this)
33 ->write('')
34 ->subcompile($this->getNode('var'))
35 ->raw(' = ')
36 ;
37
38 if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) {
39 $compiler->raw("\$this");
40 } else {
41 $compiler
42 ->raw('$this->env->loadTemplate(')
43 ->subcompile($this->getNode('expr'))
44 ->raw(")")
45 ;
46 }
47
48 $compiler->raw(";\n");
49 }
50}
diff --git a/vendor/twig/twig/lib/Twig/Node/Include.php b/vendor/twig/twig/lib/Twig/Node/Include.php
new file mode 100644
index 00000000..ed4a3751
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Include.php
@@ -0,0 +1,99 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents an include node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
19{
20 public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
21 {
22 parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (Boolean) $only, 'ignore_missing' => (Boolean) $ignoreMissing), $lineno, $tag);
23 }
24
25 /**
26 * Compiles the node to PHP.
27 *
28 * @param Twig_Compiler A Twig_Compiler instance
29 */
30 public function compile(Twig_Compiler $compiler)
31 {
32 $compiler->addDebugInfo($this);
33
34 if ($this->getAttribute('ignore_missing')) {
35 $compiler
36 ->write("try {\n")
37 ->indent()
38 ;
39 }
40
41 $this->addGetTemplate($compiler);
42
43 $compiler->raw('->display(');
44
45 $this->addTemplateArguments($compiler);
46
47 $compiler->raw(");\n");
48
49 if ($this->getAttribute('ignore_missing')) {
50 $compiler
51 ->outdent()
52 ->write("} catch (Twig_Error_Loader \$e) {\n")
53 ->indent()
54 ->write("// ignore missing template\n")
55 ->outdent()
56 ->write("}\n\n")
57 ;
58 }
59 }
60
61 protected function addGetTemplate(Twig_Compiler $compiler)
62 {
63 if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
64 $compiler
65 ->write("\$this->env->loadTemplate(")
66 ->subcompile($this->getNode('expr'))
67 ->raw(")")
68 ;
69 } else {
70 $compiler
71 ->write("\$template = \$this->env->resolveTemplate(")
72 ->subcompile($this->getNode('expr'))
73 ->raw(");\n")
74 ->write('$template')
75 ;
76 }
77 }
78
79 protected function addTemplateArguments(Twig_Compiler $compiler)
80 {
81 if (false === $this->getAttribute('only')) {
82 if (null === $this->getNode('variables')) {
83 $compiler->raw('$context');
84 } else {
85 $compiler
86 ->raw('array_merge($context, ')
87 ->subcompile($this->getNode('variables'))
88 ->raw(')')
89 ;
90 }
91 } else {
92 if (null === $this->getNode('variables')) {
93 $compiler->raw('array()');
94 } else {
95 $compiler->subcompile($this->getNode('variables'));
96 }
97 }
98 }
99}
diff --git a/vendor/twig/twig/lib/Twig/Node/Macro.php b/vendor/twig/twig/lib/Twig/Node/Macro.php
new file mode 100644
index 00000000..89910618
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Macro.php
@@ -0,0 +1,96 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Represents a macro node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Macro extends Twig_Node
18{
19 public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
20 {
21 parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
22 }
23
24 /**
25 * Compiles the node to PHP.
26 *
27 * @param Twig_Compiler A Twig_Compiler instance
28 */
29 public function compile(Twig_Compiler $compiler)
30 {
31 $compiler
32 ->addDebugInfo($this)
33 ->write(sprintf("public function get%s(", $this->getAttribute('name')))
34 ;
35
36 $count = count($this->getNode('arguments'));
37 $pos = 0;
38 foreach ($this->getNode('arguments') as $name => $default) {
39 $compiler
40 ->raw('$_'.$name.' = ')
41 ->subcompile($default)
42 ;
43
44 if (++$pos < $count) {
45 $compiler->raw(', ');
46 }
47 }
48
49 $compiler
50 ->raw(")\n")
51 ->write("{\n")
52 ->indent()
53 ;
54
55 if (!count($this->getNode('arguments'))) {
56 $compiler->write("\$context = \$this->env->getGlobals();\n\n");
57 } else {
58 $compiler
59 ->write("\$context = \$this->env->mergeGlobals(array(\n")
60 ->indent()
61 ;
62
63 foreach ($this->getNode('arguments') as $name => $default) {
64 $compiler
65 ->write('')
66 ->string($name)
67 ->raw(' => $_'.$name)
68 ->raw(",\n")
69 ;
70 }
71
72 $compiler
73 ->outdent()
74 ->write("));\n\n")
75 ;
76 }
77
78 $compiler
79 ->write("\$blocks = array();\n\n")
80 ->write("ob_start();\n")
81 ->write("try {\n")
82 ->indent()
83 ->subcompile($this->getNode('body'))
84 ->outdent()
85 ->write("} catch (Exception \$e) {\n")
86 ->indent()
87 ->write("ob_end_clean();\n\n")
88 ->write("throw \$e;\n")
89 ->outdent()
90 ->write("}\n\n")
91 ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n")
92 ->outdent()
93 ->write("}\n\n")
94 ;
95 }
96}
diff --git a/vendor/twig/twig/lib/Twig/Node/Module.php b/vendor/twig/twig/lib/Twig/Node/Module.php
new file mode 100644
index 00000000..585048b8
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Module.php
@@ -0,0 +1,371 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a module node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_Module extends Twig_Node
19{
20 public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename)
21 {
22 // embedded templates are set as attributes so that they are only visited once by the visitors
23 parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates), 1);
24 }
25
26 public function setIndex($index)
27 {
28 $this->setAttribute('index', $index);
29 }
30
31 /**
32 * Compiles the node to PHP.
33 *
34 * @param Twig_Compiler A Twig_Compiler instance
35 */
36 public function compile(Twig_Compiler $compiler)
37 {
38 $this->compileTemplate($compiler);
39
40 foreach ($this->getAttribute('embedded_templates') as $template) {
41 $compiler->subcompile($template);
42 }
43 }
44
45 protected function compileTemplate(Twig_Compiler $compiler)
46 {
47 if (!$this->getAttribute('index')) {
48 $compiler->write('<?php');
49 }
50
51 $this->compileClassHeader($compiler);
52
53 if (count($this->getNode('blocks')) || count($this->getNode('traits')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
54 $this->compileConstructor($compiler);
55 }
56
57 $this->compileGetParent($compiler);
58
59 $this->compileDisplayHeader($compiler);
60
61 $this->compileDisplayBody($compiler);
62
63 $this->compileDisplayFooter($compiler);
64
65 $compiler->subcompile($this->getNode('blocks'));
66
67 $this->compileMacros($compiler);
68
69 $this->compileGetTemplateName($compiler);
70
71 $this->compileIsTraitable($compiler);
72
73 $this->compileDebugInfo($compiler);
74
75 $this->compileClassFooter($compiler);
76 }
77
78 protected function compileGetParent(Twig_Compiler $compiler)
79 {
80 if (null === $this->getNode('parent')) {
81 return;
82 }
83
84 $compiler
85 ->write("protected function doGetParent(array \$context)\n", "{\n")
86 ->indent()
87 ->write("return ")
88 ;
89
90 if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
91 $compiler->subcompile($this->getNode('parent'));
92 } else {
93 $compiler
94 ->raw("\$this->env->resolveTemplate(")
95 ->subcompile($this->getNode('parent'))
96 ->raw(")")
97 ;
98 }
99
100 $compiler
101 ->raw(";\n")
102 ->outdent()
103 ->write("}\n\n")
104 ;
105 }
106
107 protected function compileDisplayBody(Twig_Compiler $compiler)
108 {
109 $compiler->subcompile($this->getNode('body'));
110
111 if (null !== $this->getNode('parent')) {
112 if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
113 $compiler->write("\$this->parent");
114 } else {
115 $compiler->write("\$this->getParent(\$context)");
116 }
117 $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
118 }
119 }
120
121 protected function compileClassHeader(Twig_Compiler $compiler)
122 {
123 $compiler
124 ->write("\n\n")
125 // if the filename contains */, add a blank to avoid a PHP parse error
126 ->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
127 ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index')))
128 ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
129 ->write("{\n")
130 ->indent()
131 ;
132 }
133
134 protected function compileConstructor(Twig_Compiler $compiler)
135 {
136 $compiler
137 ->write("public function __construct(Twig_Environment \$env)\n", "{\n")
138 ->indent()
139 ->write("parent::__construct(\$env);\n\n")
140 ;
141
142 // parent
143 if (null === $this->getNode('parent')) {
144 $compiler->write("\$this->parent = false;\n\n");
145 } elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
146 $compiler
147 ->write("\$this->parent = \$this->env->loadTemplate(")
148 ->subcompile($this->getNode('parent'))
149 ->raw(");\n\n")
150 ;
151 }
152
153 $countTraits = count($this->getNode('traits'));
154 if ($countTraits) {
155 // traits
156 foreach ($this->getNode('traits') as $i => $trait) {
157 $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
158
159 $compiler
160 ->addDebugInfo($trait->getNode('template'))
161 ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
162 ->indent()
163 ->write("throw new Twig_Error_Runtime('Template \"'.")
164 ->subcompile($trait->getNode('template'))
165 ->raw(".'\" cannot be used as a trait.');\n")
166 ->outdent()
167 ->write("}\n")
168 ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
169 ;
170
171 foreach ($trait->getNode('targets') as $key => $value) {
172 $compiler
173 ->write(sprintf("\$_trait_%s_blocks[", $i))
174 ->subcompile($value)
175 ->raw(sprintf("] = \$_trait_%s_blocks[", $i))
176 ->string($key)
177 ->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i))
178 ->string($key)
179 ->raw("]);\n\n")
180 ;
181 }
182 }
183
184 if ($countTraits > 1) {
185 $compiler
186 ->write("\$this->traits = array_merge(\n")
187 ->indent()
188 ;
189
190 for ($i = 0; $i < $countTraits; $i++) {
191 $compiler
192 ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
193 ;
194 }
195
196 $compiler
197 ->outdent()
198 ->write(");\n\n")
199 ;
200 } else {
201 $compiler
202 ->write("\$this->traits = \$_trait_0_blocks;\n\n")
203 ;
204 }
205
206 $compiler
207 ->write("\$this->blocks = array_merge(\n")
208 ->indent()
209 ->write("\$this->traits,\n")
210 ->write("array(\n")
211 ;
212 } else {
213 $compiler
214 ->write("\$this->blocks = array(\n")
215 ;
216 }
217
218 // blocks
219 $compiler
220 ->indent()
221 ;
222
223 foreach ($this->getNode('blocks') as $name => $node) {
224 $compiler
225 ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
226 ;
227 }
228
229 if ($countTraits) {
230 $compiler
231 ->outdent()
232 ->write(")\n")
233 ;
234 }
235
236 $compiler
237 ->outdent()
238 ->write(");\n")
239 ->outdent()
240 ->write("}\n\n");
241 ;
242 }
243
244 protected function compileDisplayHeader(Twig_Compiler $compiler)
245 {
246 $compiler
247 ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
248 ->indent()
249 ;
250 }
251
252 protected function compileDisplayFooter(Twig_Compiler $compiler)
253 {
254 $compiler
255 ->outdent()
256 ->write("}\n\n")
257 ;
258 }
259
260 protected function compileClassFooter(Twig_Compiler $compiler)
261 {
262 $compiler
263 ->outdent()
264 ->write("}\n")
265 ;
266 }
267
268 protected function compileMacros(Twig_Compiler $compiler)
269 {
270 $compiler->subcompile($this->getNode('macros'));
271 }
272
273 protected function compileGetTemplateName(Twig_Compiler $compiler)
274 {
275 $compiler
276 ->write("public function getTemplateName()\n", "{\n")
277 ->indent()
278 ->write('return ')
279 ->repr($this->getAttribute('filename'))
280 ->raw(";\n")
281 ->outdent()
282 ->write("}\n\n")
283 ;
284 }
285
286 protected function compileIsTraitable(Twig_Compiler $compiler)
287 {
288 // A template can be used as a trait if:
289 // * it has no parent
290 // * it has no macros
291 // * it has no body
292 //
293 // Put another way, a template can be used as a trait if it
294 // only contains blocks and use statements.
295 $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
296 if ($traitable) {
297 if ($this->getNode('body') instanceof Twig_Node_Body) {
298 $nodes = $this->getNode('body')->getNode(0);
299 } else {
300 $nodes = $this->getNode('body');
301 }
302
303 if (!count($nodes)) {
304 $nodes = new Twig_Node(array($nodes));
305 }
306
307 foreach ($nodes as $node) {
308 if (!count($node)) {
309 continue;
310 }
311
312 if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
313 continue;
314 }
315
316 if ($node instanceof Twig_Node_BlockReference) {
317 continue;
318 }
319
320 $traitable = false;
321 break;
322 }
323 }
324
325 if ($traitable) {
326 return;
327 }
328
329 $compiler
330 ->write("public function isTraitable()\n", "{\n")
331 ->indent()
332 ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
333 ->outdent()
334 ->write("}\n\n")
335 ;
336 }
337
338 protected function compileDebugInfo(Twig_Compiler $compiler)
339 {
340 $compiler
341 ->write("public function getDebugInfo()\n", "{\n")
342 ->indent()
343 ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
344 ->outdent()
345 ->write("}\n")
346 ;
347 }
348
349 protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
350 {
351 if ($node instanceof Twig_Node_Expression_Constant) {
352 $compiler
353 ->write(sprintf("%s = \$this->env->loadTemplate(", $var))
354 ->subcompile($node)
355 ->raw(");\n")
356 ;
357 } else {
358 $compiler
359 ->write(sprintf("%s = ", $var))
360 ->subcompile($node)
361 ->raw(";\n")
362 ->write(sprintf("if (!%s", $var))
363 ->raw(" instanceof Twig_Template) {\n")
364 ->indent()
365 ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
366 ->outdent()
367 ->write("}\n")
368 ;
369 }
370 }
371}
diff --git a/vendor/twig/twig/lib/Twig/Node/Print.php b/vendor/twig/twig/lib/Twig/Node/Print.php
new file mode 100644
index 00000000..b0c41d1d
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Print.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a node that outputs an expression.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface
19{
20 public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
21 {
22 parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
23 }
24
25 /**
26 * Compiles the node to PHP.
27 *
28 * @param Twig_Compiler A Twig_Compiler instance
29 */
30 public function compile(Twig_Compiler $compiler)
31 {
32 $compiler
33 ->addDebugInfo($this)
34 ->write('echo ')
35 ->subcompile($this->getNode('expr'))
36 ->raw(";\n")
37 ;
38 }
39}
diff --git a/vendor/twig/twig/lib/Twig/Node/Sandbox.php b/vendor/twig/twig/lib/Twig/Node/Sandbox.php
new file mode 100644
index 00000000..8cf3ed44
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Sandbox.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a sandbox node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Sandbox extends Twig_Node
18{
19 public function __construct(Twig_NodeInterface $body, $lineno, $tag = null)
20 {
21 parent::__construct(array('body' => $body), array(), $lineno, $tag);
22 }
23
24 /**
25 * Compiles the node to PHP.
26 *
27 * @param Twig_Compiler A Twig_Compiler instance
28 */
29 public function compile(Twig_Compiler $compiler)
30 {
31 $compiler
32 ->addDebugInfo($this)
33 ->write("\$sandbox = \$this->env->getExtension('sandbox');\n")
34 ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n")
35 ->indent()
36 ->write("\$sandbox->enableSandbox();\n")
37 ->outdent()
38 ->write("}\n")
39 ->subcompile($this->getNode('body'))
40 ->write("if (!\$alreadySandboxed) {\n")
41 ->indent()
42 ->write("\$sandbox->disableSandbox();\n")
43 ->outdent()
44 ->write("}\n")
45 ;
46 }
47}
diff --git a/vendor/twig/twig/lib/Twig/Node/SandboxedModule.php b/vendor/twig/twig/lib/Twig/Node/SandboxedModule.php
new file mode 100644
index 00000000..be1f5daa
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/SandboxedModule.php
@@ -0,0 +1,60 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a module node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_SandboxedModule extends Twig_Node_Module
19{
20 protected $usedFilters;
21 protected $usedTags;
22 protected $usedFunctions;
23
24 public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
25 {
26 parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'), $node->getLine(), $node->getNodeTag());
27
28 $this->setAttribute('index', $node->getAttribute('index'));
29
30 $this->usedFilters = $usedFilters;
31 $this->usedTags = $usedTags;
32 $this->usedFunctions = $usedFunctions;
33 }
34
35 protected function compileDisplayBody(Twig_Compiler $compiler)
36 {
37 $compiler->write("\$this->checkSecurity();\n");
38
39 parent::compileDisplayBody($compiler);
40 }
41
42 protected function compileDisplayFooter(Twig_Compiler $compiler)
43 {
44 parent::compileDisplayFooter($compiler);
45
46 $compiler
47 ->write("protected function checkSecurity()\n", "{\n")
48 ->indent()
49 ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
50 ->indent()
51 ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
52 ->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n")
53 ->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
54 ->outdent()
55 ->write(");\n")
56 ->outdent()
57 ->write("}\n\n")
58 ;
59 }
60}
diff --git a/vendor/twig/twig/lib/Twig/Node/SandboxedPrint.php b/vendor/twig/twig/lib/Twig/Node/SandboxedPrint.php
new file mode 100644
index 00000000..73dfaa96
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/SandboxedPrint.php
@@ -0,0 +1,59 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Twig_Node_SandboxedPrint adds a check for the __toString() method
14 * when the variable is an object and the sandbox is activated.
15 *
16 * When there is a simple Print statement, like {{ article }},
17 * and if the sandbox is enabled, we need to check that the __toString()
18 * method is allowed if 'article' is an object.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 */
22class Twig_Node_SandboxedPrint extends Twig_Node_Print
23{
24 public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
25 {
26 parent::__construct($expr, $lineno, $tag);
27 }
28
29 /**
30 * Compiles the node to PHP.
31 *
32 * @param Twig_Compiler A Twig_Compiler instance
33 */
34 public function compile(Twig_Compiler $compiler)
35 {
36 $compiler
37 ->addDebugInfo($this)
38 ->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(')
39 ->subcompile($this->getNode('expr'))
40 ->raw(");\n")
41 ;
42 }
43
44 /**
45 * Removes node filters.
46 *
47 * This is mostly needed when another visitor adds filters (like the escaper one).
48 *
49 * @param Twig_Node $node A Node
50 */
51 protected function removeNodeFilter($node)
52 {
53 if ($node instanceof Twig_Node_Expression_Filter) {
54 return $this->removeNodeFilter($node->getNode('node'));
55 }
56
57 return $node;
58 }
59}
diff --git a/vendor/twig/twig/lib/Twig/Node/Set.php b/vendor/twig/twig/lib/Twig/Node/Set.php
new file mode 100644
index 00000000..4c9c16ce
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Set.php
@@ -0,0 +1,101 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a set node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Node_Set extends Twig_Node
18{
19 public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null)
20 {
21 parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag);
22
23 /*
24 * Optimizes the node when capture is used for a large block of text.
25 *
26 * {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo");
27 */
28 if ($this->getAttribute('capture')) {
29 $this->setAttribute('safe', true);
30
31 $values = $this->getNode('values');
32 if ($values instanceof Twig_Node_Text) {
33 $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine()));
34 $this->setAttribute('capture', false);
35 }
36 }
37 }
38
39 /**
40 * Compiles the node to PHP.
41 *
42 * @param Twig_Compiler A Twig_Compiler instance
43 */
44 public function compile(Twig_Compiler $compiler)
45 {
46 $compiler->addDebugInfo($this);
47
48 if (count($this->getNode('names')) > 1) {
49 $compiler->write('list(');
50 foreach ($this->getNode('names') as $idx => $node) {
51 if ($idx) {
52 $compiler->raw(', ');
53 }
54
55 $compiler->subcompile($node);
56 }
57 $compiler->raw(')');
58 } else {
59 if ($this->getAttribute('capture')) {
60 $compiler
61 ->write("ob_start();\n")
62 ->subcompile($this->getNode('values'))
63 ;
64 }
65
66 $compiler->subcompile($this->getNode('names'), false);
67
68 if ($this->getAttribute('capture')) {
69 $compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())");
70 }
71 }
72
73 if (!$this->getAttribute('capture')) {
74 $compiler->raw(' = ');
75
76 if (count($this->getNode('names')) > 1) {
77 $compiler->write('array(');
78 foreach ($this->getNode('values') as $idx => $value) {
79 if ($idx) {
80 $compiler->raw(', ');
81 }
82
83 $compiler->subcompile($value);
84 }
85 $compiler->raw(')');
86 } else {
87 if ($this->getAttribute('safe')) {
88 $compiler
89 ->raw("('' === \$tmp = ")
90 ->subcompile($this->getNode('values'))
91 ->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())")
92 ;
93 } else {
94 $compiler->subcompile($this->getNode('values'));
95 }
96 }
97 }
98
99 $compiler->raw(";\n");
100 }
101}
diff --git a/vendor/twig/twig/lib/Twig/Node/SetTemp.php b/vendor/twig/twig/lib/Twig/Node/SetTemp.php
new file mode 100644
index 00000000..3bdd1cb7
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/SetTemp.php
@@ -0,0 +1,35 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Node_SetTemp extends Twig_Node
13{
14 public function __construct($name, $lineno)
15 {
16 parent::__construct(array(), array('name' => $name), $lineno);
17 }
18
19 public function compile(Twig_Compiler $compiler)
20 {
21 $name = $this->getAttribute('name');
22 $compiler
23 ->addDebugInfo($this)
24 ->write('if (isset($context[')
25 ->string($name)
26 ->raw('])) { $_')
27 ->raw($name)
28 ->raw('_ = $context[')
29 ->repr($name)
30 ->raw(']; } else { $_')
31 ->raw($name)
32 ->raw("_ = null; }\n")
33 ;
34 }
35}
diff --git a/vendor/twig/twig/lib/Twig/Node/Spaceless.php b/vendor/twig/twig/lib/Twig/Node/Spaceless.php
new file mode 100644
index 00000000..7555fa0f
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Spaceless.php
@@ -0,0 +1,40 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a spaceless node.
14 *
15 * It removes spaces between HTML tags.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19class Twig_Node_Spaceless extends Twig_Node
20{
21 public function __construct(Twig_NodeInterface $body, $lineno, $tag = 'spaceless')
22 {
23 parent::__construct(array('body' => $body), array(), $lineno, $tag);
24 }
25
26 /**
27 * Compiles the node to PHP.
28 *
29 * @param Twig_Compiler A Twig_Compiler instance
30 */
31 public function compile(Twig_Compiler $compiler)
32 {
33 $compiler
34 ->addDebugInfo($this)
35 ->write("ob_start();\n")
36 ->subcompile($this->getNode('body'))
37 ->write("echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));\n")
38 ;
39 }
40}
diff --git a/vendor/twig/twig/lib/Twig/Node/Text.php b/vendor/twig/twig/lib/Twig/Node/Text.php
new file mode 100644
index 00000000..21bdcea1
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Node/Text.php
@@ -0,0 +1,39 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a text node.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface
19{
20 public function __construct($data, $lineno)
21 {
22 parent::__construct(array(), array('data' => $data), $lineno);
23 }
24
25 /**
26 * Compiles the node to PHP.
27 *
28 * @param Twig_Compiler A Twig_Compiler instance
29 */
30 public function compile(Twig_Compiler $compiler)
31 {
32 $compiler
33 ->addDebugInfo($this)
34 ->write('echo ')
35 ->string($this->getAttribute('data'))
36 ->raw(";\n")
37 ;
38 }
39}
diff --git a/vendor/twig/twig/lib/Twig/NodeInterface.php b/vendor/twig/twig/lib/Twig/NodeInterface.php
new file mode 100644
index 00000000..f0ef7258
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/NodeInterface.php
@@ -0,0 +1,30 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a node in the AST.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18interface Twig_NodeInterface extends Countable, IteratorAggregate
19{
20 /**
21 * Compiles the node to PHP.
22 *
23 * @param Twig_Compiler A Twig_Compiler instance
24 */
25 public function compile(Twig_Compiler $compiler);
26
27 public function getLine();
28
29 public function getNodeTag();
30}
diff --git a/vendor/twig/twig/lib/Twig/NodeOutputInterface.php b/vendor/twig/twig/lib/Twig/NodeOutputInterface.php
new file mode 100644
index 00000000..22172c09
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/NodeOutputInterface.php
@@ -0,0 +1,19 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a displayable node in the AST.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17interface Twig_NodeOutputInterface
18{
19}
diff --git a/vendor/twig/twig/lib/Twig/NodeTraverser.php b/vendor/twig/twig/lib/Twig/NodeTraverser.php
new file mode 100644
index 00000000..28cba1ad
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/NodeTraverser.php
@@ -0,0 +1,88 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Twig_NodeTraverser is a node traverser.
14 *
15 * It visits all nodes and their children and call the given visitor for each.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19class Twig_NodeTraverser
20{
21 protected $env;
22 protected $visitors;
23
24 /**
25 * Constructor.
26 *
27 * @param Twig_Environment $env A Twig_Environment instance
28 * @param array $visitors An array of Twig_NodeVisitorInterface instances
29 */
30 public function __construct(Twig_Environment $env, array $visitors = array())
31 {
32 $this->env = $env;
33 $this->visitors = array();
34 foreach ($visitors as $visitor) {
35 $this->addVisitor($visitor);
36 }
37 }
38
39 /**
40 * Adds a visitor.
41 *
42 * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
43 */
44 public function addVisitor(Twig_NodeVisitorInterface $visitor)
45 {
46 if (!isset($this->visitors[$visitor->getPriority()])) {
47 $this->visitors[$visitor->getPriority()] = array();
48 }
49
50 $this->visitors[$visitor->getPriority()][] = $visitor;
51 }
52
53 /**
54 * Traverses a node and calls the registered visitors.
55 *
56 * @param Twig_NodeInterface $node A Twig_NodeInterface instance
57 */
58 public function traverse(Twig_NodeInterface $node)
59 {
60 ksort($this->visitors);
61 foreach ($this->visitors as $visitors) {
62 foreach ($visitors as $visitor) {
63 $node = $this->traverseForVisitor($visitor, $node);
64 }
65 }
66
67 return $node;
68 }
69
70 protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null)
71 {
72 if (null === $node) {
73 return null;
74 }
75
76 $node = $visitor->enterNode($node, $this->env);
77
78 foreach ($node as $k => $n) {
79 if (false !== $n = $this->traverseForVisitor($visitor, $n)) {
80 $node->setNode($k, $n);
81 } else {
82 $node->removeNode($k);
83 }
84 }
85
86 return $visitor->leaveNode($node, $this->env);
87 }
88}
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.php b/vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.php
new file mode 100644
index 00000000..cc4b3d71
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.php
@@ -0,0 +1,167 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Twig_NodeVisitor_Escaper implements output escaping.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
18{
19 protected $statusStack = array();
20 protected $blocks = array();
21 protected $safeAnalysis;
22 protected $traverser;
23 protected $defaultStrategy = false;
24 protected $safeVars = array();
25
26 public function __construct()
27 {
28 $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
29 }
30
31 /**
32 * Called before child nodes are visited.
33 *
34 * @param Twig_NodeInterface $node The node to visit
35 * @param Twig_Environment $env The Twig environment instance
36 *
37 * @return Twig_NodeInterface The modified node
38 */
39 public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
40 {
41 if ($node instanceof Twig_Node_Module) {
42 if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) {
43 $this->defaultStrategy = $defaultStrategy;
44 }
45 $this->safeVars = array();
46 } elseif ($node instanceof Twig_Node_AutoEscape) {
47 $this->statusStack[] = $node->getAttribute('value');
48 } elseif ($node instanceof Twig_Node_Block) {
49 $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
50 } elseif ($node instanceof Twig_Node_Import) {
51 $this->safeVars[] = $node->getNode('var')->getAttribute('name');
52 }
53
54 return $node;
55 }
56
57 /**
58 * Called after child nodes are visited.
59 *
60 * @param Twig_NodeInterface $node The node to visit
61 * @param Twig_Environment $env The Twig environment instance
62 *
63 * @return Twig_NodeInterface The modified node
64 */
65 public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
66 {
67 if ($node instanceof Twig_Node_Module) {
68 $this->defaultStrategy = false;
69 $this->safeVars = array();
70 } elseif ($node instanceof Twig_Node_Expression_Filter) {
71 return $this->preEscapeFilterNode($node, $env);
72 } elseif ($node instanceof Twig_Node_Print) {
73 return $this->escapePrintNode($node, $env, $this->needEscaping($env));
74 }
75
76 if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) {
77 array_pop($this->statusStack);
78 } elseif ($node instanceof Twig_Node_BlockReference) {
79 $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
80 }
81
82 return $node;
83 }
84
85 protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type)
86 {
87 if (false === $type) {
88 return $node;
89 }
90
91 $expression = $node->getNode('expr');
92
93 if ($this->isSafeFor($type, $expression, $env)) {
94 return $node;
95 }
96
97 $class = get_class($node);
98
99 return new $class(
100 $this->getEscaperFilter($type, $expression),
101 $node->getLine()
102 );
103 }
104
105 protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env)
106 {
107 $name = $filter->getNode('filter')->getAttribute('value');
108
109 $type = $env->getFilter($name)->getPreEscape();
110 if (null === $type) {
111 return $filter;
112 }
113
114 $node = $filter->getNode('node');
115 if ($this->isSafeFor($type, $node, $env)) {
116 return $filter;
117 }
118
119 $filter->setNode('node', $this->getEscaperFilter($type, $node));
120
121 return $filter;
122 }
123
124 protected function isSafeFor($type, Twig_NodeInterface $expression, $env)
125 {
126 $safe = $this->safeAnalysis->getSafe($expression);
127
128 if (null === $safe) {
129 if (null === $this->traverser) {
130 $this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis));
131 }
132
133 $this->safeAnalysis->setSafeVars($this->safeVars);
134
135 $this->traverser->traverse($expression);
136 $safe = $this->safeAnalysis->getSafe($expression);
137 }
138
139 return in_array($type, $safe) || in_array('all', $safe);
140 }
141
142 protected function needEscaping(Twig_Environment $env)
143 {
144 if (count($this->statusStack)) {
145 return $this->statusStack[count($this->statusStack) - 1];
146 }
147
148 return $this->defaultStrategy ? $this->defaultStrategy : false;
149 }
150
151 protected function getEscaperFilter($type, Twig_NodeInterface $node)
152 {
153 $line = $node->getLine();
154 $name = new Twig_Node_Expression_Constant('escape', $line);
155 $args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line)));
156
157 return new Twig_Node_Expression_Filter($node, $name, $args, $line);
158 }
159
160 /**
161 * {@inheritdoc}
162 */
163 public function getPriority()
164 {
165 return 0;
166 }
167}
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php b/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php
new file mode 100644
index 00000000..a254def7
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php
@@ -0,0 +1,246 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Twig_NodeVisitor_Optimizer tries to optimizes the AST.
14 *
15 * This visitor is always the last registered one.
16 *
17 * You can configure which optimizations you want to activate via the
18 * optimizer mode.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 */
22class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
23{
24 const OPTIMIZE_ALL = -1;
25 const OPTIMIZE_NONE = 0;
26 const OPTIMIZE_FOR = 2;
27 const OPTIMIZE_RAW_FILTER = 4;
28 const OPTIMIZE_VAR_ACCESS = 8;
29
30 protected $loops = array();
31 protected $optimizers;
32 protected $prependedNodes = array();
33 protected $inABody = false;
34
35 /**
36 * Constructor.
37 *
38 * @param integer $optimizers The optimizer mode
39 */
40 public function __construct($optimizers = -1)
41 {
42 if (!is_int($optimizers) || $optimizers > 2) {
43 throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
44 }
45
46 $this->optimizers = $optimizers;
47 }
48
49 /**
50 * {@inheritdoc}
51 */
52 public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
53 {
54 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
55 $this->enterOptimizeFor($node, $env);
56 }
57
58 if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
59 if ($this->inABody) {
60 if (!$node instanceof Twig_Node_Expression) {
61 if (get_class($node) !== 'Twig_Node') {
62 array_unshift($this->prependedNodes, array());
63 }
64 } else {
65 $node = $this->optimizeVariables($node, $env);
66 }
67 } elseif ($node instanceof Twig_Node_Body) {
68 $this->inABody = true;
69 }
70 }
71
72 return $node;
73 }
74
75 /**
76 * {@inheritdoc}
77 */
78 public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
79 {
80 $expression = $node instanceof Twig_Node_Expression;
81
82 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
83 $this->leaveOptimizeFor($node, $env);
84 }
85
86 if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
87 $node = $this->optimizeRawFilter($node, $env);
88 }
89
90 $node = $this->optimizePrintNode($node, $env);
91
92 if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
93 if ($node instanceof Twig_Node_Body) {
94 $this->inABody = false;
95 } elseif ($this->inABody) {
96 if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) {
97 $nodes = array();
98 foreach (array_unique($prependedNodes) as $name) {
99 $nodes[] = new Twig_Node_SetTemp($name, $node->getLine());
100 }
101
102 $nodes[] = $node;
103 $node = new Twig_Node($nodes);
104 }
105 }
106 }
107
108 return $node;
109 }
110
111 protected function optimizeVariables($node, $env)
112 {
113 if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) {
114 $this->prependedNodes[0][] = $node->getAttribute('name');
115
116 return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine());
117 }
118
119 return $node;
120 }
121
122 /**
123 * Optimizes print nodes.
124 *
125 * It replaces:
126 *
127 * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
128 *
129 * @param Twig_NodeInterface $node A Node
130 * @param Twig_Environment $env The current Twig environment
131 */
132 protected function optimizePrintNode($node, $env)
133 {
134 if (!$node instanceof Twig_Node_Print) {
135 return $node;
136 }
137
138 if (
139 $node->getNode('expr') instanceof Twig_Node_Expression_BlockReference ||
140 $node->getNode('expr') instanceof Twig_Node_Expression_Parent
141 ) {
142 $node->getNode('expr')->setAttribute('output', true);
143
144 return $node->getNode('expr');
145 }
146
147 return $node;
148 }
149
150 /**
151 * Removes "raw" filters.
152 *
153 * @param Twig_NodeInterface $node A Node
154 * @param Twig_Environment $env The current Twig environment
155 */
156 protected function optimizeRawFilter($node, $env)
157 {
158 if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
159 return $node->getNode('node');
160 }
161
162 return $node;
163 }
164
165 /**
166 * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
167 *
168 * @param Twig_NodeInterface $node A Node
169 * @param Twig_Environment $env The current Twig environment
170 */
171 protected function enterOptimizeFor($node, $env)
172 {
173 if ($node instanceof Twig_Node_For) {
174 // disable the loop variable by default
175 $node->setAttribute('with_loop', false);
176 array_unshift($this->loops, $node);
177 } elseif (!$this->loops) {
178 // we are outside a loop
179 return;
180 }
181
182 // when do we need to add the loop variable back?
183
184 // the loop variable is referenced for the current loop
185 elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
186 $this->addLoopToCurrent();
187 }
188
189 // block reference
190 elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
191 $this->addLoopToCurrent();
192 }
193
194 // include without the only attribute
195 elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
196 $this->addLoopToAll();
197 }
198
199 // the loop variable is referenced via an attribute
200 elseif ($node instanceof Twig_Node_Expression_GetAttr
201 && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
202 || 'parent' === $node->getNode('attribute')->getAttribute('value')
203 )
204 && (true === $this->loops[0]->getAttribute('with_loop')
205 || ($node->getNode('node') instanceof Twig_Node_Expression_Name
206 && 'loop' === $node->getNode('node')->getAttribute('name')
207 )
208 )
209 ) {
210 $this->addLoopToAll();
211 }
212 }
213
214 /**
215 * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
216 *
217 * @param Twig_NodeInterface $node A Node
218 * @param Twig_Environment $env The current Twig environment
219 */
220 protected function leaveOptimizeFor($node, $env)
221 {
222 if ($node instanceof Twig_Node_For) {
223 array_shift($this->loops);
224 }
225 }
226
227 protected function addLoopToCurrent()
228 {
229 $this->loops[0]->setAttribute('with_loop', true);
230 }
231
232 protected function addLoopToAll()
233 {
234 foreach ($this->loops as $loop) {
235 $loop->setAttribute('with_loop', true);
236 }
237 }
238
239 /**
240 * {@inheritdoc}
241 */
242 public function getPriority()
243 {
244 return 255;
245 }
246}
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php b/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php
new file mode 100644
index 00000000..c4bbd812
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php
@@ -0,0 +1,131 @@
1<?php
2
3class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
4{
5 protected $data = array();
6 protected $safeVars = array();
7
8 public function setSafeVars($safeVars)
9 {
10 $this->safeVars = $safeVars;
11 }
12
13 public function getSafe(Twig_NodeInterface $node)
14 {
15 $hash = spl_object_hash($node);
16 if (isset($this->data[$hash])) {
17 foreach ($this->data[$hash] as $bucket) {
18 if ($bucket['key'] === $node) {
19 return $bucket['value'];
20 }
21 }
22 }
23 }
24
25 protected function setSafe(Twig_NodeInterface $node, array $safe)
26 {
27 $hash = spl_object_hash($node);
28 if (isset($this->data[$hash])) {
29 foreach ($this->data[$hash] as &$bucket) {
30 if ($bucket['key'] === $node) {
31 $bucket['value'] = $safe;
32
33 return;
34 }
35 }
36 }
37 $this->data[$hash][] = array(
38 'key' => $node,
39 'value' => $safe,
40 );
41 }
42
43 public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
44 {
45 return $node;
46 }
47
48 public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
49 {
50 if ($node instanceof Twig_Node_Expression_Constant) {
51 // constants are marked safe for all
52 $this->setSafe($node, array('all'));
53 } elseif ($node instanceof Twig_Node_Expression_BlockReference) {
54 // blocks are safe by definition
55 $this->setSafe($node, array('all'));
56 } elseif ($node instanceof Twig_Node_Expression_Parent) {
57 // parent block is safe by definition
58 $this->setSafe($node, array('all'));
59 } elseif ($node instanceof Twig_Node_Expression_Conditional) {
60 // intersect safeness of both operands
61 $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
62 $this->setSafe($node, $safe);
63 } elseif ($node instanceof Twig_Node_Expression_Filter) {
64 // filter expression is safe when the filter is safe
65 $name = $node->getNode('filter')->getAttribute('value');
66 $args = $node->getNode('arguments');
67 if (false !== $filter = $env->getFilter($name)) {
68 $safe = $filter->getSafe($args);
69 if (null === $safe) {
70 $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
71 }
72 $this->setSafe($node, $safe);
73 } else {
74 $this->setSafe($node, array());
75 }
76 } elseif ($node instanceof Twig_Node_Expression_Function) {
77 // function expression is safe when the function is safe
78 $name = $node->getAttribute('name');
79 $args = $node->getNode('arguments');
80 $function = $env->getFunction($name);
81 if (false !== $function) {
82 $this->setSafe($node, $function->getSafe($args));
83 } else {
84 $this->setSafe($node, array());
85 }
86 } elseif ($node instanceof Twig_Node_Expression_MethodCall) {
87 if ($node->getAttribute('safe')) {
88 $this->setSafe($node, array('all'));
89 } else {
90 $this->setSafe($node, array());
91 }
92 } elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) {
93 $name = $node->getNode('node')->getAttribute('name');
94 // attributes on template instances are safe
95 if ('_self' == $name || in_array($name, $this->safeVars)) {
96 $this->setSafe($node, array('all'));
97 } else {
98 $this->setSafe($node, array());
99 }
100 } else {
101 $this->setSafe($node, array());
102 }
103
104 return $node;
105 }
106
107 protected function intersectSafe(array $a = null, array $b = null)
108 {
109 if (null === $a || null === $b) {
110 return array();
111 }
112
113 if (in_array('all', $a)) {
114 return $b;
115 }
116
117 if (in_array('all', $b)) {
118 return $a;
119 }
120
121 return array_intersect($a, $b);
122 }
123
124 /**
125 * {@inheritdoc}
126 */
127 public function getPriority()
128 {
129 return 0;
130 }
131}
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitor/Sandbox.php b/vendor/twig/twig/lib/Twig/NodeVisitor/Sandbox.php
new file mode 100644
index 00000000..fb27045b
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/NodeVisitor/Sandbox.php
@@ -0,0 +1,92 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Twig_NodeVisitor_Sandbox implements sandboxing.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
18{
19 protected $inAModule = false;
20 protected $tags;
21 protected $filters;
22 protected $functions;
23
24 /**
25 * Called before child nodes are visited.
26 *
27 * @param Twig_NodeInterface $node The node to visit
28 * @param Twig_Environment $env The Twig environment instance
29 *
30 * @return Twig_NodeInterface The modified node
31 */
32 public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
33 {
34 if ($node instanceof Twig_Node_Module) {
35 $this->inAModule = true;
36 $this->tags = array();
37 $this->filters = array();
38 $this->functions = array();
39
40 return $node;
41 } elseif ($this->inAModule) {
42 // look for tags
43 if ($node->getNodeTag()) {
44 $this->tags[] = $node->getNodeTag();
45 }
46
47 // look for filters
48 if ($node instanceof Twig_Node_Expression_Filter) {
49 $this->filters[] = $node->getNode('filter')->getAttribute('value');
50 }
51
52 // look for functions
53 if ($node instanceof Twig_Node_Expression_Function) {
54 $this->functions[] = $node->getAttribute('name');
55 }
56
57 // wrap print to check __toString() calls
58 if ($node instanceof Twig_Node_Print) {
59 return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag());
60 }
61 }
62
63 return $node;
64 }
65
66 /**
67 * Called after child nodes are visited.
68 *
69 * @param Twig_NodeInterface $node The node to visit
70 * @param Twig_Environment $env The Twig environment instance
71 *
72 * @return Twig_NodeInterface The modified node
73 */
74 public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
75 {
76 if ($node instanceof Twig_Node_Module) {
77 $this->inAModule = false;
78
79 return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags), array_unique($this->functions));
80 }
81
82 return $node;
83 }
84
85 /**
86 * {@inheritdoc}
87 */
88 public function getPriority()
89 {
90 return 0;
91 }
92}
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitorInterface.php b/vendor/twig/twig/lib/Twig/NodeVisitorInterface.php
new file mode 100644
index 00000000..f33c13fc
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/NodeVisitorInterface.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Twig_NodeVisitorInterface is the interface the all node visitor classes must implement.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17interface Twig_NodeVisitorInterface
18{
19 /**
20 * Called before child nodes are visited.
21 *
22 * @param Twig_NodeInterface $node The node to visit
23 * @param Twig_Environment $env The Twig environment instance
24 *
25 * @return Twig_NodeInterface The modified node
26 */
27 public function enterNode(Twig_NodeInterface $node, Twig_Environment $env);
28
29 /**
30 * Called after child nodes are visited.
31 *
32 * @param Twig_NodeInterface $node The node to visit
33 * @param Twig_Environment $env The Twig environment instance
34 *
35 * @return Twig_NodeInterface|false The modified node or false if the node must be removed
36 */
37 public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env);
38
39 /**
40 * Returns the priority for this visitor.
41 *
42 * Priority should be between -10 and 10 (0 is the default).
43 *
44 * @return integer The priority level
45 */
46 public function getPriority();
47}
diff --git a/vendor/twig/twig/lib/Twig/Parser.php b/vendor/twig/twig/lib/Twig/Parser.php
new file mode 100644
index 00000000..958e46b3
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Parser.php
@@ -0,0 +1,394 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Default parser implementation.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Parser implements Twig_ParserInterface
19{
20 protected $stack = array();
21 protected $stream;
22 protected $parent;
23 protected $handlers;
24 protected $visitors;
25 protected $expressionParser;
26 protected $blocks;
27 protected $blockStack;
28 protected $macros;
29 protected $env;
30 protected $reservedMacroNames;
31 protected $importedSymbols;
32 protected $traits;
33 protected $embeddedTemplates = array();
34
35 /**
36 * Constructor.
37 *
38 * @param Twig_Environment $env A Twig_Environment instance
39 */
40 public function __construct(Twig_Environment $env)
41 {
42 $this->env = $env;
43 }
44
45 public function getEnvironment()
46 {
47 return $this->env;
48 }
49
50 public function getVarName()
51 {
52 return sprintf('__internal_%s', hash('sha1', uniqid(mt_rand(), true), false));
53 }
54
55 public function getFilename()
56 {
57 return $this->stream->getFilename();
58 }
59
60 /**
61 * Converts a token stream to a node tree.
62 *
63 * @param Twig_TokenStream $stream A token stream instance
64 *
65 * @return Twig_Node_Module A node tree
66 */
67 public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
68 {
69 // push all variables into the stack to keep the current state of the parser
70 $vars = get_object_vars($this);
71 unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']);
72 $this->stack[] = $vars;
73
74 // tag handlers
75 if (null === $this->handlers) {
76 $this->handlers = $this->env->getTokenParsers();
77 $this->handlers->setParser($this);
78 }
79
80 // node visitors
81 if (null === $this->visitors) {
82 $this->visitors = $this->env->getNodeVisitors();
83 }
84
85 if (null === $this->expressionParser) {
86 $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators());
87 }
88
89 $this->stream = $stream;
90 $this->parent = null;
91 $this->blocks = array();
92 $this->macros = array();
93 $this->traits = array();
94 $this->blockStack = array();
95 $this->importedSymbols = array(array());
96 $this->embeddedTemplates = array();
97
98 try {
99 $body = $this->subparse($test, $dropNeedle);
100
101 if (null !== $this->parent) {
102 if (null === $body = $this->filterBodyNodes($body)) {
103 $body = new Twig_Node();
104 }
105 }
106 } catch (Twig_Error_Syntax $e) {
107 if (!$e->getTemplateFile()) {
108 $e->setTemplateFile($this->getFilename());
109 }
110
111 if (!$e->getTemplateLine()) {
112 $e->setTemplateLine($this->stream->getCurrent()->getLine());
113 }
114
115 throw $e;
116 }
117
118 $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename());
119
120 $traverser = new Twig_NodeTraverser($this->env, $this->visitors);
121
122 $node = $traverser->traverse($node);
123
124 // restore previous stack so previous parse() call can resume working
125 foreach (array_pop($this->stack) as $key => $val) {
126 $this->$key = $val;
127 }
128
129 return $node;
130 }
131
132 public function subparse($test, $dropNeedle = false)
133 {
134 $lineno = $this->getCurrentToken()->getLine();
135 $rv = array();
136 while (!$this->stream->isEOF()) {
137 switch ($this->getCurrentToken()->getType()) {
138 case Twig_Token::TEXT_TYPE:
139 $token = $this->stream->next();
140 $rv[] = new Twig_Node_Text($token->getValue(), $token->getLine());
141 break;
142
143 case Twig_Token::VAR_START_TYPE:
144 $token = $this->stream->next();
145 $expr = $this->expressionParser->parseExpression();
146 $this->stream->expect(Twig_Token::VAR_END_TYPE);
147 $rv[] = new Twig_Node_Print($expr, $token->getLine());
148 break;
149
150 case Twig_Token::BLOCK_START_TYPE:
151 $this->stream->next();
152 $token = $this->getCurrentToken();
153
154 if ($token->getType() !== Twig_Token::NAME_TYPE) {
155 throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename());
156 }
157
158 if (null !== $test && call_user_func($test, $token)) {
159 if ($dropNeedle) {
160 $this->stream->next();
161 }
162
163 if (1 === count($rv)) {
164 return $rv[0];
165 }
166
167 return new Twig_Node($rv, array(), $lineno);
168 }
169
170 $subparser = $this->handlers->getTokenParser($token->getValue());
171 if (null === $subparser) {
172 if (null !== $test) {
173 $error = sprintf('Unexpected tag name "%s"', $token->getValue());
174 if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
175 $error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno);
176 }
177
178 throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename());
179 }
180
181 $message = sprintf('Unknown tag name "%s"', $token->getValue());
182 if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) {
183 $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
184 }
185
186 throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename());
187 }
188
189 $this->stream->next();
190
191 $node = $subparser->parse($token);
192 if (null !== $node) {
193 $rv[] = $node;
194 }
195 break;
196
197 default:
198 throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
199 }
200 }
201
202 if (1 === count($rv)) {
203 return $rv[0];
204 }
205
206 return new Twig_Node($rv, array(), $lineno);
207 }
208
209 public function addHandler($name, $class)
210 {
211 $this->handlers[$name] = $class;
212 }
213
214 public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
215 {
216 $this->visitors[] = $visitor;
217 }
218
219 public function getBlockStack()
220 {
221 return $this->blockStack;
222 }
223
224 public function peekBlockStack()
225 {
226 return $this->blockStack[count($this->blockStack) - 1];
227 }
228
229 public function popBlockStack()
230 {
231 array_pop($this->blockStack);
232 }
233
234 public function pushBlockStack($name)
235 {
236 $this->blockStack[] = $name;
237 }
238
239 public function hasBlock($name)
240 {
241 return isset($this->blocks[$name]);
242 }
243
244 public function getBlock($name)
245 {
246 return $this->blocks[$name];
247 }
248
249 public function setBlock($name, $value)
250 {
251 $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine());
252 }
253
254 public function hasMacro($name)
255 {
256 return isset($this->macros[$name]);
257 }
258
259 public function setMacro($name, Twig_Node_Macro $node)
260 {
261 if (null === $this->reservedMacroNames) {
262 $this->reservedMacroNames = array();
263 $r = new ReflectionClass($this->env->getBaseTemplateClass());
264 foreach ($r->getMethods() as $method) {
265 $this->reservedMacroNames[] = $method->getName();
266 }
267 }
268
269 if (in_array($name, $this->reservedMacroNames)) {
270 throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename());
271 }
272
273 $this->macros[$name] = $node;
274 }
275
276 public function addTrait($trait)
277 {
278 $this->traits[] = $trait;
279 }
280
281 public function hasTraits()
282 {
283 return count($this->traits) > 0;
284 }
285
286 public function embedTemplate(Twig_Node_Module $template)
287 {
288 $template->setIndex(mt_rand());
289
290 $this->embeddedTemplates[] = $template;
291 }
292
293 public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null)
294 {
295 $this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node);
296 }
297
298 public function getImportedSymbol($type, $alias)
299 {
300 foreach ($this->importedSymbols as $functions) {
301 if (isset($functions[$type][$alias])) {
302 return $functions[$type][$alias];
303 }
304 }
305 }
306
307 public function isMainScope()
308 {
309 return 1 === count($this->importedSymbols);
310 }
311
312 public function pushLocalScope()
313 {
314 array_unshift($this->importedSymbols, array());
315 }
316
317 public function popLocalScope()
318 {
319 array_shift($this->importedSymbols);
320 }
321
322 /**
323 * Gets the expression parser.
324 *
325 * @return Twig_ExpressionParser The expression parser
326 */
327 public function getExpressionParser()
328 {
329 return $this->expressionParser;
330 }
331
332 public function getParent()
333 {
334 return $this->parent;
335 }
336
337 public function setParent($parent)
338 {
339 $this->parent = $parent;
340 }
341
342 /**
343 * Gets the token stream.
344 *
345 * @return Twig_TokenStream The token stream
346 */
347 public function getStream()
348 {
349 return $this->stream;
350 }
351
352 /**
353 * Gets the current token.
354 *
355 * @return Twig_Token The current token
356 */
357 public function getCurrentToken()
358 {
359 return $this->stream->getCurrent();
360 }
361
362 protected function filterBodyNodes(Twig_NodeInterface $node)
363 {
364 // check that the body does not contain non-empty output nodes
365 if (
366 ($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data')))
367 ||
368 (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
369 ) {
370 if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
371 throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename());
372 }
373
374 throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename());
375 }
376
377 // bypass "set" nodes as they "capture" the output
378 if ($node instanceof Twig_Node_Set) {
379 return $node;
380 }
381
382 if ($node instanceof Twig_NodeOutputInterface) {
383 return;
384 }
385
386 foreach ($node as $k => $n) {
387 if (null !== $n && null === $n = $this->filterBodyNodes($n)) {
388 $node->removeNode($k);
389 }
390 }
391
392 return $node;
393 }
394}
diff --git a/vendor/twig/twig/lib/Twig/ParserInterface.php b/vendor/twig/twig/lib/Twig/ParserInterface.php
new file mode 100644
index 00000000..f0d79009
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/ParserInterface.php
@@ -0,0 +1,28 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Interface implemented by parser classes.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18interface Twig_ParserInterface
19{
20 /**
21 * Converts a token stream to a node tree.
22 *
23 * @param Twig_TokenStream $stream A token stream instance
24 *
25 * @return Twig_Node_Module A node tree
26 */
27 public function parse(Twig_TokenStream $stream);
28}
diff --git a/vendor/twig/twig/lib/Twig/Sandbox/SecurityError.php b/vendor/twig/twig/lib/Twig/Sandbox/SecurityError.php
new file mode 100644
index 00000000..015bfaea
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Sandbox/SecurityError.php
@@ -0,0 +1,19 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Exception thrown when a security error occurs at runtime.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Sandbox_SecurityError extends Twig_Error
18{
19}
diff --git a/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php b/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php
new file mode 100644
index 00000000..66ee2332
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php
@@ -0,0 +1,119 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Represents a security policy which need to be enforced when sandbox mode is enabled.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface
18{
19 protected $allowedTags;
20 protected $allowedFilters;
21 protected $allowedMethods;
22 protected $allowedProperties;
23 protected $allowedFunctions;
24
25 public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array())
26 {
27 $this->allowedTags = $allowedTags;
28 $this->allowedFilters = $allowedFilters;
29 $this->setAllowedMethods($allowedMethods);
30 $this->allowedProperties = $allowedProperties;
31 $this->allowedFunctions = $allowedFunctions;
32 }
33
34 public function setAllowedTags(array $tags)
35 {
36 $this->allowedTags = $tags;
37 }
38
39 public function setAllowedFilters(array $filters)
40 {
41 $this->allowedFilters = $filters;
42 }
43
44 public function setAllowedMethods(array $methods)
45 {
46 $this->allowedMethods = array();
47 foreach ($methods as $class => $m) {
48 $this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m));
49 }
50 }
51
52 public function setAllowedProperties(array $properties)
53 {
54 $this->allowedProperties = $properties;
55 }
56
57 public function setAllowedFunctions(array $functions)
58 {
59 $this->allowedFunctions = $functions;
60 }
61
62 public function checkSecurity($tags, $filters, $functions)
63 {
64 foreach ($tags as $tag) {
65 if (!in_array($tag, $this->allowedTags)) {
66 throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not allowed.', $tag));
67 }
68 }
69
70 foreach ($filters as $filter) {
71 if (!in_array($filter, $this->allowedFilters)) {
72 throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter));
73 }
74 }
75
76 foreach ($functions as $function) {
77 if (!in_array($function, $this->allowedFunctions)) {
78 throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function));
79 }
80 }
81 }
82
83 public function checkMethodAllowed($obj, $method)
84 {
85 if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) {
86 return true;
87 }
88
89 $allowed = false;
90 $method = strtolower($method);
91 foreach ($this->allowedMethods as $class => $methods) {
92 if ($obj instanceof $class) {
93 $allowed = in_array($method, $methods);
94
95 break;
96 }
97 }
98
99 if (!$allowed) {
100 throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
101 }
102 }
103
104 public function checkPropertyAllowed($obj, $property)
105 {
106 $allowed = false;
107 foreach ($this->allowedProperties as $class => $properties) {
108 if ($obj instanceof $class) {
109 $allowed = in_array($property, is_array($properties) ? $properties : array($properties));
110
111 break;
112 }
113 }
114
115 if (!$allowed) {
116 throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj)));
117 }
118 }
119}
diff --git a/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php b/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php
new file mode 100644
index 00000000..6ab48e3c
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php
@@ -0,0 +1,24 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Interfaces that all security policy classes must implements.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17interface Twig_Sandbox_SecurityPolicyInterface
18{
19 public function checkSecurity($tags, $filters, $functions);
20
21 public function checkMethodAllowed($obj, $method);
22
23 public function checkPropertyAllowed($obj, $method);
24}
diff --git a/vendor/twig/twig/lib/Twig/SimpleFilter.php b/vendor/twig/twig/lib/Twig/SimpleFilter.php
new file mode 100644
index 00000000..d35c5633
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/SimpleFilter.php
@@ -0,0 +1,94 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009-2012 Fabien Potencier
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 * Represents a template filter.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_SimpleFilter
18{
19 protected $name;
20 protected $callable;
21 protected $options;
22 protected $arguments = array();
23
24 public function __construct($name, $callable, array $options = array())
25 {
26 $this->name = $name;
27 $this->callable = $callable;
28 $this->options = array_merge(array(
29 'needs_environment' => false,
30 'needs_context' => false,
31 'is_safe' => null,
32 'is_safe_callback' => null,
33 'pre_escape' => null,
34 'preserves_safety' => null,
35 'node_class' => 'Twig_Node_Expression_Filter',
36 ), $options);
37 }
38
39 public function getName()
40 {
41 return $this->name;
42 }
43
44 public function getCallable()
45 {
46 return $this->callable;
47 }
48
49 public function getNodeClass()
50 {
51 return $this->options['node_class'];
52 }
53
54 public function setArguments($arguments)
55 {
56 $this->arguments = $arguments;
57 }
58
59 public function getArguments()
60 {
61 return $this->arguments;
62 }
63
64 public function needsEnvironment()
65 {
66 return $this->options['needs_environment'];
67 }
68
69 public function needsContext()
70 {
71 return $this->options['needs_context'];
72 }
73
74 public function getSafe(Twig_Node $filterArgs)
75 {
76 if (null !== $this->options['is_safe']) {
77 return $this->options['is_safe'];
78 }
79
80 if (null !== $this->options['is_safe_callback']) {
81 return call_user_func($this->options['is_safe_callback'], $filterArgs);
82 }
83 }
84
85 public function getPreservesSafety()
86 {
87 return $this->options['preserves_safety'];
88 }
89
90 public function getPreEscape()
91 {
92 return $this->options['pre_escape'];
93 }
94}
diff --git a/vendor/twig/twig/lib/Twig/SimpleFunction.php b/vendor/twig/twig/lib/Twig/SimpleFunction.php
new file mode 100644
index 00000000..8ef6aca2
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/SimpleFunction.php
@@ -0,0 +1,84 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010-2012 Fabien Potencier
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 * Represents a template function.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_SimpleFunction
18{
19 protected $name;
20 protected $callable;
21 protected $options;
22 protected $arguments = array();
23
24 public function __construct($name, $callable, array $options = array())
25 {
26 $this->name = $name;
27 $this->callable = $callable;
28 $this->options = array_merge(array(
29 'needs_environment' => false,
30 'needs_context' => false,
31 'is_safe' => null,
32 'is_safe_callback' => null,
33 'node_class' => 'Twig_Node_Expression_Function',
34 ), $options);
35 }
36
37 public function getName()
38 {
39 return $this->name;
40 }
41
42 public function getCallable()
43 {
44 return $this->callable;
45 }
46
47 public function getNodeClass()
48 {
49 return $this->options['node_class'];
50 }
51
52 public function setArguments($arguments)
53 {
54 $this->arguments = $arguments;
55 }
56
57 public function getArguments()
58 {
59 return $this->arguments;
60 }
61
62 public function needsEnvironment()
63 {
64 return $this->options['needs_environment'];
65 }
66
67 public function needsContext()
68 {
69 return $this->options['needs_context'];
70 }
71
72 public function getSafe(Twig_Node $functionArgs)
73 {
74 if (null !== $this->options['is_safe']) {
75 return $this->options['is_safe'];
76 }
77
78 if (null !== $this->options['is_safe_callback']) {
79 return call_user_func($this->options['is_safe_callback'], $functionArgs);
80 }
81
82 return array();
83 }
84}
diff --git a/vendor/twig/twig/lib/Twig/SimpleTest.php b/vendor/twig/twig/lib/Twig/SimpleTest.php
new file mode 100644
index 00000000..225459c9
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/SimpleTest.php
@@ -0,0 +1,46 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010-2012 Fabien Potencier
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 * Represents a template test.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class Twig_SimpleTest
18{
19 protected $name;
20 protected $callable;
21 protected $options;
22
23 public function __construct($name, $callable, array $options = array())
24 {
25 $this->name = $name;
26 $this->callable = $callable;
27 $this->options = array_merge(array(
28 'node_class' => 'Twig_Node_Expression_Test',
29 ), $options);
30 }
31
32 public function getName()
33 {
34 return $this->name;
35 }
36
37 public function getCallable()
38 {
39 return $this->callable;
40 }
41
42 public function getNodeClass()
43 {
44 return $this->options['node_class'];
45 }
46}
diff --git a/vendor/twig/twig/lib/Twig/Template.php b/vendor/twig/twig/lib/Twig/Template.php
new file mode 100644
index 00000000..a001ca03
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Template.php
@@ -0,0 +1,455 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Default base class for compiled templates.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18abstract class Twig_Template implements Twig_TemplateInterface
19{
20 protected static $cache = array();
21
22 protected $parent;
23 protected $parents;
24 protected $env;
25 protected $blocks;
26 protected $traits;
27
28 /**
29 * Constructor.
30 *
31 * @param Twig_Environment $env A Twig_Environment instance
32 */
33 public function __construct(Twig_Environment $env)
34 {
35 $this->env = $env;
36 $this->blocks = array();
37 $this->traits = array();
38 }
39
40 /**
41 * Returns the template name.
42 *
43 * @return string The template name
44 */
45 abstract public function getTemplateName();
46
47 /**
48 * {@inheritdoc}
49 */
50 public function getEnvironment()
51 {
52 return $this->env;
53 }
54
55 /**
56 * Returns the parent template.
57 *
58 * This method is for internal use only and should never be called
59 * directly.
60 *
61 * @return Twig_TemplateInterface|false The parent template or false if there is no parent
62 */
63 public function getParent(array $context)
64 {
65 if (null !== $this->parent) {
66 return $this->parent;
67 }
68
69 $parent = $this->doGetParent($context);
70 if (false === $parent) {
71 return false;
72 } elseif ($parent instanceof Twig_Template) {
73 $name = $parent->getTemplateName();
74 $this->parents[$name] = $parent;
75 $parent = $name;
76 } elseif (!isset($this->parents[$parent])) {
77 $this->parents[$parent] = $this->env->loadTemplate($parent);
78 }
79
80 return $this->parents[$parent];
81 }
82
83 protected function doGetParent(array $context)
84 {
85 return false;
86 }
87
88 public function isTraitable()
89 {
90 return true;
91 }
92
93 /**
94 * Displays a parent block.
95 *
96 * This method is for internal use only and should never be called
97 * directly.
98 *
99 * @param string $name The block name to display from the parent
100 * @param array $context The context
101 * @param array $blocks The current set of blocks
102 */
103 public function displayParentBlock($name, array $context, array $blocks = array())
104 {
105 $name = (string) $name;
106
107 if (isset($this->traits[$name])) {
108 $this->traits[$name][0]->displayBlock($name, $context, $blocks);
109 } elseif (false !== $parent = $this->getParent($context)) {
110 $parent->displayBlock($name, $context, $blocks);
111 } else {
112 throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
113 }
114 }
115
116 /**
117 * Displays a block.
118 *
119 * This method is for internal use only and should never be called
120 * directly.
121 *
122 * @param string $name The block name to display
123 * @param array $context The context
124 * @param array $blocks The current set of blocks
125 */
126 public function displayBlock($name, array $context, array $blocks = array())
127 {
128 $name = (string) $name;
129
130 if (isset($blocks[$name])) {
131 $b = $blocks;
132 unset($b[$name]);
133 call_user_func($blocks[$name], $context, $b);
134 } elseif (isset($this->blocks[$name])) {
135 call_user_func($this->blocks[$name], $context, $blocks);
136 } elseif (false !== $parent = $this->getParent($context)) {
137 $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks));
138 }
139 }
140
141 /**
142 * Renders a parent block.
143 *
144 * This method is for internal use only and should never be called
145 * directly.
146 *
147 * @param string $name The block name to render from the parent
148 * @param array $context The context
149 * @param array $blocks The current set of blocks
150 *
151 * @return string The rendered block
152 */
153 public function renderParentBlock($name, array $context, array $blocks = array())
154 {
155 ob_start();
156 $this->displayParentBlock($name, $context, $blocks);
157
158 return ob_get_clean();
159 }
160
161 /**
162 * Renders a block.
163 *
164 * This method is for internal use only and should never be called
165 * directly.
166 *
167 * @param string $name The block name to render
168 * @param array $context The context
169 * @param array $blocks The current set of blocks
170 *
171 * @return string The rendered block
172 */
173 public function renderBlock($name, array $context, array $blocks = array())
174 {
175 ob_start();
176 $this->displayBlock($name, $context, $blocks);
177
178 return ob_get_clean();
179 }
180
181 /**
182 * Returns whether a block exists or not.
183 *
184 * This method is for internal use only and should never be called
185 * directly.
186 *
187 * This method does only return blocks defined in the current template
188 * or defined in "used" traits.
189 *
190 * It does not return blocks from parent templates as the parent
191 * template name can be dynamic, which is only known based on the
192 * current context.
193 *
194 * @param string $name The block name
195 *
196 * @return Boolean true if the block exists, false otherwise
197 */
198 public function hasBlock($name)
199 {
200 return isset($this->blocks[(string) $name]);
201 }
202
203 /**
204 * Returns all block names.
205 *
206 * This method is for internal use only and should never be called
207 * directly.
208 *
209 * @return array An array of block names
210 *
211 * @see hasBlock
212 */
213 public function getBlockNames()
214 {
215 return array_keys($this->blocks);
216 }
217
218 /**
219 * Returns all blocks.
220 *
221 * This method is for internal use only and should never be called
222 * directly.
223 *
224 * @return array An array of blocks
225 *
226 * @see hasBlock
227 */
228 public function getBlocks()
229 {
230 return $this->blocks;
231 }
232
233 /**
234 * {@inheritdoc}
235 */
236 public function display(array $context, array $blocks = array())
237 {
238 $this->displayWithErrorHandling($this->env->mergeGlobals($context), $blocks);
239 }
240
241 /**
242 * {@inheritdoc}
243 */
244 public function render(array $context)
245 {
246 $level = ob_get_level();
247 ob_start();
248 try {
249 $this->display($context);
250 } catch (Exception $e) {
251 while (ob_get_level() > $level) {
252 ob_end_clean();
253 }
254
255 throw $e;
256 }
257
258 return ob_get_clean();
259 }
260
261 protected function displayWithErrorHandling(array $context, array $blocks = array())
262 {
263 try {
264 $this->doDisplay($context, $blocks);
265 } catch (Twig_Error $e) {
266 if (!$e->getTemplateFile()) {
267 $e->setTemplateFile($this->getTemplateName());
268 }
269
270 // this is mostly useful for Twig_Error_Loader exceptions
271 // see Twig_Error_Loader
272 if (false === $e->getTemplateLine()) {
273 $e->setTemplateLine(-1);
274 $e->guess();
275 }
276
277 throw $e;
278 } catch (Exception $e) {
279 throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, null, $e);
280 }
281 }
282
283 /**
284 * Auto-generated method to display the template with the given context.
285 *
286 * @param array $context An array of parameters to pass to the template
287 * @param array $blocks An array of blocks to pass to the template
288 */
289 abstract protected function doDisplay(array $context, array $blocks = array());
290
291 /**
292 * Returns a variable from the context.
293 *
294 * This method is for internal use only and should never be called
295 * directly.
296 *
297 * This method should not be overridden in a sub-class as this is an
298 * implementation detail that has been introduced to optimize variable
299 * access for versions of PHP before 5.4. This is not a way to override
300 * the way to get a variable value.
301 *
302 * @param array $context The context
303 * @param string $item The variable to return from the context
304 * @param Boolean $ignoreStrictCheck Whether to ignore the strict variable check or not
305 *
306 * @return The content of the context variable
307 *
308 * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode
309 */
310 final protected function getContext($context, $item, $ignoreStrictCheck = false)
311 {
312 if (!array_key_exists($item, $context)) {
313 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
314 return null;
315 }
316
317 throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName());
318 }
319
320 return $context[$item];
321 }
322
323 /**
324 * Returns the attribute value for a given array/object.
325 *
326 * @param mixed $object The object or array from where to get the item
327 * @param mixed $item The item to get from the array or object
328 * @param array $arguments An array of arguments to pass if the item is an object method
329 * @param string $type The type of attribute (@see Twig_TemplateInterface)
330 * @param Boolean $isDefinedTest Whether this is only a defined check
331 * @param Boolean $ignoreStrictCheck Whether to ignore the strict attribute check or not
332 *
333 * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
334 *
335 * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
336 */
337 protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
338 {
339 // array
340 if (Twig_TemplateInterface::METHOD_CALL !== $type) {
341 $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
342
343 if ((is_array($object) && array_key_exists($arrayItem, $object))
344 || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
345 ) {
346 if ($isDefinedTest) {
347 return true;
348 }
349
350 return $object[$arrayItem];
351 }
352
353 if (Twig_TemplateInterface::ARRAY_CALL === $type || !is_object($object)) {
354 if ($isDefinedTest) {
355 return false;
356 }
357
358 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
359 return null;
360 }
361
362 if (is_object($object)) {
363 throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName());
364 } elseif (is_array($object)) {
365 throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName());
366 } elseif (Twig_TemplateInterface::ARRAY_CALL === $type) {
367 throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
368 } else {
369 throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
370 }
371 }
372 }
373
374 if (!is_object($object)) {
375 if ($isDefinedTest) {
376 return false;
377 }
378
379 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
380 return null;
381 }
382
383 throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
384 }
385
386 $class = get_class($object);
387
388 // object property
389 if (Twig_TemplateInterface::METHOD_CALL !== $type) {
390 if (isset($object->$item) || array_key_exists((string) $item, $object)) {
391 if ($isDefinedTest) {
392 return true;
393 }
394
395 if ($this->env->hasExtension('sandbox')) {
396 $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
397 }
398
399 return $object->$item;
400 }
401 }
402
403 // object method
404 if (!isset(self::$cache[$class]['methods'])) {
405 self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
406 }
407
408 $lcItem = strtolower($item);
409 if (isset(self::$cache[$class]['methods'][$lcItem])) {
410 $method = (string) $item;
411 } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
412 $method = 'get'.$item;
413 } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
414 $method = 'is'.$item;
415 } elseif (isset(self::$cache[$class]['methods']['__call'])) {
416 $method = (string) $item;
417 } else {
418 if ($isDefinedTest) {
419 return false;
420 }
421
422 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
423 return null;
424 }
425
426 throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
427 }
428
429 if ($isDefinedTest) {
430 return true;
431 }
432
433 if ($this->env->hasExtension('sandbox')) {
434 $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
435 }
436
437 $ret = call_user_func_array(array($object, $method), $arguments);
438
439 // useful when calling a template method from a template
440 // this is not supported but unfortunately heavily used in the Symfony profiler
441 if ($object instanceof Twig_TemplateInterface) {
442 return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
443 }
444
445 return $ret;
446 }
447
448 /**
449 * This method is only useful when testing Twig. Do not use it.
450 */
451 public static function clearCache()
452 {
453 self::$cache = array();
454 }
455}
diff --git a/vendor/twig/twig/lib/Twig/TemplateInterface.php b/vendor/twig/twig/lib/Twig/TemplateInterface.php
new file mode 100644
index 00000000..879f503e
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TemplateInterface.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Interface implemented by all compiled templates.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18interface Twig_TemplateInterface
19{
20 const ANY_CALL = 'any';
21 const ARRAY_CALL = 'array';
22 const METHOD_CALL = 'method';
23
24 /**
25 * Renders the template with the given context and returns it as string.
26 *
27 * @param array $context An array of parameters to pass to the template
28 *
29 * @return string The rendered template
30 */
31 public function render(array $context);
32
33 /**
34 * Displays the template with the given context.
35 *
36 * @param array $context An array of parameters to pass to the template
37 * @param array $blocks An array of blocks to pass to the template
38 */
39 public function display(array $context, array $blocks = array());
40
41 /**
42 * Returns the bound environment for this template.
43 *
44 * @return Twig_Environment The current environment
45 */
46 public function getEnvironment();
47}
diff --git a/vendor/twig/twig/lib/Twig/Test.php b/vendor/twig/twig/lib/Twig/Test.php
new file mode 100644
index 00000000..3baff885
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Test.php
@@ -0,0 +1,34 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
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 * Represents a template test.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface
19{
20 protected $options;
21 protected $arguments = array();
22
23 public function __construct(array $options = array())
24 {
25 $this->options = array_merge(array(
26 'callable' => null,
27 ), $options);
28 }
29
30 public function getCallable()
31 {
32 return $this->options['callable'];
33 }
34}
diff --git a/vendor/twig/twig/lib/Twig/Test/Function.php b/vendor/twig/twig/lib/Twig/Test/Function.php
new file mode 100644
index 00000000..4be6b9b9
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Test/Function.php
@@ -0,0 +1,35 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a function template test.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18class Twig_Test_Function extends Twig_Test
19{
20 protected $function;
21
22 public function __construct($function, array $options = array())
23 {
24 $options['callable'] = $function;
25
26 parent::__construct($options);
27
28 $this->function = $function;
29 }
30
31 public function compile()
32 {
33 return $this->function;
34 }
35}
diff --git a/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php b/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php
new file mode 100644
index 00000000..724f0941
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php
@@ -0,0 +1,154 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Integration test helper
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @author Karma Dordrak <drak@zikula.org>
17 */
18abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase
19{
20 abstract protected function getExtensions();
21 abstract protected function getFixturesDir();
22
23 /**
24 * @dataProvider getTests
25 */
26 public function testIntegration($file, $message, $condition, $templates, $exception, $outputs)
27 {
28 $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs);
29 }
30
31 public function getTests()
32 {
33 $fixturesDir = realpath($this->getFixturesDir());
34 $tests = array();
35
36 foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
37 if (!preg_match('/\.test$/', $file)) {
38 continue;
39 }
40
41 $test = file_get_contents($file->getRealpath());
42
43 if (preg_match('/
44 --TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) {
45 $message = $match[1];
46 $condition = $match[2];
47 $templates = $this->parseTemplates($match[3]);
48 $exception = $match[5];
49 $outputs = array(array(null, $match[4], null, ''));
50 } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) {
51 $message = $match[1];
52 $condition = $match[2];
53 $templates = $this->parseTemplates($match[3]);
54 $exception = false;
55 preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER);
56 } else {
57 throw new InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file)));
58 }
59
60 $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs);
61 }
62
63 return $tests;
64 }
65
66 protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs)
67 {
68 if ($condition) {
69 eval('$ret = '.$condition.';');
70 if (!$ret) {
71 $this->markTestSkipped($condition);
72 }
73 }
74
75 $loader = new Twig_Loader_Array($templates);
76
77 foreach ($outputs as $match) {
78 $config = array_merge(array(
79 'cache' => false,
80 'strict_variables' => true,
81 ), $match[2] ? eval($match[2].';') : array());
82 $twig = new Twig_Environment($loader, $config);
83 $twig->addGlobal('global', 'global');
84 foreach ($this->getExtensions() as $extension) {
85 $twig->addExtension($extension);
86 }
87
88 try {
89 $template = $twig->loadTemplate('index.twig');
90 } catch (Exception $e) {
91 if (false !== $exception) {
92 $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage())));
93
94 return;
95 }
96
97 if ($e instanceof Twig_Error_Syntax) {
98 $e->setTemplateFile($file);
99
100 throw $e;
101 }
102
103 throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
104 }
105
106 try {
107 $output = trim($template->render(eval($match[1].';')), "\n ");
108 } catch (Exception $e) {
109 if (false !== $exception) {
110 $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage())));
111
112 return;
113 }
114
115 if ($e instanceof Twig_Error_Syntax) {
116 $e->setTemplateFile($file);
117 } else {
118 $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
119 }
120
121 $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage()));
122 }
123
124 if (false !== $exception) {
125 list($class, ) = explode(':', $exception);
126 $this->assertThat(NULL, new PHPUnit_Framework_Constraint_Exception($class));
127 }
128
129 $expected = trim($match[3], "\n ");
130
131 if ($expected != $output) {
132 echo 'Compiled template that failed:';
133
134 foreach (array_keys($templates) as $name) {
135 echo "Template: $name\n";
136 $source = $loader->getSource($name);
137 echo $twig->compile($twig->parse($twig->tokenize($source, $name)));
138 }
139 }
140 $this->assertEquals($expected, $output, $message.' (in '.$file.')');
141 }
142 }
143
144 protected static function parseTemplates($test)
145 {
146 $templates = array();
147 preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, PREG_SET_ORDER);
148 foreach ($matches as $match) {
149 $templates[($match[1] ? $match[1] : 'index.twig')] = $match[2];
150 }
151
152 return $templates;
153 }
154}
diff --git a/vendor/twig/twig/lib/Twig/Test/Method.php b/vendor/twig/twig/lib/Twig/Test/Method.php
new file mode 100644
index 00000000..17c6c041
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Test/Method.php
@@ -0,0 +1,37 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a method template test.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18class Twig_Test_Method extends Twig_Test
19{
20 protected $extension;
21 protected $method;
22
23 public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
24 {
25 $options['callable'] = array($extension, $method);
26
27 parent::__construct($options);
28
29 $this->extension = $extension;
30 $this->method = $method;
31 }
32
33 public function compile()
34 {
35 return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
36 }
37}
diff --git a/vendor/twig/twig/lib/Twig/Test/Node.php b/vendor/twig/twig/lib/Twig/Test/Node.php
new file mode 100644
index 00000000..c832a57b
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Test/Node.php
@@ -0,0 +1,37 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a template test as a Node.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18class Twig_Test_Node extends Twig_Test
19{
20 protected $class;
21
22 public function __construct($class, array $options = array())
23 {
24 parent::__construct($options);
25
26 $this->class = $class;
27 }
28
29 public function getClass()
30 {
31 return $this->class;
32 }
33
34 public function compile()
35 {
36 }
37}
diff --git a/vendor/twig/twig/lib/Twig/Test/NodeTestCase.php b/vendor/twig/twig/lib/Twig/Test/NodeTestCase.php
new file mode 100644
index 00000000..b15c85ff
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Test/NodeTestCase.php
@@ -0,0 +1,58 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11abstract class Twig_Test_NodeTestCase extends PHPUnit_Framework_TestCase
12{
13 abstract public function getTests();
14
15 /**
16 * @dataProvider getTests
17 */
18 public function testCompile($node, $source, $environment = null)
19 {
20 $this->assertNodeCompilation($source, $node, $environment);
21 }
22
23 public function assertNodeCompilation($source, Twig_Node $node, Twig_Environment $environment = null)
24 {
25 $compiler = $this->getCompiler($environment);
26 $compiler->compile($node);
27
28 $this->assertEquals($source, trim($compiler->getSource()));
29 }
30
31 protected function getCompiler(Twig_Environment $environment = null)
32 {
33 return new Twig_Compiler(null === $environment ? $this->getEnvironment() : $environment);
34 }
35
36 protected function getEnvironment()
37 {
38 return new Twig_Environment();
39 }
40
41 protected function getVariableGetter($name)
42 {
43 if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
44 return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name);
45 }
46
47 return sprintf('$this->getContext($context, "%s")', $name);
48 }
49
50 protected function getAttributeGetter()
51 {
52 if (function_exists('twig_template_get_attributes')) {
53 return 'twig_template_get_attributes($this, ';
54 }
55
56 return '$this->getAttribute(';
57 }
58}
diff --git a/vendor/twig/twig/lib/Twig/TestCallableInterface.php b/vendor/twig/twig/lib/Twig/TestCallableInterface.php
new file mode 100644
index 00000000..0db43682
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TestCallableInterface.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
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 * Represents a callable template test.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18interface Twig_TestCallableInterface
19{
20 public function getCallable();
21}
diff --git a/vendor/twig/twig/lib/Twig/TestInterface.php b/vendor/twig/twig/lib/Twig/TestInterface.php
new file mode 100644
index 00000000..30d8a2c4
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TestInterface.php
@@ -0,0 +1,26 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Represents a template test.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @deprecated since 1.12 (to be removed in 2.0)
17 */
18interface Twig_TestInterface
19{
20 /**
21 * Compiles a test.
22 *
23 * @return string The PHP code for the test
24 */
25 public function compile();
26}
diff --git a/vendor/twig/twig/lib/Twig/Token.php b/vendor/twig/twig/lib/Twig/Token.php
new file mode 100644
index 00000000..bbca90db
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/Token.php
@@ -0,0 +1,218 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a Token.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_Token
19{
20 protected $value;
21 protected $type;
22 protected $lineno;
23
24 const EOF_TYPE = -1;
25 const TEXT_TYPE = 0;
26 const BLOCK_START_TYPE = 1;
27 const VAR_START_TYPE = 2;
28 const BLOCK_END_TYPE = 3;
29 const VAR_END_TYPE = 4;
30 const NAME_TYPE = 5;
31 const NUMBER_TYPE = 6;
32 const STRING_TYPE = 7;
33 const OPERATOR_TYPE = 8;
34 const PUNCTUATION_TYPE = 9;
35 const INTERPOLATION_START_TYPE = 10;
36 const INTERPOLATION_END_TYPE = 11;
37
38 /**
39 * Constructor.
40 *
41 * @param integer $type The type of the token
42 * @param string $value The token value
43 * @param integer $lineno The line position in the source
44 */
45 public function __construct($type, $value, $lineno)
46 {
47 $this->type = $type;
48 $this->value = $value;
49 $this->lineno = $lineno;
50 }
51
52 /**
53 * Returns a string representation of the token.
54 *
55 * @return string A string representation of the token
56 */
57 public function __toString()
58 {
59 return sprintf('%s(%s)', self::typeToString($this->type, true, $this->lineno), $this->value);
60 }
61
62 /**
63 * Tests the current token for a type and/or a value.
64 *
65 * Parameters may be:
66 * * just type
67 * * type and value (or array of possible values)
68 * * just value (or array of possible values) (NAME_TYPE is used as type)
69 *
70 * @param array|integer $type The type to test
71 * @param array|string|null $values The token value
72 *
73 * @return Boolean
74 */
75 public function test($type, $values = null)
76 {
77 if (null === $values && !is_int($type)) {
78 $values = $type;
79 $type = self::NAME_TYPE;
80 }
81
82 return ($this->type === $type) && (
83 null === $values ||
84 (is_array($values) && in_array($this->value, $values)) ||
85 $this->value == $values
86 );
87 }
88
89 /**
90 * Gets the line.
91 *
92 * @return integer The source line
93 */
94 public function getLine()
95 {
96 return $this->lineno;
97 }
98
99 /**
100 * Gets the token type.
101 *
102 * @return integer The token type
103 */
104 public function getType()
105 {
106 return $this->type;
107 }
108
109 /**
110 * Gets the token value.
111 *
112 * @return string The token value
113 */
114 public function getValue()
115 {
116 return $this->value;
117 }
118
119 /**
120 * Returns the constant representation (internal) of a given type.
121 *
122 * @param integer $type The type as an integer
123 * @param Boolean $short Whether to return a short representation or not
124 * @param integer $line The code line
125 *
126 * @return string The string representation
127 */
128 public static function typeToString($type, $short = false, $line = -1)
129 {
130 switch ($type) {
131 case self::EOF_TYPE:
132 $name = 'EOF_TYPE';
133 break;
134 case self::TEXT_TYPE:
135 $name = 'TEXT_TYPE';
136 break;
137 case self::BLOCK_START_TYPE:
138 $name = 'BLOCK_START_TYPE';
139 break;
140 case self::VAR_START_TYPE:
141 $name = 'VAR_START_TYPE';
142 break;
143 case self::BLOCK_END_TYPE:
144 $name = 'BLOCK_END_TYPE';
145 break;
146 case self::VAR_END_TYPE:
147 $name = 'VAR_END_TYPE';
148 break;
149 case self::NAME_TYPE:
150 $name = 'NAME_TYPE';
151 break;
152 case self::NUMBER_TYPE:
153 $name = 'NUMBER_TYPE';
154 break;
155 case self::STRING_TYPE:
156 $name = 'STRING_TYPE';
157 break;
158 case self::OPERATOR_TYPE:
159 $name = 'OPERATOR_TYPE';
160 break;
161 case self::PUNCTUATION_TYPE:
162 $name = 'PUNCTUATION_TYPE';
163 break;
164 case self::INTERPOLATION_START_TYPE:
165 $name = 'INTERPOLATION_START_TYPE';
166 break;
167 case self::INTERPOLATION_END_TYPE:
168 $name = 'INTERPOLATION_END_TYPE';
169 break;
170 default:
171 throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
172 }
173
174 return $short ? $name : 'Twig_Token::'.$name;
175 }
176
177 /**
178 * Returns the english representation of a given type.
179 *
180 * @param integer $type The type as an integer
181 * @param integer $line The code line
182 *
183 * @return string The string representation
184 */
185 public static function typeToEnglish($type, $line = -1)
186 {
187 switch ($type) {
188 case self::EOF_TYPE:
189 return 'end of template';
190 case self::TEXT_TYPE:
191 return 'text';
192 case self::BLOCK_START_TYPE:
193 return 'begin of statement block';
194 case self::VAR_START_TYPE:
195 return 'begin of print statement';
196 case self::BLOCK_END_TYPE:
197 return 'end of statement block';
198 case self::VAR_END_TYPE:
199 return 'end of print statement';
200 case self::NAME_TYPE:
201 return 'name';
202 case self::NUMBER_TYPE:
203 return 'number';
204 case self::STRING_TYPE:
205 return 'string';
206 case self::OPERATOR_TYPE:
207 return 'operator';
208 case self::PUNCTUATION_TYPE:
209 return 'punctuation';
210 case self::INTERPOLATION_START_TYPE:
211 return 'begin of string interpolation';
212 case self::INTERPOLATION_END_TYPE:
213 return 'end of string interpolation';
214 default:
215 throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
216 }
217 }
218}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser.php b/vendor/twig/twig/lib/Twig/TokenParser.php
new file mode 100644
index 00000000..decebd5e
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Base class for all token parsers.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17abstract class Twig_TokenParser implements Twig_TokenParserInterface
18{
19 /**
20 * @var Twig_Parser
21 */
22 protected $parser;
23
24 /**
25 * Sets the parser associated with this token parser
26 *
27 * @param $parser A Twig_Parser instance
28 */
29 public function setParser(Twig_Parser $parser)
30 {
31 $this->parser = $parser;
32 }
33}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/AutoEscape.php b/vendor/twig/twig/lib/Twig/TokenParser/AutoEscape.php
new file mode 100644
index 00000000..27560288
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/AutoEscape.php
@@ -0,0 +1,89 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Marks a section of a template to be escaped or not.
14 *
15 * <pre>
16 * {% autoescape true %}
17 * Everything will be automatically escaped in this block
18 * {% endautoescape %}
19 *
20 * {% autoescape false %}
21 * Everything will be outputed as is in this block
22 * {% endautoescape %}
23 *
24 * {% autoescape true js %}
25 * Everything will be automatically escaped in this block
26 * using the js escaping strategy
27 * {% endautoescape %}
28 * </pre>
29 */
30class Twig_TokenParser_AutoEscape extends Twig_TokenParser
31{
32 /**
33 * Parses a token and returns a node.
34 *
35 * @param Twig_Token $token A Twig_Token instance
36 *
37 * @return Twig_NodeInterface A Twig_NodeInterface instance
38 */
39 public function parse(Twig_Token $token)
40 {
41 $lineno = $token->getLine();
42 $stream = $this->parser->getStream();
43
44 if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
45 $value = 'html';
46 } else {
47 $expr = $this->parser->getExpressionParser()->parseExpression();
48 if (!$expr instanceof Twig_Node_Expression_Constant) {
49 throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $stream->getCurrent()->getLine(), $stream->getFilename());
50 }
51 $value = $expr->getAttribute('value');
52
53 $compat = true === $value || false === $value;
54
55 if (true === $value) {
56 $value = 'html';
57 }
58
59 if ($compat && $stream->test(Twig_Token::NAME_TYPE)) {
60 if (false === $value) {
61 throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getFilename());
62 }
63
64 $value = $stream->next()->getValue();
65 }
66 }
67
68 $stream->expect(Twig_Token::BLOCK_END_TYPE);
69 $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
70 $stream->expect(Twig_Token::BLOCK_END_TYPE);
71
72 return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag());
73 }
74
75 public function decideBlockEnd(Twig_Token $token)
76 {
77 return $token->test('endautoescape');
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 'autoescape';
88 }
89}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Block.php b/vendor/twig/twig/lib/Twig/TokenParser/Block.php
new file mode 100644
index 00000000..a2e017f3
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Block.php
@@ -0,0 +1,83 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Marks a section of a template as being reusable.
15 *
16 * <pre>
17 * {% block head %}
18 * <link rel="stylesheet" href="style.css" />
19 * <title>{% block title %}{% endblock %} - My Webpage</title>
20 * {% endblock %}
21 * </pre>
22 */
23class Twig_TokenParser_Block extends Twig_TokenParser
24{
25 /**
26 * Parses a token and returns a node.
27 *
28 * @param Twig_Token $token A Twig_Token instance
29 *
30 * @return Twig_NodeInterface A Twig_NodeInterface instance
31 */
32 public function parse(Twig_Token $token)
33 {
34 $lineno = $token->getLine();
35 $stream = $this->parser->getStream();
36 $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
37 if ($this->parser->hasBlock($name)) {
38 throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename());
39 }
40 $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
41 $this->parser->pushLocalScope();
42 $this->parser->pushBlockStack($name);
43
44 if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
45 $stream->next();
46
47 $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
48 if ($stream->test(Twig_Token::NAME_TYPE)) {
49 $value = $stream->next()->getValue();
50
51 if ($value != $name) {
52 throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
53 }
54 }
55 } else {
56 $body = new Twig_Node(array(
57 new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno),
58 ));
59 }
60 $stream->expect(Twig_Token::BLOCK_END_TYPE);
61
62 $block->setNode('body', $body);
63 $this->parser->popBlockStack();
64 $this->parser->popLocalScope();
65
66 return new Twig_Node_BlockReference($name, $lineno, $this->getTag());
67 }
68
69 public function decideBlockEnd(Twig_Token $token)
70 {
71 return $token->test('endblock');
72 }
73
74 /**
75 * Gets the tag name associated with this token parser.
76 *
77 * @return string The tag name
78 */
79 public function getTag()
80 {
81 return 'block';
82 }
83}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Do.php b/vendor/twig/twig/lib/Twig/TokenParser/Do.php
new file mode 100644
index 00000000..f50939dd
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Do.php
@@ -0,0 +1,42 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Evaluates an expression, discarding the returned value.
14 */
15class Twig_TokenParser_Do extends Twig_TokenParser
16{
17 /**
18 * Parses a token and returns a node.
19 *
20 * @param Twig_Token $token A Twig_Token instance
21 *
22 * @return Twig_NodeInterface A Twig_NodeInterface instance
23 */
24 public function parse(Twig_Token $token)
25 {
26 $expr = $this->parser->getExpressionParser()->parseExpression();
27
28 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
29
30 return new Twig_Node_Do($expr, $token->getLine(), $this->getTag());
31 }
32
33 /**
34 * Gets the tag name associated with this token parser.
35 *
36 * @return string The tag name
37 */
38 public function getTag()
39 {
40 return 'do';
41 }
42}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Embed.php b/vendor/twig/twig/lib/Twig/TokenParser/Embed.php
new file mode 100644
index 00000000..69cb5f35
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Embed.php
@@ -0,0 +1,66 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2012 Fabien Potencier
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 * Embeds a template.
14 */
15class Twig_TokenParser_Embed extends Twig_TokenParser_Include
16{
17 /**
18 * Parses a token and returns a node.
19 *
20 * @param Twig_Token $token A Twig_Token instance
21 *
22 * @return Twig_NodeInterface A Twig_NodeInterface instance
23 */
24 public function parse(Twig_Token $token)
25 {
26 $stream = $this->parser->getStream();
27
28 $parent = $this->parser->getExpressionParser()->parseExpression();
29
30 list($variables, $only, $ignoreMissing) = $this->parseArguments();
31
32 // inject a fake parent to make the parent() function work
33 $stream->injectTokens(array(
34 new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()),
35 new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()),
36 new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()),
37 new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()),
38 ));
39
40 $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true);
41
42 // override the parent with the correct one
43 $module->setNode('parent', $parent);
44
45 $this->parser->embedTemplate($module);
46
47 $stream->expect(Twig_Token::BLOCK_END_TYPE);
48
49 return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
50 }
51
52 public function decideBlockEnd(Twig_Token $token)
53 {
54 return $token->test('endembed');
55 }
56
57 /**
58 * Gets the tag name associated with this token parser.
59 *
60 * @return string The tag name
61 */
62 public function getTag()
63 {
64 return 'embed';
65 }
66}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Extends.php b/vendor/twig/twig/lib/Twig/TokenParser/Extends.php
new file mode 100644
index 00000000..f5ecee21
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Extends.php
@@ -0,0 +1,52 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Extends a template by another one.
15 *
16 * <pre>
17 * {% extends "base.html" %}
18 * </pre>
19 */
20class Twig_TokenParser_Extends extends Twig_TokenParser
21{
22 /**
23 * Parses a token and returns a node.
24 *
25 * @param Twig_Token $token A Twig_Token instance
26 *
27 * @return Twig_NodeInterface A Twig_NodeInterface instance
28 */
29 public function parse(Twig_Token $token)
30 {
31 if (!$this->parser->isMainScope()) {
32 throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine(), $this->parser->getFilename());
33 }
34
35 if (null !== $this->parser->getParent()) {
36 throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine(), $this->parser->getFilename());
37 }
38 $this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
39
40 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
41 }
42
43 /**
44 * Gets the tag name associated with this token parser.
45 *
46 * @return string The tag name
47 */
48 public function getTag()
49 {
50 return 'extends';
51 }
52}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Filter.php b/vendor/twig/twig/lib/Twig/TokenParser/Filter.php
new file mode 100644
index 00000000..2b97475a
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Filter.php
@@ -0,0 +1,61 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Filters a section of a template by applying filters.
14 *
15 * <pre>
16 * {% filter upper %}
17 * This text becomes uppercase
18 * {% endfilter %}
19 * </pre>
20 */
21class Twig_TokenParser_Filter 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 $name = $this->parser->getVarName();
33 $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag());
34
35 $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag());
36 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
37
38 $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
39 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
40
41 $block = new Twig_Node_Block($name, $body, $token->getLine());
42 $this->parser->setBlock($name, $block);
43
44 return new Twig_Node_Print($filter, $token->getLine(), $this->getTag());
45 }
46
47 public function decideBlockEnd(Twig_Token $token)
48 {
49 return $token->test('endfilter');
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 'filter';
60 }
61}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Flush.php b/vendor/twig/twig/lib/Twig/TokenParser/Flush.php
new file mode 100644
index 00000000..4e15e785
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Flush.php
@@ -0,0 +1,42 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Flushes the output to the client.
14 *
15 * @see flush()
16 */
17class Twig_TokenParser_Flush extends Twig_TokenParser
18{
19 /**
20 * Parses a token and returns a node.
21 *
22 * @param Twig_Token $token A Twig_Token instance
23 *
24 * @return Twig_NodeInterface A Twig_NodeInterface instance
25 */
26 public function parse(Twig_Token $token)
27 {
28 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
29
30 return new Twig_Node_Flush($token->getLine(), $this->getTag());
31 }
32
33 /**
34 * Gets the tag name associated with this token parser.
35 *
36 * @return string The tag name
37 */
38 public function getTag()
39 {
40 return 'flush';
41 }
42}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/For.php b/vendor/twig/twig/lib/Twig/TokenParser/For.php
new file mode 100644
index 00000000..98a6d079
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/For.php
@@ -0,0 +1,136 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Loops over each item of a sequence.
15 *
16 * <pre>
17 * <ul>
18 * {% for user in users %}
19 * <li>{{ user.username|e }}</li>
20 * {% endfor %}
21 * </ul>
22 * </pre>
23 */
24class Twig_TokenParser_For extends Twig_TokenParser
25{
26 /**
27 * Parses a token and returns a node.
28 *
29 * @param Twig_Token $token A Twig_Token instance
30 *
31 * @return Twig_NodeInterface A Twig_NodeInterface instance
32 */
33 public function parse(Twig_Token $token)
34 {
35 $lineno = $token->getLine();
36 $stream = $this->parser->getStream();
37 $targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
38 $stream->expect(Twig_Token::OPERATOR_TYPE, 'in');
39 $seq = $this->parser->getExpressionParser()->parseExpression();
40
41 $ifexpr = null;
42 if ($stream->test(Twig_Token::NAME_TYPE, 'if')) {
43 $stream->next();
44 $ifexpr = $this->parser->getExpressionParser()->parseExpression();
45 }
46
47 $stream->expect(Twig_Token::BLOCK_END_TYPE);
48 $body = $this->parser->subparse(array($this, 'decideForFork'));
49 if ($stream->next()->getValue() == 'else') {
50 $stream->expect(Twig_Token::BLOCK_END_TYPE);
51 $else = $this->parser->subparse(array($this, 'decideForEnd'), true);
52 } else {
53 $else = null;
54 }
55 $stream->expect(Twig_Token::BLOCK_END_TYPE);
56
57 if (count($targets) > 1) {
58 $keyTarget = $targets->getNode(0);
59 $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine());
60 $valueTarget = $targets->getNode(1);
61 $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
62 } else {
63 $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno);
64 $valueTarget = $targets->getNode(0);
65 $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
66 }
67
68 if ($ifexpr) {
69 $this->checkLoopUsageCondition($stream, $ifexpr);
70 $this->checkLoopUsageBody($stream, $body);
71 }
72
73 return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag());
74 }
75
76 public function decideForFork(Twig_Token $token)
77 {
78 return $token->test(array('else', 'endfor'));
79 }
80
81 public function decideForEnd(Twig_Token $token)
82 {
83 return $token->test('endfor');
84 }
85
86 // the loop variable cannot be used in the condition
87 protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node)
88 {
89 if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
90 throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename());
91 }
92
93 foreach ($node as $n) {
94 if (!$n) {
95 continue;
96 }
97
98 $this->checkLoopUsageCondition($stream, $n);
99 }
100 }
101
102 // check usage of non-defined loop-items
103 // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include)
104 protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node)
105 {
106 if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
107 $attribute = $node->getNode('attribute');
108 if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) {
109 throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename());
110 }
111 }
112
113 // should check for parent.loop.XXX usage
114 if ($node instanceof Twig_Node_For) {
115 return;
116 }
117
118 foreach ($node as $n) {
119 if (!$n) {
120 continue;
121 }
122
123 $this->checkLoopUsageBody($stream, $n);
124 }
125 }
126
127 /**
128 * Gets the tag name associated with this token parser.
129 *
130 * @return string The tag name
131 */
132 public function getTag()
133 {
134 return 'for';
135 }
136}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/From.php b/vendor/twig/twig/lib/Twig/TokenParser/From.php
new file mode 100644
index 00000000..a54054db
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/From.php
@@ -0,0 +1,74 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Imports macros.
14 *
15 * <pre>
16 * {% from 'forms.html' import forms %}
17 * </pre>
18 */
19class Twig_TokenParser_From extends Twig_TokenParser
20{
21 /**
22 * Parses a token and returns a node.
23 *
24 * @param Twig_Token $token A Twig_Token instance
25 *
26 * @return Twig_NodeInterface A Twig_NodeInterface instance
27 */
28 public function parse(Twig_Token $token)
29 {
30 $macro = $this->parser->getExpressionParser()->parseExpression();
31 $stream = $this->parser->getStream();
32 $stream->expect('import');
33
34 $targets = array();
35 do {
36 $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
37
38 $alias = $name;
39 if ($stream->test('as')) {
40 $stream->next();
41
42 $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
43 }
44
45 $targets[$name] = $alias;
46
47 if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
48 break;
49 }
50
51 $stream->next();
52 } while (true);
53
54 $stream->expect(Twig_Token::BLOCK_END_TYPE);
55
56 $node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag());
57
58 foreach ($targets as $name => $alias) {
59 $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
60 }
61
62 return $node;
63 }
64
65 /**
66 * Gets the tag name associated with this token parser.
67 *
68 * @return string The tag name
69 */
70 public function getTag()
71 {
72 return 'from';
73 }
74}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/If.php b/vendor/twig/twig/lib/Twig/TokenParser/If.php
new file mode 100644
index 00000000..3d7d1f51
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/If.php
@@ -0,0 +1,94 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Tests a condition.
15 *
16 * <pre>
17 * {% if users %}
18 * <ul>
19 * {% for user in users %}
20 * <li>{{ user.username|e }}</li>
21 * {% endfor %}
22 * </ul>
23 * {% endif %}
24 * </pre>
25 */
26class Twig_TokenParser_If extends Twig_TokenParser
27{
28 /**
29 * Parses a token and returns a node.
30 *
31 * @param Twig_Token $token A Twig_Token instance
32 *
33 * @return Twig_NodeInterface A Twig_NodeInterface instance
34 */
35 public function parse(Twig_Token $token)
36 {
37 $lineno = $token->getLine();
38 $expr = $this->parser->getExpressionParser()->parseExpression();
39 $stream = $this->parser->getStream();
40 $stream->expect(Twig_Token::BLOCK_END_TYPE);
41 $body = $this->parser->subparse(array($this, 'decideIfFork'));
42 $tests = array($expr, $body);
43 $else = null;
44
45 $end = false;
46 while (!$end) {
47 switch ($stream->next()->getValue()) {
48 case 'else':
49 $stream->expect(Twig_Token::BLOCK_END_TYPE);
50 $else = $this->parser->subparse(array($this, 'decideIfEnd'));
51 break;
52
53 case 'elseif':
54 $expr = $this->parser->getExpressionParser()->parseExpression();
55 $stream->expect(Twig_Token::BLOCK_END_TYPE);
56 $body = $this->parser->subparse(array($this, 'decideIfFork'));
57 $tests[] = $expr;
58 $tests[] = $body;
59 break;
60
61 case 'endif':
62 $end = true;
63 break;
64
65 default:
66 throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename());
67 }
68 }
69
70 $stream->expect(Twig_Token::BLOCK_END_TYPE);
71
72 return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag());
73 }
74
75 public function decideIfFork(Twig_Token $token)
76 {
77 return $token->test(array('elseif', 'else', 'endif'));
78 }
79
80 public function decideIfEnd(Twig_Token $token)
81 {
82 return $token->test(array('endif'));
83 }
84
85 /**
86 * Gets the tag name associated with this token parser.
87 *
88 * @return string The tag name
89 */
90 public function getTag()
91 {
92 return 'if';
93 }
94}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Import.php b/vendor/twig/twig/lib/Twig/TokenParser/Import.php
new file mode 100644
index 00000000..e7050c70
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Import.php
@@ -0,0 +1,49 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Imports macros.
14 *
15 * <pre>
16 * {% import 'forms.html' as forms %}
17 * </pre>
18 */
19class Twig_TokenParser_Import extends Twig_TokenParser
20{
21 /**
22 * Parses a token and returns a node.
23 *
24 * @param Twig_Token $token A Twig_Token instance
25 *
26 * @return Twig_NodeInterface A Twig_NodeInterface instance
27 */
28 public function parse(Twig_Token $token)
29 {
30 $macro = $this->parser->getExpressionParser()->parseExpression();
31 $this->parser->getStream()->expect('as');
32 $var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine());
33 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
34
35 $this->parser->addImportedSymbol('template', $var->getAttribute('name'));
36
37 return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag());
38 }
39
40 /**
41 * Gets the tag name associated with this token parser.
42 *
43 * @return string The tag name
44 */
45 public function getTag()
46 {
47 return 'import';
48 }
49}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Include.php b/vendor/twig/twig/lib/Twig/TokenParser/Include.php
new file mode 100644
index 00000000..4a317868
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Include.php
@@ -0,0 +1,80 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Includes a template.
15 *
16 * <pre>
17 * {% include 'header.html' %}
18 * Body
19 * {% include 'footer.html' %}
20 * </pre>
21 */
22class Twig_TokenParser_Include extends Twig_TokenParser
23{
24 /**
25 * Parses a token and returns a node.
26 *
27 * @param Twig_Token $token A Twig_Token instance
28 *
29 * @return Twig_NodeInterface A Twig_NodeInterface instance
30 */
31 public function parse(Twig_Token $token)
32 {
33 $expr = $this->parser->getExpressionParser()->parseExpression();
34
35 list($variables, $only, $ignoreMissing) = $this->parseArguments();
36
37 return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
38 }
39
40 protected function parseArguments()
41 {
42 $stream = $this->parser->getStream();
43
44 $ignoreMissing = false;
45 if ($stream->test(Twig_Token::NAME_TYPE, 'ignore')) {
46 $stream->next();
47 $stream->expect(Twig_Token::NAME_TYPE, 'missing');
48
49 $ignoreMissing = true;
50 }
51
52 $variables = null;
53 if ($stream->test(Twig_Token::NAME_TYPE, 'with')) {
54 $stream->next();
55
56 $variables = $this->parser->getExpressionParser()->parseExpression();
57 }
58
59 $only = false;
60 if ($stream->test(Twig_Token::NAME_TYPE, 'only')) {
61 $stream->next();
62
63 $only = true;
64 }
65
66 $stream->expect(Twig_Token::BLOCK_END_TYPE);
67
68 return array($variables, $only, $ignoreMissing);
69 }
70
71 /**
72 * Gets the tag name associated with this token parser.
73 *
74 * @return string The tag name
75 */
76 public function getTag()
77 {
78 return 'include';
79 }
80}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Macro.php b/vendor/twig/twig/lib/Twig/TokenParser/Macro.php
new file mode 100644
index 00000000..82b4fa6d
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Macro.php
@@ -0,0 +1,68 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Defines a macro.
14 *
15 * <pre>
16 * {% macro input(name, value, type, size) %}
17 * <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
18 * {% endmacro %}
19 * </pre>
20 */
21class Twig_TokenParser_Macro 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 $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
35
36 $arguments = $this->parser->getExpressionParser()->parseArguments(true, true);
37
38 $stream->expect(Twig_Token::BLOCK_END_TYPE);
39 $this->parser->pushLocalScope();
40 $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
41 if ($stream->test(Twig_Token::NAME_TYPE)) {
42 $value = $stream->next()->getValue();
43
44 if ($value != $name) {
45 throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
46 }
47 }
48 $this->parser->popLocalScope();
49 $stream->expect(Twig_Token::BLOCK_END_TYPE);
50
51 $this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag()));
52 }
53
54 public function decideBlockEnd(Twig_Token $token)
55 {
56 return $token->test('endmacro');
57 }
58
59 /**
60 * Gets the tag name associated with this token parser.
61 *
62 * @return string The tag name
63 */
64 public function getTag()
65 {
66 return 'macro';
67 }
68}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Sandbox.php b/vendor/twig/twig/lib/Twig/TokenParser/Sandbox.php
new file mode 100644
index 00000000..9457325a
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Sandbox.php
@@ -0,0 +1,68 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Marks a section of a template as untrusted code that must be evaluated in the sandbox mode.
14 *
15 * <pre>
16 * {% sandbox %}
17 * {% include 'user.html' %}
18 * {% endsandbox %}
19 * </pre>
20 *
21 * @see http://www.twig-project.org/doc/api.html#sandbox-extension for details
22 */
23class Twig_TokenParser_Sandbox extends Twig_TokenParser
24{
25 /**
26 * Parses a token and returns a node.
27 *
28 * @param Twig_Token $token A Twig_Token instance
29 *
30 * @return Twig_NodeInterface A Twig_NodeInterface instance
31 */
32 public function parse(Twig_Token $token)
33 {
34 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
35 $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
36 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
37
38 // in a sandbox tag, only include tags are allowed
39 if (!$body instanceof Twig_Node_Include) {
40 foreach ($body as $node) {
41 if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
42 continue;
43 }
44
45 if (!$node instanceof Twig_Node_Include) {
46 throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine(), $this->parser->getFilename());
47 }
48 }
49 }
50
51 return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag());
52 }
53
54 public function decideBlockEnd(Twig_Token $token)
55 {
56 return $token->test('endsandbox');
57 }
58
59 /**
60 * Gets the tag name associated with this token parser.
61 *
62 * @return string The tag name
63 */
64 public function getTag()
65 {
66 return 'sandbox';
67 }
68}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Set.php b/vendor/twig/twig/lib/Twig/TokenParser/Set.php
new file mode 100644
index 00000000..70e0b41b
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Set.php
@@ -0,0 +1,84 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
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 * Defines a variable.
14 *
15 * <pre>
16 * {% set foo = 'foo' %}
17 *
18 * {% set foo = [1, 2] %}
19 *
20 * {% set foo = {'foo': 'bar'} %}
21 *
22 * {% set foo = 'foo' ~ 'bar' %}
23 *
24 * {% set foo, bar = 'foo', 'bar' %}
25 *
26 * {% set foo %}Some content{% endset %}
27 * </pre>
28 */
29class Twig_TokenParser_Set extends Twig_TokenParser
30{
31 /**
32 * Parses a token and returns a node.
33 *
34 * @param Twig_Token $token A Twig_Token instance
35 *
36 * @return Twig_NodeInterface A Twig_NodeInterface instance
37 */
38 public function parse(Twig_Token $token)
39 {
40 $lineno = $token->getLine();
41 $stream = $this->parser->getStream();
42 $names = $this->parser->getExpressionParser()->parseAssignmentExpression();
43
44 $capture = false;
45 if ($stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
46 $stream->next();
47 $values = $this->parser->getExpressionParser()->parseMultitargetExpression();
48
49 $stream->expect(Twig_Token::BLOCK_END_TYPE);
50
51 if (count($names) !== count($values)) {
52 throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignments.", $stream->getCurrent()->getLine(), $stream->getFilename());
53 }
54 } else {
55 $capture = true;
56
57 if (count($names) > 1) {
58 throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $stream->getCurrent()->getLine(), $stream->getFilename());
59 }
60
61 $stream->expect(Twig_Token::BLOCK_END_TYPE);
62
63 $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
64 $stream->expect(Twig_Token::BLOCK_END_TYPE);
65 }
66
67 return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag());
68 }
69
70 public function decideBlockEnd(Twig_Token $token)
71 {
72 return $token->test('endset');
73 }
74
75 /**
76 * Gets the tag name associated with this token parser.
77 *
78 * @return string The tag name
79 */
80 public function getTag()
81 {
82 return 'set';
83 }
84}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Spaceless.php b/vendor/twig/twig/lib/Twig/TokenParser/Spaceless.php
new file mode 100644
index 00000000..1e3fa8f3
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Spaceless.php
@@ -0,0 +1,59 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Remove whitespaces between HTML tags.
14 *
15 * <pre>
16 * {% spaceless %}
17 * <div>
18 * <strong>foo</strong>
19 * </div>
20 * {% endspaceless %}
21 *
22 * {# output will be <div><strong>foo</strong></div> #}
23 * </pre>
24 */
25class Twig_TokenParser_Spaceless extends Twig_TokenParser
26{
27 /**
28 * Parses a token and returns a node.
29 *
30 * @param Twig_Token $token A Twig_Token instance
31 *
32 * @return Twig_NodeInterface A Twig_NodeInterface instance
33 */
34 public function parse(Twig_Token $token)
35 {
36 $lineno = $token->getLine();
37
38 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
39 $body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true);
40 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
41
42 return new Twig_Node_Spaceless($body, $lineno, $this->getTag());
43 }
44
45 public function decideSpacelessEnd(Twig_Token $token)
46 {
47 return $token->test('endspaceless');
48 }
49
50 /**
51 * Gets the tag name associated with this token parser.
52 *
53 * @return string The tag name
54 */
55 public function getTag()
56 {
57 return 'spaceless';
58 }
59}
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Use.php b/vendor/twig/twig/lib/Twig/TokenParser/Use.php
new file mode 100644
index 00000000..bc0e09ef
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParser/Use.php
@@ -0,0 +1,82 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2011 Fabien Potencier
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 * Imports blocks defined in another template into the current template.
14 *
15 * <pre>
16 * {% extends "base.html" %}
17 *
18 * {% use "blocks.html" %}
19 *
20 * {% block title %}{% endblock %}
21 * {% block content %}{% endblock %}
22 * </pre>
23 *
24 * @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details.
25 */
26class Twig_TokenParser_Use extends Twig_TokenParser
27{
28 /**
29 * Parses a token and returns a node.
30 *
31 * @param Twig_Token $token A Twig_Token instance
32 *
33 * @return Twig_NodeInterface A Twig_NodeInterface instance
34 */
35 public function parse(Twig_Token $token)
36 {
37 $template = $this->parser->getExpressionParser()->parseExpression();
38 $stream = $this->parser->getStream();
39
40 if (!$template instanceof Twig_Node_Expression_Constant) {
41 throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename());
42 }
43
44 $targets = array();
45 if ($stream->test('with')) {
46 $stream->next();
47
48 do {
49 $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
50
51 $alias = $name;
52 if ($stream->test('as')) {
53 $stream->next();
54
55 $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
56 }
57
58 $targets[$name] = new Twig_Node_Expression_Constant($alias, -1);
59
60 if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
61 break;
62 }
63
64 $stream->next();
65 } while (true);
66 }
67
68 $stream->expect(Twig_Token::BLOCK_END_TYPE);
69
70 $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets))));
71 }
72
73 /**
74 * Gets the tag name associated with this token parser.
75 *
76 * @return string The tag name
77 */
78 public function getTag()
79 {
80 return 'use';
81 }
82}
diff --git a/vendor/twig/twig/lib/Twig/TokenParserBroker.php b/vendor/twig/twig/lib/Twig/TokenParserBroker.php
new file mode 100644
index 00000000..ec3fba67
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParserBroker.php
@@ -0,0 +1,136 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 * (c) 2010 Arnaud Le Blanc
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Default implementation of a token parser broker.
15 *
16 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
17 * @deprecated since 1.12 (to be removed in 2.0)
18 */
19class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface
20{
21 protected $parser;
22 protected $parsers = array();
23 protected $brokers = array();
24
25 /**
26 * Constructor.
27 *
28 * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances
29 * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances
30 */
31 public function __construct($parsers = array(), $brokers = array())
32 {
33 foreach ($parsers as $parser) {
34 if (!$parser instanceof Twig_TokenParserInterface) {
35 throw new LogicException('$parsers must a an array of Twig_TokenParserInterface');
36 }
37 $this->parsers[$parser->getTag()] = $parser;
38 }
39 foreach ($brokers as $broker) {
40 if (!$broker instanceof Twig_TokenParserBrokerInterface) {
41 throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface');
42 }
43 $this->brokers[] = $broker;
44 }
45 }
46
47 /**
48 * Adds a TokenParser.
49 *
50 * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
51 */
52 public function addTokenParser(Twig_TokenParserInterface $parser)
53 {
54 $this->parsers[$parser->getTag()] = $parser;
55 }
56
57 /**
58 * Removes a TokenParser.
59 *
60 * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
61 */
62 public function removeTokenParser(Twig_TokenParserInterface $parser)
63 {
64 $name = $parser->getTag();
65 if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) {
66 unset($this->parsers[$name]);
67 }
68 }
69
70 /**
71 * Adds a TokenParserBroker.
72 *
73 * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
74 */
75 public function addTokenParserBroker(Twig_TokenParserBroker $broker)
76 {
77 $this->brokers[] = $broker;
78 }
79
80 /**
81 * Removes a TokenParserBroker.
82 *
83 * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
84 */
85 public function removeTokenParserBroker(Twig_TokenParserBroker $broker)
86 {
87 if (false !== $pos = array_search($broker, $this->brokers)) {
88 unset($this->brokers[$pos]);
89 }
90 }
91
92 /**
93 * Gets a suitable TokenParser for a tag.
94 *
95 * First looks in parsers, then in brokers.
96 *
97 * @param string $tag A tag name
98 *
99 * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
100 */
101 public function getTokenParser($tag)
102 {
103 if (isset($this->parsers[$tag])) {
104 return $this->parsers[$tag];
105 }
106 $broker = end($this->brokers);
107 while (false !== $broker) {
108 $parser = $broker->getTokenParser($tag);
109 if (null !== $parser) {
110 return $parser;
111 }
112 $broker = prev($this->brokers);
113 }
114 }
115
116 public function getParsers()
117 {
118 return $this->parsers;
119 }
120
121 public function getParser()
122 {
123 return $this->parser;
124 }
125
126 public function setParser(Twig_ParserInterface $parser)
127 {
128 $this->parser = $parser;
129 foreach ($this->parsers as $tokenParser) {
130 $tokenParser->setParser($parser);
131 }
132 foreach ($this->brokers as $broker) {
133 $broker->setParser($parser);
134 }
135 }
136}
diff --git a/vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php b/vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php
new file mode 100644
index 00000000..3f006e33
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
7 * (c) 2010 Arnaud Le Blanc
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Interface implemented by token parser brokers.
15 *
16 * Token parser brokers allows to implement custom logic in the process of resolving a token parser for a given tag name.
17 *
18 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19 * @deprecated since 1.12 (to be removed in 2.0)
20 */
21interface Twig_TokenParserBrokerInterface
22{
23 /**
24 * Gets a TokenParser suitable for a tag.
25 *
26 * @param string $tag A tag name
27 *
28 * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
29 */
30 public function getTokenParser($tag);
31
32 /**
33 * Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of.
34 *
35 * @param Twig_ParserInterface $parser A Twig_ParserInterface interface
36 */
37 public function setParser(Twig_ParserInterface $parser);
38
39 /**
40 * Gets the Twig_ParserInterface.
41 *
42 * @return null|Twig_ParserInterface A Twig_ParserInterface instance or null
43 */
44 public function getParser();
45}
diff --git a/vendor/twig/twig/lib/Twig/TokenParserInterface.php b/vendor/twig/twig/lib/Twig/TokenParserInterface.php
new file mode 100644
index 00000000..bbde7714
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenParserInterface.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 Fabien Potencier
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 * Interface implemented by token parsers.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17interface Twig_TokenParserInterface
18{
19 /**
20 * Sets the parser associated with this token parser
21 *
22 * @param $parser A Twig_Parser instance
23 */
24 public function setParser(Twig_Parser $parser);
25
26 /**
27 * Parses a token and returns a node.
28 *
29 * @param Twig_Token $token A Twig_Token instance
30 *
31 * @return Twig_NodeInterface A Twig_NodeInterface instance
32 */
33 public function parse(Twig_Token $token);
34
35 /**
36 * Gets the tag name associated with this token parser.
37 *
38 * @return string The tag name
39 */
40 public function getTag();
41}
diff --git a/vendor/twig/twig/lib/Twig/TokenStream.php b/vendor/twig/twig/lib/Twig/TokenStream.php
new file mode 100644
index 00000000..a78189f6
--- /dev/null
+++ b/vendor/twig/twig/lib/Twig/TokenStream.php
@@ -0,0 +1,144 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 * (c) 2009 Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Represents a token stream.
15 *
16 * @author Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_TokenStream
19{
20 protected $tokens;
21 protected $current;
22 protected $filename;
23
24 /**
25 * Constructor.
26 *
27 * @param array $tokens An array of tokens
28 * @param string $filename The name of the filename which tokens are associated with
29 */
30 public function __construct(array $tokens, $filename = null)
31 {
32 $this->tokens = $tokens;
33 $this->current = 0;
34 $this->filename = $filename;
35 }
36
37 /**
38 * Returns a string representation of the token stream.
39 *
40 * @return string
41 */
42 public function __toString()
43 {
44 return implode("\n", $this->tokens);
45 }
46
47 public function injectTokens(array $tokens)
48 {
49 $this->tokens = array_merge(array_slice($this->tokens, 0, $this->current), $tokens, array_slice($this->tokens, $this->current));
50 }
51
52 /**
53 * Sets the pointer to the next token and returns the old one.
54 *
55 * @return Twig_Token
56 */
57 public function next()
58 {
59 if (!isset($this->tokens[++$this->current])) {
60 throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current - 1]->getLine(), $this->filename);
61 }
62
63 return $this->tokens[$this->current - 1];
64 }
65
66 /**
67 * Tests a token and returns it or throws a syntax error.
68 *
69 * @return Twig_Token
70 */
71 public function expect($type, $value = null, $message = null)
72 {
73 $token = $this->tokens[$this->current];
74 if (!$token->test($type, $value)) {
75 $line = $token->getLine();
76 throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)',
77 $message ? $message.'. ' : '',
78 Twig_Token::typeToEnglish($token->getType(), $line), $token->getValue(),
79 Twig_Token::typeToEnglish($type, $line), $value ? sprintf(' with value "%s"', $value) : ''),
80 $line,
81 $this->filename
82 );
83 }
84 $this->next();
85
86 return $token;
87 }
88
89 /**
90 * Looks at the next token.
91 *
92 * @param integer $number
93 *
94 * @return Twig_Token
95 */
96 public function look($number = 1)
97 {
98 if (!isset($this->tokens[$this->current + $number])) {
99 throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename);
100 }
101
102 return $this->tokens[$this->current + $number];
103 }
104
105 /**
106 * Tests the current token
107 *
108 * @return bool
109 */
110 public function test($primary, $secondary = null)
111 {
112 return $this->tokens[$this->current]->test($primary, $secondary);
113 }
114
115 /**
116 * Checks if end of stream was reached
117 *
118 * @return bool
119 */
120 public function isEOF()
121 {
122 return $this->tokens[$this->current]->getType() === Twig_Token::EOF_TYPE;
123 }
124
125 /**
126 * Gets the current token
127 *
128 * @return Twig_Token
129 */
130 public function getCurrent()
131 {
132 return $this->tokens[$this->current];
133 }
134
135 /**
136 * Gets the filename associated with this stream
137 *
138 * @return string
139 */
140 public function getFilename()
141 {
142 return $this->filename;
143 }
144}
diff --git a/vendor/twig/twig/phpunit.xml.dist b/vendor/twig/twig/phpunit.xml.dist
new file mode 100644
index 00000000..6c5046f1
--- /dev/null
+++ b/vendor/twig/twig/phpunit.xml.dist
@@ -0,0 +1,25 @@
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="test/bootstrap.php"
13>
14 <testsuites>
15 <testsuite name="Twig Test Suite">
16 <directory>./test/Twig/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory suffix=".php">./lib/Twig/</directory>
23 </whitelist>
24 </filter>
25</phpunit>
diff --git a/vendor/twig/twig/test/Twig/Tests/AutoloaderTest.php b/vendor/twig/twig/test/Twig/Tests/AutoloaderTest.php
new file mode 100644
index 00000000..c8b7999a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/AutoloaderTest.php
@@ -0,0 +1,21 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_AutoloaderTest extends PHPUnit_Framework_TestCase
13{
14 public function testAutoload()
15 {
16 $this->assertFalse(class_exists('FooBarFoo'), '->autoload() does not try to load classes that does not begin with Twig');
17
18 $autoloader = new Twig_Autoloader();
19 $this->assertNull($autoloader->autoload('Foo'), '->autoload() returns false if it is not able to load a class');
20 }
21}
diff --git a/vendor/twig/twig/test/Twig/Tests/CompilerTest.php b/vendor/twig/twig/test/Twig/Tests/CompilerTest.php
new file mode 100644
index 00000000..ebe79aef
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/CompilerTest.php
@@ -0,0 +1,33 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_CompilerTest extends PHPUnit_Framework_TestCase
13{
14 public function testReprNumericValueWithLocale()
15 {
16 $compiler = new Twig_Compiler(new Twig_Environment());
17
18 $locale = setlocale(LC_NUMERIC, 0);
19 if (false === $locale) {
20 $this->markTestSkipped('Your platform does not support locales.');
21 }
22
23 $required_locales = array('fr_FR.UTF-8', 'fr_FR.UTF8', 'fr_FR.utf-8', 'fr_FR.utf8', 'French_France.1252');
24 if (false === setlocale(LC_ALL, $required_locales)) {
25 $this->markTestSkipped('Could not set any of required locales: ' . implode(", ", $required_locales));
26 }
27
28 $this->assertEquals('1.2', $compiler->repr(1.2)->getSource());
29 $this->assertContains('fr', strtolower(setlocale(LC_NUMERIC, 0)));
30
31 setlocale(LC_ALL, $locale);
32 }
33}
diff --git a/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php b/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php
new file mode 100644
index 00000000..22461b5d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php
@@ -0,0 +1,288 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
13{
14 /**
15 * @expectedException LogicException
16 * @expectedExceptionMessage You must set a loader first.
17 */
18 public function testRenderNoLoader()
19 {
20 $env = new Twig_Environment();
21 $env->render('test');
22 }
23
24 public function testAutoescapeOption()
25 {
26 $loader = new Twig_Loader_Array(array(
27 'html' => '{{ foo }} {{ foo }}',
28 'js' => '{{ bar }} {{ bar }}',
29 ));
30
31 $twig = new Twig_Environment($loader, array(
32 'debug' => true,
33 'cache' => false,
34 'autoescape' => array($this, 'escapingStrategyCallback'),
35 ));
36
37 $this->assertEquals('foo&lt;br/ &gt; foo&lt;br/ &gt;', $twig->render('html', array('foo' => 'foo<br/ >')));
38 $this->assertEquals('foo\x3Cbr\x2F\x20\x3E foo\x3Cbr\x2F\x20\x3E', $twig->render('js', array('bar' => 'foo<br/ >')));
39 }
40
41 public function escapingStrategyCallback($filename)
42 {
43 return $filename;
44 }
45
46 public function testGlobals()
47 {
48 // globals can be added after calling getGlobals
49 $twig = new Twig_Environment(new Twig_Loader_String());
50 $twig->addGlobal('foo', 'foo');
51 $globals = $twig->getGlobals();
52 $twig->addGlobal('foo', 'bar');
53 $globals = $twig->getGlobals();
54 $this->assertEquals('bar', $globals['foo']);
55
56 // globals can be modified after runtime init
57 $twig = new Twig_Environment(new Twig_Loader_String());
58 $twig->addGlobal('foo', 'foo');
59 $globals = $twig->getGlobals();
60 $twig->initRuntime();
61 $twig->addGlobal('foo', 'bar');
62 $globals = $twig->getGlobals();
63 $this->assertEquals('bar', $globals['foo']);
64
65 // globals can be modified after extensions init
66 $twig = new Twig_Environment(new Twig_Loader_String());
67 $twig->addGlobal('foo', 'foo');
68 $globals = $twig->getGlobals();
69 $twig->getFunctions();
70 $twig->addGlobal('foo', 'bar');
71 $globals = $twig->getGlobals();
72 $this->assertEquals('bar', $globals['foo']);
73
74 // globals can be modified after extensions and runtime init
75 $twig = new Twig_Environment(new Twig_Loader_String());
76 $twig->addGlobal('foo', 'foo');
77 $globals = $twig->getGlobals();
78 $twig->getFunctions();
79 $twig->initRuntime();
80 $twig->addGlobal('foo', 'bar');
81 $globals = $twig->getGlobals();
82 $this->assertEquals('bar', $globals['foo']);
83
84 $twig = new Twig_Environment(new Twig_Loader_String());
85 $twig->getGlobals();
86 $twig->addGlobal('foo', 'bar');
87 $template = $twig->loadTemplate('{{foo}}');
88 $this->assertEquals('bar', $template->render(array()));
89
90 /* to be uncomment in Twig 2.0
91 // globals cannot be added after runtime init
92 $twig = new Twig_Environment(new Twig_Loader_String());
93 $twig->addGlobal('foo', 'foo');
94 $globals = $twig->getGlobals();
95 $twig->initRuntime();
96 try {
97 $twig->addGlobal('bar', 'bar');
98 $this->fail();
99 } catch (LogicException $e) {
100 $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
101 }
102
103 // globals cannot be added after extensions init
104 $twig = new Twig_Environment(new Twig_Loader_String());
105 $twig->addGlobal('foo', 'foo');
106 $globals = $twig->getGlobals();
107 $twig->getFunctions();
108 try {
109 $twig->addGlobal('bar', 'bar');
110 $this->fail();
111 } catch (LogicException $e) {
112 $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
113 }
114
115 // globals cannot be added after extensions and runtime init
116 $twig = new Twig_Environment(new Twig_Loader_String());
117 $twig->addGlobal('foo', 'foo');
118 $globals = $twig->getGlobals();
119 $twig->getFunctions();
120 $twig->initRuntime();
121 try {
122 $twig->addGlobal('bar', 'bar');
123 $this->fail();
124 } catch (LogicException $e) {
125 $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
126 }
127
128 // test adding globals after initRuntime without call to getGlobals
129 $twig = new Twig_Environment(new Twig_Loader_String());
130 $twig->initRuntime();
131 try {
132 $twig->addGlobal('bar', 'bar');
133 $this->fail();
134 } catch (LogicException $e) {
135 $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
136 }
137 */
138 }
139
140 public function testExtensionsAreNotInitializedWhenRenderingACompiledTemplate()
141 {
142 $options = array('cache' => sys_get_temp_dir().'/twig', 'auto_reload' => false, 'debug' => false);
143
144 // force compilation
145 $twig = new Twig_Environment(new Twig_Loader_String(), $options);
146 $cache = $twig->getCacheFilename('{{ foo }}');
147 if (!is_dir(dirname($cache))) {
148 mkdir(dirname($cache), 0777, true);
149 }
150 file_put_contents($cache, $twig->compileSource('{{ foo }}', '{{ foo }}'));
151
152 // check that extensions won't be initialized when rendering a template that is already in the cache
153 $twig = $this
154 ->getMockBuilder('Twig_Environment')
155 ->setConstructorArgs(array(new Twig_Loader_String(), $options))
156 ->setMethods(array('initExtensions'))
157 ->getMock()
158 ;
159
160 $twig->expects($this->never())->method('initExtensions');
161
162 // render template
163 $output = $twig->render('{{ foo }}', array('foo' => 'bar'));
164 $this->assertEquals('bar', $output);
165
166 unlink($cache);
167 }
168
169 public function testAddExtension()
170 {
171 $twig = new Twig_Environment(new Twig_Loader_String());
172 $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
173
174 $this->assertArrayHasKey('test', $twig->getTags());
175 $this->assertArrayHasKey('foo_filter', $twig->getFilters());
176 $this->assertArrayHasKey('foo_function', $twig->getFunctions());
177 $this->assertArrayHasKey('foo_test', $twig->getTests());
178 $this->assertArrayHasKey('foo_unary', $twig->getUnaryOperators());
179 $this->assertArrayHasKey('foo_binary', $twig->getBinaryOperators());
180 $this->assertArrayHasKey('foo_global', $twig->getGlobals());
181 $visitors = $twig->getNodeVisitors();
182 $this->assertEquals('Twig_Tests_EnvironmentTest_NodeVisitor', get_class($visitors[2]));
183 }
184
185 public function testRemoveExtension()
186 {
187 $twig = new Twig_Environment(new Twig_Loader_String());
188 $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
189 $twig->removeExtension('environment_test');
190
191 $this->assertFalse(array_key_exists('test', $twig->getTags()));
192 $this->assertFalse(array_key_exists('foo_filter', $twig->getFilters()));
193 $this->assertFalse(array_key_exists('foo_function', $twig->getFunctions()));
194 $this->assertFalse(array_key_exists('foo_test', $twig->getTests()));
195 $this->assertFalse(array_key_exists('foo_unary', $twig->getUnaryOperators()));
196 $this->assertFalse(array_key_exists('foo_binary', $twig->getBinaryOperators()));
197 $this->assertFalse(array_key_exists('foo_global', $twig->getGlobals()));
198 $this->assertCount(2, $twig->getNodeVisitors());
199 }
200}
201
202class Twig_Tests_EnvironmentTest_Extension extends Twig_Extension
203{
204 public function getTokenParsers()
205 {
206 return array(
207 new Twig_Tests_EnvironmentTest_TokenParser(),
208 );
209 }
210
211 public function getNodeVisitors()
212 {
213 return array(
214 new Twig_Tests_EnvironmentTest_NodeVisitor(),
215 );
216 }
217
218 public function getFilters()
219 {
220 return array(
221 'foo_filter' => new Twig_Filter_Function('foo_filter'),
222 );
223 }
224
225 public function getTests()
226 {
227 return array(
228 'foo_test' => new Twig_Test_Function('foo_test'),
229 );
230 }
231
232 public function getFunctions()
233 {
234 return array(
235 'foo_function' => new Twig_Function_Function('foo_function'),
236 );
237 }
238
239 public function getOperators()
240 {
241 return array(
242 array('foo_unary' => array()),
243 array('foo_binary' => array()),
244 );
245 }
246
247 public function getGlobals()
248 {
249 return array(
250 'foo_global' => 'foo_global',
251 );
252 }
253
254 public function getName()
255 {
256 return 'environment_test';
257 }
258}
259
260class Twig_Tests_EnvironmentTest_TokenParser extends Twig_TokenParser
261{
262 public function parse(Twig_Token $token)
263 {
264 }
265
266 public function getTag()
267 {
268 return 'test';
269 }
270}
271
272class Twig_Tests_EnvironmentTest_NodeVisitor implements Twig_NodeVisitorInterface
273{
274 public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
275 {
276 return $node;
277 }
278
279 public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
280 {
281 return $node;
282 }
283
284 public function getPriority()
285 {
286 return 0;
287 }
288}
diff --git a/vendor/twig/twig/test/Twig/Tests/ErrorTest.php b/vendor/twig/twig/test/Twig/Tests/ErrorTest.php
new file mode 100644
index 00000000..9b286974
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/ErrorTest.php
@@ -0,0 +1,159 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_ErrorTest extends PHPUnit_Framework_TestCase
13{
14 public function testErrorWithObjectFilename()
15 {
16 $error = new Twig_Error('foo');
17 $error->setTemplateFile(new SplFileInfo(__FILE__));
18
19 $this->assertContains('test'.DIRECTORY_SEPARATOR.'Twig'.DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR.'ErrorTest.php', $error->getMessage());
20 }
21
22 public function testErrorWithArrayFilename()
23 {
24 $error = new Twig_Error('foo');
25 $error->setTemplateFile(array('foo' => 'bar'));
26
27 $this->assertEquals('foo in {"foo":"bar"}', $error->getMessage());
28 }
29
30 public function testTwigExceptionAddsFileAndLineWhenMissing()
31 {
32 $loader = new Twig_Loader_Array(array('index' => "\n\n{{ foo.bar }}\n\n\n{{ 'foo' }}"));
33 $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
34
35 $template = $twig->loadTemplate('index');
36
37 try {
38 $template->render(array());
39
40 $this->fail();
41 } catch (Twig_Error_Runtime $e) {
42 $this->assertEquals('Variable "foo" does not exist in "index" at line 3', $e->getMessage());
43 $this->assertEquals(3, $e->getTemplateLine());
44 $this->assertEquals('index', $e->getTemplateFile());
45 }
46 }
47
48 public function testRenderWrapsExceptions()
49 {
50 $loader = new Twig_Loader_Array(array('index' => "\n\n\n{{ foo.bar }}\n\n\n\n{{ 'foo' }}"));
51 $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
52
53 $template = $twig->loadTemplate('index');
54
55 try {
56 $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo()));
57
58 $this->fail();
59 } catch (Twig_Error_Runtime $e) {
60 $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index" at line 4.', $e->getMessage());
61 $this->assertEquals(4, $e->getTemplateLine());
62 $this->assertEquals('index', $e->getTemplateFile());
63 }
64 }
65
66 public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritance()
67 {
68 $loader = new Twig_Loader_Array(array(
69 'index' => "{% extends 'base' %}
70 {% block content %}
71 {{ foo.bar }}
72 {% endblock %}
73 {% block foo %}
74 {{ foo.bar }}
75 {% endblock %}",
76 'base' => '{% block content %}{% endblock %}'
77 ));
78 $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
79
80 $template = $twig->loadTemplate('index');
81 try {
82 $template->render(array());
83
84 $this->fail();
85 } catch (Twig_Error_Runtime $e) {
86 $this->assertEquals('Variable "foo" does not exist in "index" at line 3', $e->getMessage());
87 $this->assertEquals(3, $e->getTemplateLine());
88 $this->assertEquals('index', $e->getTemplateFile());
89 }
90
91 try {
92 $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo()));
93
94 $this->fail();
95 } catch (Twig_Error_Runtime $e) {
96 $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index" at line 3.', $e->getMessage());
97 $this->assertEquals(3, $e->getTemplateLine());
98 $this->assertEquals('index', $e->getTemplateFile());
99 }
100 }
101
102 public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritanceAgain()
103 {
104 $loader = new Twig_Loader_Array(array(
105 'index' => "{% extends 'base' %}
106 {% block content %}
107 {{ parent() }}
108 {% endblock %}",
109 'base' => '{% block content %}{{ foo }}{% endblock %}'
110 ));
111 $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
112
113 $template = $twig->loadTemplate('index');
114 try {
115 $template->render(array());
116
117 $this->fail();
118 } catch (Twig_Error_Runtime $e) {
119 $this->assertEquals('Variable "foo" does not exist in "base" at line 1', $e->getMessage());
120 $this->assertEquals(1, $e->getTemplateLine());
121 $this->assertEquals('base', $e->getTemplateFile());
122 }
123 }
124
125 public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritanceOnDisk()
126 {
127 $loader = new Twig_Loader_Filesystem(dirname(__FILE__).'/Fixtures/errors');
128 $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
129
130 $template = $twig->loadTemplate('index.html');
131 try {
132 $template->render(array());
133
134 $this->fail();
135 } catch (Twig_Error_Runtime $e) {
136 $this->assertEquals('Variable "foo" does not exist in "index.html" at line 3', $e->getMessage());
137 $this->assertEquals(3, $e->getTemplateLine());
138 $this->assertEquals('index.html', $e->getTemplateFile());
139 }
140
141 try {
142 $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo()));
143
144 $this->fail();
145 } catch (Twig_Error_Runtime $e) {
146 $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index.html" at line 3.', $e->getMessage());
147 $this->assertEquals(3, $e->getTemplateLine());
148 $this->assertEquals('index.html', $e->getTemplateFile());
149 }
150 }
151}
152
153class Twig_Tests_ErrorTest_Foo
154{
155 public function bar()
156 {
157 throw new Exception('Runtime error...');
158 }
159}
diff --git a/vendor/twig/twig/test/Twig/Tests/ExpressionParserTest.php b/vendor/twig/twig/test/Twig/Tests/ExpressionParserTest.php
new file mode 100644
index 00000000..8ec6537a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/ExpressionParserTest.php
@@ -0,0 +1,332 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
13{
14 /**
15 * @expectedException Twig_Error_Syntax
16 * @dataProvider getFailingTestsForAssignment
17 */
18 public function testCanOnlyAssignToNames($template)
19 {
20 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
21 $parser = new Twig_Parser($env);
22
23 $parser->parse($env->tokenize($template, 'index'));
24 }
25
26 public function getFailingTestsForAssignment()
27 {
28 return array(
29 array('{% set false = "foo" %}'),
30 array('{% set true = "foo" %}'),
31 array('{% set none = "foo" %}'),
32 array('{% set 3 = "foo" %}'),
33 array('{% set 1 + 2 = "foo" %}'),
34 array('{% set "bar" = "foo" %}'),
35 array('{% set %}{% endset %}')
36 );
37 }
38
39 /**
40 * @dataProvider getTestsForArray
41 */
42 public function testArrayExpression($template, $expected)
43 {
44 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
45 $stream = $env->tokenize($template, 'index');
46 $parser = new Twig_Parser($env);
47
48 $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr'));
49 }
50
51 /**
52 * @expectedException Twig_Error_Syntax
53 * @dataProvider getFailingTestsForArray
54 */
55 public function testArraySyntaxError($template)
56 {
57 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
58 $parser = new Twig_Parser($env);
59
60 $parser->parse($env->tokenize($template, 'index'));
61 }
62
63 public function getFailingTestsForArray()
64 {
65 return array(
66 array('{{ [1, "a": "b"] }}'),
67 array('{{ {"a": "b", 2} }}'),
68 );
69 }
70
71 public function getTestsForArray()
72 {
73 return array(
74 // simple array
75 array('{{ [1, 2] }}', new Twig_Node_Expression_Array(array(
76 new Twig_Node_Expression_Constant(0, 1),
77 new Twig_Node_Expression_Constant(1, 1),
78
79 new Twig_Node_Expression_Constant(1, 1),
80 new Twig_Node_Expression_Constant(2, 1),
81 ), 1),
82 ),
83
84 // array with trailing ,
85 array('{{ [1, 2, ] }}', new Twig_Node_Expression_Array(array(
86 new Twig_Node_Expression_Constant(0, 1),
87 new Twig_Node_Expression_Constant(1, 1),
88
89 new Twig_Node_Expression_Constant(1, 1),
90 new Twig_Node_Expression_Constant(2, 1),
91 ), 1),
92 ),
93
94 // simple hash
95 array('{{ {"a": "b", "b": "c"} }}', new Twig_Node_Expression_Array(array(
96 new Twig_Node_Expression_Constant('a', 1),
97 new Twig_Node_Expression_Constant('b', 1),
98
99 new Twig_Node_Expression_Constant('b', 1),
100 new Twig_Node_Expression_Constant('c', 1),
101 ), 1),
102 ),
103
104 // hash with trailing ,
105 array('{{ {"a": "b", "b": "c", } }}', new Twig_Node_Expression_Array(array(
106 new Twig_Node_Expression_Constant('a', 1),
107 new Twig_Node_Expression_Constant('b', 1),
108
109 new Twig_Node_Expression_Constant('b', 1),
110 new Twig_Node_Expression_Constant('c', 1),
111 ), 1),
112 ),
113
114 // hash in an array
115 array('{{ [1, {"a": "b", "b": "c"}] }}', new Twig_Node_Expression_Array(array(
116 new Twig_Node_Expression_Constant(0, 1),
117 new Twig_Node_Expression_Constant(1, 1),
118
119 new Twig_Node_Expression_Constant(1, 1),
120 new Twig_Node_Expression_Array(array(
121 new Twig_Node_Expression_Constant('a', 1),
122 new Twig_Node_Expression_Constant('b', 1),
123
124 new Twig_Node_Expression_Constant('b', 1),
125 new Twig_Node_Expression_Constant('c', 1),
126 ), 1),
127 ), 1),
128 ),
129
130 // array in a hash
131 array('{{ {"a": [1, 2], "b": "c"} }}', new Twig_Node_Expression_Array(array(
132 new Twig_Node_Expression_Constant('a', 1),
133 new Twig_Node_Expression_Array(array(
134 new Twig_Node_Expression_Constant(0, 1),
135 new Twig_Node_Expression_Constant(1, 1),
136
137 new Twig_Node_Expression_Constant(1, 1),
138 new Twig_Node_Expression_Constant(2, 1),
139 ), 1),
140 new Twig_Node_Expression_Constant('b', 1),
141 new Twig_Node_Expression_Constant('c', 1),
142 ), 1),
143 ),
144 );
145 }
146
147 /**
148 * @expectedException Twig_Error_Syntax
149 */
150 public function testStringExpressionDoesNotConcatenateTwoConsecutiveStrings()
151 {
152 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
153 $stream = $env->tokenize('{{ "a" "b" }}', 'index');
154 $parser = new Twig_Parser($env);
155
156 $parser->parse($stream);
157 }
158
159 /**
160 * @dataProvider getTestsForString
161 */
162 public function testStringExpression($template, $expected)
163 {
164 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
165 $stream = $env->tokenize($template, 'index');
166 $parser = new Twig_Parser($env);
167
168 $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr'));
169 }
170
171 public function getTestsForString()
172 {
173 return array(
174 array(
175 '{{ "foo" }}', new Twig_Node_Expression_Constant('foo', 1),
176 ),
177 array(
178 '{{ "foo #{bar}" }}', new Twig_Node_Expression_Binary_Concat(
179 new Twig_Node_Expression_Constant('foo ', 1),
180 new Twig_Node_Expression_Name('bar', 1),
181 1
182 ),
183 ),
184 array(
185 '{{ "foo #{bar} baz" }}', new Twig_Node_Expression_Binary_Concat(
186 new Twig_Node_Expression_Binary_Concat(
187 new Twig_Node_Expression_Constant('foo ', 1),
188 new Twig_Node_Expression_Name('bar', 1),
189 1
190 ),
191 new Twig_Node_Expression_Constant(' baz', 1),
192 1
193 )
194 ),
195
196 array(
197 '{{ "foo #{"foo #{bar} baz"} baz" }}', new Twig_Node_Expression_Binary_Concat(
198 new Twig_Node_Expression_Binary_Concat(
199 new Twig_Node_Expression_Constant('foo ', 1),
200 new Twig_Node_Expression_Binary_Concat(
201 new Twig_Node_Expression_Binary_Concat(
202 new Twig_Node_Expression_Constant('foo ', 1),
203 new Twig_Node_Expression_Name('bar', 1),
204 1
205 ),
206 new Twig_Node_Expression_Constant(' baz', 1),
207 1
208 ),
209 1
210 ),
211 new Twig_Node_Expression_Constant(' baz', 1),
212 1
213 ),
214 ),
215 );
216 }
217
218 /**
219 * @expectedException Twig_Error_Syntax
220 */
221 public function testAttributeCallDoesNotSupportNamedArguments()
222 {
223 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
224 $parser = new Twig_Parser($env);
225
226 $parser->parse($env->tokenize('{{ foo.bar(name="Foo") }}', 'index'));
227 }
228
229 /**
230 * @expectedException Twig_Error_Syntax
231 */
232 public function testMacroCallDoesNotSupportNamedArguments()
233 {
234 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
235 $parser = new Twig_Parser($env);
236
237 $parser->parse($env->tokenize('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index'));
238 }
239
240 /**
241 * @expectedException Twig_Error_Syntax
242 * @expectedExceptionMessage An argument must be a name. Unexpected token "string" of value "a" ("name" expected) in "index" at line 1
243 */
244 public function testMacroDefinitionDoesNotSupportNonNameVariableName()
245 {
246 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
247 $parser = new Twig_Parser($env);
248
249 $parser->parse($env->tokenize('{% macro foo("a") %}{% endmacro %}', 'index'));
250 }
251
252 /**
253 * @expectedException Twig_Error_Syntax
254 * @expectedExceptionMessage A default value for an argument must be a constant (a boolean, a string, a number, or an array) in "index" at line 1
255 * @dataProvider getMacroDefinitionDoesNotSupportNonConstantDefaultValues
256 */
257 public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template)
258 {
259 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
260 $parser = new Twig_Parser($env);
261
262 $parser->parse($env->tokenize($template, 'index'));
263 }
264
265 public function getMacroDefinitionDoesNotSupportNonConstantDefaultValues()
266 {
267 return array(
268 array('{% macro foo(name = "a #{foo} a") %}{% endmacro %}'),
269 array('{% macro foo(name = [["b", "a #{foo} a"]]) %}{% endmacro %}'),
270 );
271 }
272
273 /**
274 * @dataProvider getMacroDefinitionSupportsConstantDefaultValues
275 */
276 public function testMacroDefinitionSupportsConstantDefaultValues($template)
277 {
278 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
279 $parser = new Twig_Parser($env);
280
281 $parser->parse($env->tokenize($template, 'index'));
282 }
283
284 public function getMacroDefinitionSupportsConstantDefaultValues()
285 {
286 return array(
287 array('{% macro foo(name = "aa") %}{% endmacro %}'),
288 array('{% macro foo(name = 12) %}{% endmacro %}'),
289 array('{% macro foo(name = true) %}{% endmacro %}'),
290 array('{% macro foo(name = ["a"]) %}{% endmacro %}'),
291 array('{% macro foo(name = [["a"]]) %}{% endmacro %}'),
292 array('{% macro foo(name = {a: "a"}) %}{% endmacro %}'),
293 array('{% macro foo(name = {a: {b: "a"}}) %}{% endmacro %}'),
294 );
295 }
296
297 /**
298 * @expectedException Twig_Error_Syntax
299 * @expectedExceptionMessage The function "cycl" does not exist. Did you mean "cycle" in "index" at line 1
300 */
301 public function testUnknownFunction()
302 {
303 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
304 $parser = new Twig_Parser($env);
305
306 $parser->parse($env->tokenize('{{ cycl() }}', 'index'));
307 }
308
309 /**
310 * @expectedException Twig_Error_Syntax
311 * @expectedExceptionMessage The filter "lowe" does not exist. Did you mean "lower" in "index" at line 1
312 */
313 public function testUnknownFilter()
314 {
315 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
316 $parser = new Twig_Parser($env);
317
318 $parser->parse($env->tokenize('{{ 1|lowe }}', 'index'));
319 }
320
321 /**
322 * @expectedException Twig_Error_Syntax
323 * @expectedExceptionMessage The test "nul" does not exist. Did you mean "null" in "index" at line 1
324 */
325 public function testUnknownTest()
326 {
327 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
328 $parser = new Twig_Parser($env);
329
330 $parser->parse($env->tokenize('{{ 1 is nul }}', 'index'));
331 }
332}
diff --git a/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php b/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php
new file mode 100644
index 00000000..5743e343
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php
@@ -0,0 +1,117 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Extension_CoreTest extends PHPUnit_Framework_TestCase
13{
14 /**
15 * @dataProvider getRandomFunctionTestData
16 */
17 public function testRandomFunction($value, $expectedInArray)
18 {
19 $env = new Twig_Environment();
20
21 for ($i = 0; $i < 100; $i++) {
22 $this->assertTrue(in_array(twig_random($env, $value), $expectedInArray, true)); // assertContains() would not consider the type
23 }
24 }
25
26 public function getRandomFunctionTestData()
27 {
28 return array(
29 array( // array
30 array('apple', 'orange', 'citrus'),
31 array('apple', 'orange', 'citrus'),
32 ),
33 array( // Traversable
34 new ArrayObject(array('apple', 'orange', 'citrus')),
35 array('apple', 'orange', 'citrus'),
36 ),
37 array( // unicode string
38 'Ä€é',
39 array('Ä', '€', 'é'),
40 ),
41 array( // numeric but string
42 '123',
43 array('1', '2', '3'),
44 ),
45 array( // integer
46 5,
47 range(0, 5, 1),
48 ),
49 array( // float
50 5.9,
51 range(0, 5, 1),
52 ),
53 array( // negative
54 -2,
55 array(0, -1, -2),
56 ),
57 );
58 }
59
60 public function testRandomFunctionWithoutParameter()
61 {
62 $max = mt_getrandmax();
63
64 for ($i = 0; $i < 100; $i++) {
65 $val = twig_random(new Twig_Environment());
66 $this->assertTrue(is_int($val) && $val >= 0 && $val <= $max);
67 }
68 }
69
70 public function testRandomFunctionReturnsAsIs()
71 {
72 $this->assertSame('', twig_random(new Twig_Environment(), ''));
73 $this->assertSame('', twig_random(new Twig_Environment(null, array('charset' => null)), ''));
74
75 $instance = new stdClass();
76 $this->assertSame($instance, twig_random(new Twig_Environment(), $instance));
77 }
78
79 /**
80 * @expectedException Twig_Error_Runtime
81 */
82 public function testRandomFunctionOfEmptyArrayThrowsException()
83 {
84 twig_random(new Twig_Environment(), array());
85 }
86
87 public function testRandomFunctionOnNonUTF8String()
88 {
89 if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
90 $this->markTestSkipped('needs iconv or mbstring');
91 }
92
93 $twig = new Twig_Environment();
94 $twig->setCharset('ISO-8859-1');
95
96 $text = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8');
97 for ($i = 0; $i < 30; $i++) {
98 $rand = twig_random($twig, $text);
99 $this->assertTrue(in_array(twig_convert_encoding($rand, 'UTF-8', 'ISO-8859-1'), array('Ä', 'é'), true));
100 }
101 }
102
103 public function testReverseFilterOnNonUTF8String()
104 {
105 if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
106 $this->markTestSkipped('needs iconv or mbstring');
107 }
108
109 $twig = new Twig_Environment();
110 $twig->setCharset('ISO-8859-1');
111
112 $input = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8');
113 $output = twig_convert_encoding(twig_reverse_filter($twig, $input), 'UTF-8', 'ISO-8859-1');
114
115 $this->assertEquals($output, 'éÄ');
116 }
117}
diff --git a/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php b/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php
new file mode 100644
index 00000000..72253c88
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php
@@ -0,0 +1,212 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase
13{
14 protected static $params, $templates;
15
16 public function setUp()
17 {
18 self::$params = array(
19 'name' => 'Fabien',
20 'obj' => new FooObject(),
21 'arr' => array('obj' => new FooObject()),
22 );
23
24 self::$templates = array(
25 '1_basic1' => '{{ obj.foo }}',
26 '1_basic2' => '{{ name|upper }}',
27 '1_basic3' => '{% if name %}foo{% endif %}',
28 '1_basic4' => '{{ obj.bar }}',
29 '1_basic5' => '{{ obj }}',
30 '1_basic6' => '{{ arr.obj }}',
31 '1_basic7' => '{{ cycle(["foo","bar"], 1) }}',
32 '1_basic8' => '{{ obj.getfoobar }}{{ obj.getFooBar }}',
33 '1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
34 '1_layout' => '{% block content %}{% endblock %}',
35 '1_child' => '{% extends "1_layout" %}{% block content %}{{ "a"|json_encode }}{% endblock %}',
36 );
37 }
38
39 /**
40 * @expectedException Twig_Sandbox_SecurityError
41 * @expectedExceptionMessage Filter "json_encode" is not allowed in "1_child".
42 */
43 public function testSandboxWithInheritance()
44 {
45 $twig = $this->getEnvironment(true, array(), self::$templates, array('block'));
46 $twig->loadTemplate('1_child')->render(array());
47 }
48
49 public function testSandboxGloballySet()
50 {
51 $twig = $this->getEnvironment(false, array(), self::$templates);
52 $this->assertEquals('FOO', $twig->loadTemplate('1_basic')->render(self::$params), 'Sandbox does nothing if it is disabled globally');
53
54 $twig = $this->getEnvironment(true, array(), self::$templates);
55 try {
56 $twig->loadTemplate('1_basic1')->render(self::$params);
57 $this->fail('Sandbox throws a SecurityError exception if an unallowed method is called');
58 } catch (Twig_Sandbox_SecurityError $e) {
59 }
60
61 $twig = $this->getEnvironment(true, array(), self::$templates);
62 try {
63 $twig->loadTemplate('1_basic2')->render(self::$params);
64 $this->fail('Sandbox throws a SecurityError exception if an unallowed filter is called');
65 } catch (Twig_Sandbox_SecurityError $e) {
66 }
67
68 $twig = $this->getEnvironment(true, array(), self::$templates);
69 try {
70 $twig->loadTemplate('1_basic3')->render(self::$params);
71 $this->fail('Sandbox throws a SecurityError exception if an unallowed tag is used in the template');
72 } catch (Twig_Sandbox_SecurityError $e) {
73 }
74
75 $twig = $this->getEnvironment(true, array(), self::$templates);
76 try {
77 $twig->loadTemplate('1_basic4')->render(self::$params);
78 $this->fail('Sandbox throws a SecurityError exception if an unallowed property is called in the template');
79 } catch (Twig_Sandbox_SecurityError $e) {
80 }
81
82 $twig = $this->getEnvironment(true, array(), self::$templates);
83 try {
84 $twig->loadTemplate('1_basic5')->render(self::$params);
85 $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
86 } catch (Twig_Sandbox_SecurityError $e) {
87 }
88
89 $twig = $this->getEnvironment(true, array(), self::$templates);
90 try {
91 $twig->loadTemplate('1_basic6')->render(self::$params);
92 $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
93 } catch (Twig_Sandbox_SecurityError $e) {
94 }
95
96 $twig = $this->getEnvironment(true, array(), self::$templates);
97 try {
98 $twig->loadTemplate('1_basic7')->render(self::$params);
99 $this->fail('Sandbox throws a SecurityError exception if an unallowed function is called in the template');
100 } catch (Twig_Sandbox_SecurityError $e) {
101 }
102
103 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => 'foo'));
104 FooObject::reset();
105 $this->assertEquals('foo', $twig->loadTemplate('1_basic1')->render(self::$params), 'Sandbox allow some methods');
106 $this->assertEquals(1, FooObject::$called['foo'], 'Sandbox only calls method once');
107
108 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => '__toString'));
109 FooObject::reset();
110 $this->assertEquals('foo', $twig->loadTemplate('1_basic5')->render(self::$params), 'Sandbox allow some methods');
111 $this->assertEquals(1, FooObject::$called['__toString'], 'Sandbox only calls method once');
112
113 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array('upper'));
114 $this->assertEquals('FABIEN', $twig->loadTemplate('1_basic2')->render(self::$params), 'Sandbox allow some filters');
115
116 $twig = $this->getEnvironment(true, array(), self::$templates, array('if'));
117 $this->assertEquals('foo', $twig->loadTemplate('1_basic3')->render(self::$params), 'Sandbox allow some tags');
118
119 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array('FooObject' => 'bar'));
120 $this->assertEquals('bar', $twig->loadTemplate('1_basic4')->render(self::$params), 'Sandbox allow some properties');
121
122 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array(), array('cycle'));
123 $this->assertEquals('bar', $twig->loadTemplate('1_basic7')->render(self::$params), 'Sandbox allow some functions');
124
125 foreach (array('getfoobar', 'getFoobar', 'getFooBar') as $name) {
126 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => $name));
127 FooObject::reset();
128 $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic8')->render(self::$params), 'Sandbox allow methods in a case-insensitive way');
129 $this->assertEquals(2, FooObject::$called['getFooBar'], 'Sandbox only calls method once');
130 }
131 }
132
133 public function testSandboxLocallySetForAnInclude()
134 {
135 self::$templates = array(
136 '2_basic' => '{{ obj.foo }}{% include "2_included" %}{{ obj.foo }}',
137 '2_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
138 );
139
140 $twig = $this->getEnvironment(false, array(), self::$templates);
141 $this->assertEquals('fooFOOfoo', $twig->loadTemplate('2_basic')->render(self::$params), 'Sandbox does nothing if disabled globally and sandboxed not used for the include');
142
143 self::$templates = array(
144 '3_basic' => '{{ obj.foo }}{% sandbox %}{% include "3_included" %}{% endsandbox %}{{ obj.foo }}',
145 '3_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
146 );
147
148 $twig = $this->getEnvironment(true, array(), self::$templates);
149 try {
150 $twig->loadTemplate('3_basic')->render(self::$params);
151 $this->fail('Sandbox throws a SecurityError exception when the included file is sandboxed');
152 } catch (Twig_Sandbox_SecurityError $e) {
153 }
154 }
155
156 public function testMacrosInASandbox()
157 {
158 $twig = $this->getEnvironment(true, array('autoescape' => true), array('index' => <<<EOF
159{%- import _self as macros %}
160
161{%- macro test(text) %}<p>{{ text }}</p>{% endmacro %}
162
163{{- macros.test('username') }}
164EOF
165 ), array('macro', 'import'), array('escape'));
166
167 $this->assertEquals('<p>username</p>', $twig->loadTemplate('index')->render(array()));
168 }
169
170 protected function getEnvironment($sandboxed, $options, $templates, $tags = array(), $filters = array(), $methods = array(), $properties = array(), $functions = array())
171 {
172 $loader = new Twig_Loader_Array($templates);
173 $twig = new Twig_Environment($loader, array_merge(array('debug' => true, 'cache' => false, 'autoescape' => false), $options));
174 $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
175 $twig->addExtension(new Twig_Extension_Sandbox($policy, $sandboxed));
176
177 return $twig;
178 }
179}
180
181class FooObject
182{
183 public static $called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
184
185 public $bar = 'bar';
186
187 public static function reset()
188 {
189 self::$called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
190 }
191
192 public function __toString()
193 {
194 ++self::$called['__toString'];
195
196 return 'foo';
197 }
198
199 public function foo()
200 {
201 ++self::$called['foo'];
202
203 return 'foo';
204 }
205
206 public function getFooBar()
207 {
208 ++self::$called['getFooBar'];
209
210 return 'foobar';
211 }
212}
diff --git a/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php b/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php
new file mode 100644
index 00000000..8efc948f
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php
@@ -0,0 +1,70 @@
1<?php
2
3class Twig_Tests_FileCachingTest extends PHPUnit_Framework_TestCase
4{
5 protected $fileName;
6 protected $env;
7 protected $tmpDir;
8
9 public function setUp()
10 {
11 $this->tmpDir = sys_get_temp_dir().'/TwigTests';
12 if (!file_exists($this->tmpDir)) {
13 @mkdir($this->tmpDir, 0777, true);
14 }
15
16 if (!is_writable($this->tmpDir)) {
17 $this->markTestSkipped(sprintf('Unable to run the tests as "%s" is not writable.', $this->tmpDir));
18 }
19
20 $this->env = new Twig_Environment(new Twig_Loader_String(), array('cache' => $this->tmpDir));
21 }
22
23 public function tearDown()
24 {
25 if ($this->fileName) {
26 unlink($this->fileName);
27 }
28
29 $this->removeDir($this->tmpDir);
30 }
31
32 public function testWritingCacheFiles()
33 {
34 $name = 'This is just text.';
35 $template = $this->env->loadTemplate($name);
36 $cacheFileName = $this->env->getCacheFilename($name);
37
38 $this->assertTrue(file_exists($cacheFileName), 'Cache file does not exist.');
39 $this->fileName = $cacheFileName;
40 }
41
42 public function testClearingCacheFiles()
43 {
44 $name = 'I will be deleted.';
45 $template = $this->env->loadTemplate($name);
46 $cacheFileName = $this->env->getCacheFilename($name);
47
48 $this->assertTrue(file_exists($cacheFileName), 'Cache file does not exist.');
49 $this->env->clearCacheFiles();
50 $this->assertFalse(file_exists($cacheFileName), 'Cache file was not cleared.');
51 }
52
53 private function removeDir($target)
54 {
55 $fp = opendir($target);
56 while (false !== $file = readdir($fp)) {
57 if (in_array($file, array('.', '..'))) {
58 continue;
59 }
60
61 if (is_dir($target.'/'.$file)) {
62 self::removeDir($target.'/'.$file);
63 } else {
64 unlink($target.'/'.$file);
65 }
66 }
67 closedir($fp);
68 rmdir($target);
69 }
70}
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/base.html b/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/base.html
new file mode 100644
index 00000000..cb0dbe44
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/base.html
@@ -0,0 +1 @@
{% block content %}{% endblock %}
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/index.html b/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/index.html
new file mode 100644
index 00000000..df57c822
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/index.html
@@ -0,0 +1,7 @@
1{% extends 'base.html' %}
2{% block content %}
3 {{ foo.bar }}
4{% endblock %}
5{% block foo %}
6 {{ foo.bar }}
7{% endblock %}
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test
new file mode 100644
index 00000000..02245e93
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test
@@ -0,0 +1,20 @@
1--TEST--
2Exception for an unclosed tag
3--TEMPLATE--
4{% block foo %}
5 {% if foo %}
6
7
8
9
10 {% for i in fo %}
11
12
13
14 {% endfor %}
15
16
17
18{% endblock %}
19--EXCEPTION--
20Twig_Error_Syntax: Unexpected tag name "endblock" (expecting closing tag for the "if" tag defined near line 4) in "index.twig" at line 16
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array.test
new file mode 100644
index 00000000..c69b1192
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array.test
@@ -0,0 +1,61 @@
1--TEST--
2Twig supports array notation
3--TEMPLATE--
4{# empty array #}
5{{ []|join(',') }}
6
7{{ [1, 2]|join(',') }}
8{{ ['foo', "bar"]|join(',') }}
9{{ {0: 1, 'foo': 'bar'}|join(',') }}
10{{ {0: 1, 'foo': 'bar'}|keys|join(',') }}
11
12{{ {0: 1, foo: 'bar'}|join(',') }}
13{{ {0: 1, foo: 'bar'}|keys|join(',') }}
14
15{# nested arrays #}
16{% set a = [1, 2, [1, 2], {'foo': {'foo': 'bar'}}] %}
17{{ a[2]|join(',') }}
18{{ a[3]["foo"]|join(',') }}
19
20{# works even if [] is used inside the array #}
21{{ [foo[bar]]|join(',') }}
22
23{# elements can be any expression #}
24{{ ['foo'|upper, bar|upper, bar == foo]|join(',') }}
25
26{# arrays can have a trailing , like in PHP #}
27{{
28 [
29 1,
30 2,
31 ]|join(',')
32}}
33
34{# keys can be any expression #}
35{% set a = 1 %}
36{% set b = "foo" %}
37{% set ary = { (a): 'a', (b): 'b', 'c': 'c', (a ~ b): 'd' } %}
38{{ ary|keys|join(',') }}
39{{ ary|join(',') }}
40--DATA--
41return array('bar' => 'bar', 'foo' => array('bar' => 'bar'))
42--EXPECT--
431,2
44foo,bar
451,bar
460,foo
47
481,bar
490,foo
50
511,2
52bar
53
54bar
55
56FOO,BAR,
57
581,2
59
601,foo,c,1foo
61a,b,c,d
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array_call.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array_call.test
new file mode 100644
index 00000000..f3df328f
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array_call.test
@@ -0,0 +1,14 @@
1--TEST--
2Twig supports method calls
3--TEMPLATE--
4{{ items.foo }}
5{{ items['foo'] }}
6{{ items[foo] }}
7{{ items[items[foo]] }}
8--DATA--
9return array('foo' => 'bar', 'items' => array('foo' => 'bar', 'bar' => 'foo'))
10--EXPECT--
11bar
12bar
13foo
14bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/binary.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/binary.test
new file mode 100644
index 00000000..f5e68456
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/binary.test
@@ -0,0 +1,46 @@
1--TEST--
2Twig supports binary operations (+, -, *, /, ~, %, and, or)
3--TEMPLATE--
4{{ 1 + 1 }}
5{{ 2 - 1 }}
6{{ 2 * 2 }}
7{{ 2 / 2 }}
8{{ 3 % 2 }}
9{{ 1 and 1 }}
10{{ 1 and 0 }}
11{{ 0 and 1 }}
12{{ 0 and 0 }}
13{{ 1 or 1 }}
14{{ 1 or 0 }}
15{{ 0 or 1 }}
16{{ 0 or 0 }}
17{{ 0 or 1 and 0 }}
18{{ 1 or 0 and 1 }}
19{{ "foo" ~ "bar" }}
20{{ foo ~ "bar" }}
21{{ "foo" ~ bar }}
22{{ foo ~ bar }}
23{{ 20 // 7 }}
24--DATA--
25return array('foo' => 'bar', 'bar' => 'foo')
26--EXPECT--
272
281
294
301
311
321
33
34
35
361
371
381
39
40
411
42foobar
43barbar
44foofoo
45barfoo
462
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/bitwise.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/bitwise.test
new file mode 100644
index 00000000..7b56b761
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/bitwise.test
@@ -0,0 +1,14 @@
1--TEST--
2Twig supports bitwise operations
3--TEMPLATE--
4{{ 1 b-and 5 }}
5{{ 1 b-or 5 }}
6{{ 1 b-xor 5 }}
7{{ (1 and 0 b-or 0) is sameas(1 and (0 b-or 0)) ? 'ok' : 'ko' }}
8--DATA--
9return array()
10--EXPECT--
111
125
134
14ok
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/comparison.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/comparison.test
new file mode 100644
index 00000000..726b8507
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/comparison.test
@@ -0,0 +1,14 @@
1--TEST--
2Twig supports comparison operators (==, !=, <, >, >=, <=)
3--TEMPLATE--
4{{ 1 > 2 }}/{{ 1 > 1 }}/{{ 1 >= 2 }}/{{ 1 >= 1 }}
5{{ 1 < 2 }}/{{ 1 < 1 }}/{{ 1 <= 2 }}/{{ 1 <= 1 }}
6{{ 1 == 1 }}/{{ 1 == 2 }}
7{{ 1 != 1 }}/{{ 1 != 2 }}
8--DATA--
9return array()
10--EXPECT--
11///1
121//1/1
131/
14/1
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/dotdot.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/dotdot.test
new file mode 100644
index 00000000..9cd0676c
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/dotdot.test
@@ -0,0 +1,20 @@
1--TEST--
2Twig supports the .. operator
3--TEMPLATE--
4{% for i in 0..10 %}{{ i }} {% endfor %}
5
6{% for letter in 'a'..'z' %}{{ letter }} {% endfor %}
7
8{% for letter in 'a'|upper..'z'|upper %}{{ letter }} {% endfor %}
9
10{% for i in foo[0]..foo[1] %}{{ i }} {% endfor %}
11
12{% for i in 0 + 1 .. 10 - 1 %}{{ i }} {% endfor %}
13--DATA--
14return array('foo' => array(1, 10))
15--EXPECT--
160 1 2 3 4 5 6 7 8 9 10
17a b c d e f g h i j k l m n o p q r s t u v w x y z
18A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
191 2 3 4 5 6 7 8 9 10
201 2 3 4 5 6 7 8 9
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/grouping.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/grouping.test
new file mode 100644
index 00000000..79f8e0b0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/grouping.test
@@ -0,0 +1,8 @@
1--TEST--
2Twig supports grouping of expressions
3--TEMPLATE--
4{{ (2 + 2) / 2 }}
5--DATA--
6return array()
7--EXPECT--
82
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/literals.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/literals.test
new file mode 100644
index 00000000..7ae3bae9
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/literals.test
@@ -0,0 +1,22 @@
1--TEST--
2Twig supports literals
3--TEMPLATE--
41 {{ true }}
52 {{ TRUE }}
63 {{ false }}
74 {{ FALSE }}
85 {{ none }}
96 {{ NONE }}
107 {{ null }}
118 {{ NULL }}
12--DATA--
13return array()
14--EXPECT--
151 1
162 1
173
184
195
206
217
228
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/magic_call.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/magic_call.test
new file mode 100644
index 00000000..159db96f
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/magic_call.test
@@ -0,0 +1,27 @@
1--TEST--
2Twig supports __call() for attributes
3--TEMPLATE--
4{{ foo.foo }}
5{{ foo.bar }}
6--DATA--
7class TestClassForMagicCallAttributes
8{
9 public function getBar()
10 {
11 return 'bar_from_getbar';
12 }
13
14 public function __call($method, $arguments)
15 {
16 if ('foo' === $method)
17 {
18 return 'foo_from_call';
19 }
20
21 return false;
22 }
23}
24return array('foo' => new TestClassForMagicCallAttributes())
25--EXPECT--
26foo_from_call
27bar_from_getbar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/method_call.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/method_call.test
new file mode 100644
index 00000000..5f801e63
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/method_call.test
@@ -0,0 +1,28 @@
1--TEST--
2Twig supports method calls
3--TEMPLATE--
4{{ items.foo.foo }}
5{{ items.foo.getFoo() }}
6{{ items.foo.bar }}
7{{ items.foo['bar'] }}
8{{ items.foo.bar('a', 43) }}
9{{ items.foo.bar(foo) }}
10{{ items.foo.self.foo() }}
11{{ items.foo.is }}
12{{ items.foo.in }}
13{{ items.foo.not }}
14--DATA--
15return array('foo' => 'bar', 'items' => array('foo' => new TwigTestFoo(), 'bar' => 'foo'))
16--CONFIG--
17return array('strict_variables' => false)
18--EXPECT--
19foo
20foo
21bar
22
23bar_a-43
24bar_bar
25foo
26is
27in
28not
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/postfix.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/postfix.test
new file mode 100644
index 00000000..542c3504
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/postfix.test
@@ -0,0 +1,22 @@
1--TEST--
2Twig parses postfix expressions
3--TEMPLATE--
4{% import _self as macros %}
5
6{% macro foo() %}foo{% endmacro %}
7
8{{ 'a' }}
9{{ 'a'|upper }}
10{{ ('a')|upper }}
11{{ -1|upper }}
12{{ macros.foo() }}
13{{ (macros).foo() }}
14--DATA--
15return array();
16--EXPECT--
17a
18A
19A
20-1
21foo
22foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/strings.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/strings.test
new file mode 100644
index 00000000..a9116613
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/strings.test
@@ -0,0 +1,10 @@
1--TEST--
2Twig supports string interpolation
3--TEMPLATE--
4{{ "foo #{"foo #{bar} baz"} baz" }}
5{{ "foo #{bar}#{bar} baz" }}
6--DATA--
7return array('bar' => 'BAR');
8--EXPECT--
9foo foo BAR baz baz
10foo BARBAR baz
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator.test
new file mode 100644
index 00000000..0e6fa96e
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator.test
@@ -0,0 +1,18 @@
1--TEST--
2Twig supports the ternary operator
3--TEMPLATE--
4{{ 1 ? 'YES' : 'NO' }}
5{{ 0 ? 'YES' : 'NO' }}
6{{ 0 ? 'YES' : (1 ? 'YES1' : 'NO1') }}
7{{ 0 ? 'YES' : (0 ? 'YES1' : 'NO1') }}
8{{ 1 == 1 ? 'foo<br />':'' }}
9{{ foo ~ (bar ? ('-' ~ bar) : '') }}
10--DATA--
11return array('foo' => 'foo', 'bar' => 'bar')
12--EXPECT--
13YES
14NO
15YES1
16NO1
17foo<br />
18foo-bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_noelse.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_noelse.test
new file mode 100644
index 00000000..fdc660fc
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_noelse.test
@@ -0,0 +1,10 @@
1--TEST--
2Twig supports the ternary operator
3--TEMPLATE--
4{{ 1 ? 'YES' }}
5{{ 0 ? 'YES' }}
6--DATA--
7return array()
8--EXPECT--
9YES
10
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_nothen.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_nothen.test
new file mode 100644
index 00000000..9057e837
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_nothen.test
@@ -0,0 +1,10 @@
1--TEST--
2Twig supports the ternary operator
3--TEMPLATE--
4{{ 'YES' ?: 'NO' }}
5{{ 0 ?: 'NO' }}
6--DATA--
7return array()
8--EXPECT--
9YES
10NO
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary.test
new file mode 100644
index 00000000..b79219a2
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary.test
@@ -0,0 +1,12 @@
1--TEST--
2Twig supports unary operators (not, -, +)
3--TEMPLATE--
4{{ not 1 }}/{{ not 0 }}
5{{ +1 + 1 }}/{{ -1 - 1 }}
6{{ not (false or true) }}
7--DATA--
8return array()
9--EXPECT--
10/1
112/-2
12
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_precedence.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_precedence.test
new file mode 100644
index 00000000..cc6eef8d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_precedence.test
@@ -0,0 +1,14 @@
1--TEST--
2Twig unary operators precedence
3--TEMPLATE--
4{{ -1 - 1 }}
5{{ -1 - -1 }}
6{{ -1 * -1 }}
7{{ 4 / -1 * 5 }}
8--DATA--
9return array()
10--EXPECT--
11-2
120
131
14-20
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/abs.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/abs.test
new file mode 100644
index 00000000..27e93fd6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/abs.test
@@ -0,0 +1,30 @@
1--TEST--
2"abs" filter
3--TEMPLATE--
4{{ (-5.5)|abs }}
5{{ (-5)|abs }}
6{{ (-0)|abs }}
7{{ 0|abs }}
8{{ 5|abs }}
9{{ 5.5|abs }}
10{{ number1|abs }}
11{{ number2|abs }}
12{{ number3|abs }}
13{{ number4|abs }}
14{{ number5|abs }}
15{{ number6|abs }}
16--DATA--
17return array('number1' => -5.5, 'number2' => -5, 'number3' => -0, 'number4' => 0, 'number5' => 5, 'number6' => 5.5)
18--EXPECT--
195.5
205
210
220
235
245.5
255.5
265
270
280
295
305.5
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch.test
new file mode 100644
index 00000000..cb6de7f9
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch.test
@@ -0,0 +1,31 @@
1--TEST--
2"batch" filter
3--TEMPLATE--
4{% for row in items|batch(3) %}
5 <div class=row>
6 {% for column in row %}
7 <div class=item>{{ column }}</div>
8 {% endfor %}
9 </div>
10{% endfor %}
11--DATA--
12return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
13--EXPECT--
14<div class=row>
15 <div class=item>a</div>
16 <div class=item>b</div>
17 <div class=item>c</div>
18 </div>
19 <div class=row>
20 <div class=item>d</div>
21 <div class=item>e</div>
22 <div class=item>f</div>
23 </div>
24 <div class=row>
25 <div class=item>g</div>
26 <div class=item>h</div>
27 <div class=item>i</div>
28 </div>
29 <div class=row>
30 <div class=item>j</div>
31 </div>
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_float.php b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_float.php
new file mode 100644
index 00000000..52de39cb
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_float.php
@@ -0,0 +1,31 @@
1--TEST--
2"batch" filter
3--TEMPLATE--
4{% for row in items|batch(3.1) %}
5 <div class=row>
6 {% for column in row %}
7 <div class=item>{{ column }}</div>
8 {% endfor %}
9 </div>
10{% endfor %}
11--DATA--
12return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
13--EXPECT--
14<div class=row>
15 <div class=item>a</div>
16 <div class=item>b</div>
17 <div class=item>c</div>
18 </div>
19 <div class=row>
20 <div class=item>d</div>
21 <div class=item>e</div>
22 <div class=item>f</div>
23 </div>
24 <div class=row>
25 <div class=item>g</div>
26 <div class=item>h</div>
27 <div class=item>i</div>
28 </div>
29 <div class=row>
30 <div class=item>j</div>
31 </div>
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_empty_fill.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_empty_fill.test
new file mode 100644
index 00000000..af996f24
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_empty_fill.test
@@ -0,0 +1,37 @@
1--TEST--
2"batch" filter
3--TEMPLATE--
4<table>
5{% for row in items|batch(3, '') %}
6 <tr>
7 {% for column in row %}
8 <td>{{ column }}</td>
9 {% endfor %}
10 </tr>
11{% endfor %}
12</table>
13--DATA--
14return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
15--EXPECT--
16<table>
17 <tr>
18 <td>a</td>
19 <td>b</td>
20 <td>c</td>
21 </tr>
22 <tr>
23 <td>d</td>
24 <td>e</td>
25 <td>f</td>
26 </tr>
27 <tr>
28 <td>g</td>
29 <td>h</td>
30 <td>i</td>
31 </tr>
32 <tr>
33 <td>j</td>
34 <td></td>
35 <td></td>
36 </tr>
37</table>
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_fill.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_fill.test
new file mode 100644
index 00000000..746295f1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_fill.test
@@ -0,0 +1,37 @@
1--TEST--
2"batch" filter
3--TEMPLATE--
4<table>
5{% for row in items|batch(3, 'fill') %}
6 <tr>
7 {% for column in row %}
8 <td>{{ column }}</td>
9 {% endfor %}
10 </tr>
11{% endfor %}
12</table>
13--DATA--
14return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
15--EXPECT--
16<table>
17 <tr>
18 <td>a</td>
19 <td>b</td>
20 <td>c</td>
21 </tr>
22 <tr>
23 <td>d</td>
24 <td>e</td>
25 <td>f</td>
26 </tr>
27 <tr>
28 <td>g</td>
29 <td>h</td>
30 <td>i</td>
31 </tr>
32 <tr>
33 <td>j</td>
34 <td>fill</td>
35 <td>fill</td>
36 </tr>
37</table>
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/convert_encoding.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/convert_encoding.test
new file mode 100644
index 00000000..380b04bb
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/convert_encoding.test
@@ -0,0 +1,10 @@
1--TEST--
2"convert_encoding" filter
3--CONDITION--
4function_exists('iconv') || function_exists('mb_convert_encoding')
5--TEMPLATE--
6{{ "愛していますか?"|convert_encoding('ISO-2022-JP', 'UTF-8')|convert_encoding('UTF-8', 'ISO-2022-JP') }}
7--DATA--
8return array()
9--EXPECT--
10愛していますか?
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date.test
new file mode 100644
index 00000000..d40bb04a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date.test
@@ -0,0 +1,76 @@
1--TEST--
2"date" filter
3--TEMPLATE--
4{{ date1|date }}
5{{ date1|date('d/m/Y') }}
6{{ date1|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }}
7{{ date1|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }}
8{{ date1|date('d/m/Y H:i:s P', 'America/Chicago') }}
9{{ date1|date('e') }}
10{{ date1|date('d/m/Y H:i:s') }}
11
12{{ date2|date }}
13{{ date2|date('d/m/Y') }}
14{{ date2|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }}
15{{ date2|date('d/m/Y H:i:s', timezone1) }}
16{{ date2|date('d/m/Y H:i:s') }}
17
18{{ date3|date }}
19{{ date3|date('d/m/Y') }}
20
21{{ date4|date }}
22{{ date4|date('d/m/Y') }}
23
24{{ date5|date }}
25{{ date5|date('d/m/Y') }}
26
27{{ date6|date('d/m/Y H:i:s P', 'Europe/Paris') }}
28{{ date6|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }}
29{{ date6|date('d/m/Y H:i:s P', false) }}
30{{ date6|date('e', 'Europe/Paris') }}
31{{ date6|date('e', false) }}
32
33{{ date7|date }}
34--DATA--
35date_default_timezone_set('Europe/Paris');
36return array(
37 'date1' => mktime(13, 45, 0, 10, 4, 2010),
38 'date2' => new DateTime('2010-10-04 13:45'),
39 'date3' => '2010-10-04 13:45',
40 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT
41 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(),
42 'date6' => new DateTime('2010-10-04 13:45', new DateTimeZone('America/New_York')),
43 'date7' => '2010-01-28T15:00:00+05:00',
44 'timezone1' => new DateTimeZone('America/New_York'),
45)
46--EXPECT--
47October 4, 2010 13:45
4804/10/2010
4904/10/2010 19:45:00
5004/10/2010 19:45:00 +08:00
5104/10/2010 06:45:00 -05:00
52Europe/Paris
5304/10/2010 13:45:00
54
55October 4, 2010 13:45
5604/10/2010
5704/10/2010 19:45:00
5804/10/2010 07:45:00
5904/10/2010 13:45:00
60
61October 4, 2010 13:45
6204/10/2010
63
64October 4, 2010 15:45
6504/10/2010
66
67January 2, 1964 04:04
6802/01/1964
69
7004/10/2010 19:45:00 +02:00
7105/10/2010 01:45:00 +08:00
7204/10/2010 13:45:00 -04:00
73Europe/Paris
74America/New_York
75
76January 28, 2010 11:00
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format.test
new file mode 100644
index 00000000..11a1ef4b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format.test
@@ -0,0 +1,14 @@
1--TEST--
2"date" filter
3--TEMPLATE--
4{{ date1|date }}
5{{ date1|date('d/m/Y') }}
6--DATA--
7date_default_timezone_set('UTC');
8$twig->getExtension('core')->setDateFormat('Y-m-d', '%d days %h hours');
9return array(
10 'date1' => mktime(13, 45, 0, 10, 4, 2010),
11)
12--EXPECT--
132010-10-04
1404/10/2010
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format_interval.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format_interval.test
new file mode 100644
index 00000000..e6d3707d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format_interval.test
@@ -0,0 +1,16 @@
1--TEST--
2"date" filter (interval support as of PHP 5.3)
3--CONDITION--
4version_compare(phpversion(), '5.3.0', '>=')
5--TEMPLATE--
6{{ date2|date }}
7{{ date2|date('%d days') }}
8--DATA--
9date_default_timezone_set('UTC');
10$twig->getExtension('core')->setDateFormat('Y-m-d', '%d days %h hours');
11return array(
12 'date2' => new DateInterval('P2D'),
13)
14--EXPECT--
152 days 0 hours
162 days
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_interval.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_interval.test
new file mode 100644
index 00000000..0c8c6f1a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_interval.test
@@ -0,0 +1,19 @@
1--TEST--
2"date" filter (interval support as of PHP 5.3)
3--CONDITION--
4version_compare(phpversion(), '5.3.0', '>=')
5--TEMPLATE--
6{{ date1|date }}
7{{ date1|date('%d days %h hours') }}
8{{ date1|date('%d days %h hours', timezone1) }}
9--DATA--
10date_default_timezone_set('UTC');
11return array(
12 'date1' => new DateInterval('P2D'),
13 // This should have no effect on DateInterval formatting
14 'timezone1' => new DateTimeZone('America/New_York'),
15)
16--EXPECT--
172 days
182 days 0 hours
192 days 0 hours
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_modify.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_modify.test
new file mode 100644
index 00000000..53d3a69c
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_modify.test
@@ -0,0 +1,14 @@
1--TEST--
2"date_modify" filter
3--TEMPLATE--
4{{ date1|date_modify('-1day')|date('Y-m-d H:i:s') }}
5{{ date2|date_modify('-1day')|date('Y-m-d H:i:s') }}
6--DATA--
7date_default_timezone_set('UTC');
8return array(
9 'date1' => '2010-10-04 13:45',
10 'date2' => new DateTime('2010-10-04 13:45'),
11)
12--EXPECT--
132010-10-03 13:45:00
142010-10-03 13:45:00
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test
new file mode 100644
index 00000000..4ecde8a1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test
@@ -0,0 +1,13 @@
1--TEST--
2"date" filter
3--TEMPLATE--
4{{ date|date(format='d/m/Y H:i:s P', timezone='America/Chicago') }}
5{{ date|date(timezone='America/Chicago', format='d/m/Y H:i:s P') }}
6{{ date|date('d/m/Y H:i:s P', timezone='America/Chicago') }}
7--DATA--
8date_default_timezone_set('UTC');
9return array('date' => mktime(13, 45, 0, 10, 4, 2010))
10--EXPECT--
1104/10/2010 08:45:00 -05:00
1204/10/2010 08:45:00 -05:00
1304/10/2010 08:45:00 -05:00
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/default.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/default.test
new file mode 100644
index 00000000..0e4404b1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/default.test
@@ -0,0 +1,150 @@
1--TEST--
2"default" filter
3--TEMPLATE--
4Variable:
5{{ definedVar |default('default') is sameas('default') ? 'ko' : 'ok' }}
6{{ zeroVar |default('default') is sameas('default') ? 'ko' : 'ok' }}
7{{ emptyVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
8{{ nullVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
9{{ undefinedVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
10Array access:
11{{ nested.definedVar |default('default') is sameas('default') ? 'ko' : 'ok' }}
12{{ nested['definedVar'] |default('default') is sameas('default') ? 'ko' : 'ok' }}
13{{ nested.zeroVar |default('default') is sameas('default') ? 'ko' : 'ok' }}
14{{ nested.emptyVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
15{{ nested.nullVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
16{{ nested.undefinedVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
17{{ nested['undefinedVar'] |default('default') is sameas('default') ? 'ok' : 'ko' }}
18{{ undefinedVar.foo |default('default') is sameas('default') ? 'ok' : 'ko' }}
19Plain values:
20{{ 'defined' |default('default') is sameas('default') ? 'ko' : 'ok' }}
21{{ 0 |default('default') is sameas('default') ? 'ko' : 'ok' }}
22{{ '' |default('default') is sameas('default') ? 'ok' : 'ko' }}
23{{ null |default('default') is sameas('default') ? 'ok' : 'ko' }}
24Precedence:
25{{ 'o' ~ nullVar |default('k') }}
26{{ 'o' ~ nested.nullVar |default('k') }}
27Object methods:
28{{ object.foo |default('default') is sameas('default') ? 'ko' : 'ok' }}
29{{ object.undefinedMethod |default('default') is sameas('default') ? 'ok' : 'ko' }}
30{{ object.getFoo() |default('default') is sameas('default') ? 'ko' : 'ok' }}
31{{ object.getFoo('a') |default('default') is sameas('default') ? 'ko' : 'ok' }}
32{{ object.undefinedMethod() |default('default') is sameas('default') ? 'ok' : 'ko' }}
33{{ object.undefinedMethod('a') |default('default') is sameas('default') ? 'ok' : 'ko' }}
34Deep nested:
35{{ nested.undefinedVar.foo.bar |default('default') is sameas('default') ? 'ok' : 'ko' }}
36{{ nested.definedArray.0 |default('default') is sameas('default') ? 'ko' : 'ok' }}
37{{ nested['definedArray'][0] |default('default') is sameas('default') ? 'ko' : 'ok' }}
38{{ object.self.foo |default('default') is sameas('default') ? 'ko' : 'ok' }}
39{{ object.self.undefinedMethod |default('default') is sameas('default') ? 'ok' : 'ko' }}
40{{ object.undefinedMethod.self |default('default') is sameas('default') ? 'ok' : 'ko' }}
41--DATA--
42return array(
43 'definedVar' => 'defined',
44 'zeroVar' => 0,
45 'emptyVar' => '',
46 'nullVar' => null,
47 'nested' => array(
48 'definedVar' => 'defined',
49 'zeroVar' => 0,
50 'emptyVar' => '',
51 'nullVar' => null,
52 'definedArray' => array(0),
53 ),
54 'object' => new TwigTestFoo(),
55)
56--CONFIG--
57return array('strict_variables' => false)
58--EXPECT--
59Variable:
60ok
61ok
62ok
63ok
64ok
65Array access:
66ok
67ok
68ok
69ok
70ok
71ok
72ok
73ok
74Plain values:
75ok
76ok
77ok
78ok
79Precedence:
80ok
81ok
82Object methods:
83ok
84ok
85ok
86ok
87ok
88ok
89Deep nested:
90ok
91ok
92ok
93ok
94ok
95ok
96--DATA--
97return array(
98 'definedVar' => 'defined',
99 'zeroVar' => 0,
100 'emptyVar' => '',
101 'nullVar' => null,
102 'nested' => array(
103 'definedVar' => 'defined',
104 'zeroVar' => 0,
105 'emptyVar' => '',
106 'nullVar' => null,
107 'definedArray' => array(0),
108 ),
109 'object' => new TwigTestFoo(),
110)
111--CONFIG--
112return array('strict_variables' => true)
113--EXPECT--
114Variable:
115ok
116ok
117ok
118ok
119ok
120Array access:
121ok
122ok
123ok
124ok
125ok
126ok
127ok
128ok
129Plain values:
130ok
131ok
132ok
133ok
134Precedence:
135ok
136ok
137Object methods:
138ok
139ok
140ok
141ok
142ok
143ok
144Deep nested:
145ok
146ok
147ok
148ok
149ok
150ok
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/dynamic_filter.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/dynamic_filter.test
new file mode 100644
index 00000000..93c5913f
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/dynamic_filter.test
@@ -0,0 +1,10 @@
1--TEST--
2dynamic filter
3--TEMPLATE--
4{{ 'bar'|foo_path }}
5{{ 'bar'|a_foo_b_bar }}
6--DATA--
7return array()
8--EXPECT--
9foo/bar
10a/b/bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape.test
new file mode 100644
index 00000000..a606c106
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape.test
@@ -0,0 +1,8 @@
1--TEST--
2"escape" filter
3--TEMPLATE--
4{{ "foo <br />"|e }}
5--DATA--
6return array()
7--EXPECT--
8foo &lt;br /&gt;
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_non_supported_charset.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_non_supported_charset.test
new file mode 100644
index 00000000..bba26a0d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_non_supported_charset.test
@@ -0,0 +1,8 @@
1--TEST--
2"escape" filter
3--TEMPLATE--
4{{ "愛していますか? <br />"|e }}
5--DATA--
6return array()
7--EXPECT--
8愛していますか? &lt;br /&gt;
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test
new file mode 100644
index 00000000..853465b6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test
@@ -0,0 +1,14 @@
1--TEST--
2"first" filter
3--TEMPLATE--
4{{ [1, 2, 3, 4]|first }}
5{{ {a: 1, b: 2, c: 3, d: 4}|first }}
6{{ '1234'|first }}
7{{ arr|first }}
8--DATA--
9return array('arr' => new ArrayObject(array(1, 2, 3, 4)))
10--EXPECT--
111
121
131
141
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/force_escape.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/force_escape.test
new file mode 100644
index 00000000..85a9b717
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/force_escape.test
@@ -0,0 +1,18 @@
1--TEST--
2"escape" filter
3--TEMPLATE--
4{% set foo %}
5 foo<br />
6{% endset %}
7
8{{ foo|e('html') -}}
9{{ foo|e('js') }}
10{% autoescape true %}
11 {{ foo }}
12{% endautoescape %}
13--DATA--
14return array()
15--EXPECT--
16 foo&lt;br /&gt;
17\x20\x20\x20\x20foo\x3Cbr\x20\x2F\x3E\x0A
18 foo<br />
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/format.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/format.test
new file mode 100644
index 00000000..97221ff8
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/format.test
@@ -0,0 +1,8 @@
1--TEST--
2"format" filter
3--TEMPLATE--
4{{ string|format(foo, 3) }}
5--DATA--
6return array('string' => '%s/%d', 'foo' => 'bar')
7--EXPECT--
8bar/3
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/join.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/join.test
new file mode 100644
index 00000000..b342c174
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/join.test
@@ -0,0 +1,12 @@
1--TEST--
2"join" filter
3--TEMPLATE--
4{{ ["foo", "bar"]|join(', ') }}
5{{ foo|join(', ') }}
6{{ bar|join(', ') }}
7--DATA--
8return array('foo' => new TwigTestFoo(), 'bar' => new ArrayObject(array(3, 4)))
9--EXPECT--
10foo, bar
111, 2
123, 4
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/json_encode.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/json_encode.test
new file mode 100644
index 00000000..1738d40c
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/json_encode.test
@@ -0,0 +1,12 @@
1--TEST--
2"json_encode" filter
3--TEMPLATE--
4{{ "foo"|json_encode|raw }}
5{{ foo|json_encode|raw }}
6{{ [foo, "foo"]|json_encode|raw }}
7--DATA--
8return array('foo' => new Twig_Markup('foo', 'UTF-8'))
9--EXPECT--
10"foo"
11"foo"
12["foo","foo"]
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test
new file mode 100644
index 00000000..ca3ac0cf
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test
@@ -0,0 +1,14 @@
1--TEST--
2"last" filter
3--TEMPLATE--
4{{ [1, 2, 3, 4]|last }}
5{{ {a: 1, b: 2, c: 3, d: 4}|last }}
6{{ '1234'|last }}
7{{ arr|last }}
8--DATA--
9return array('arr' => new ArrayObject(array(1, 2, 3, 4)))
10--EXPECT--
114
124
134
144
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length.test
new file mode 100644
index 00000000..3347474d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length.test
@@ -0,0 +1,14 @@
1--TEST--
2"length" filter
3--TEMPLATE--
4{{ array|length }}
5{{ string|length }}
6{{ number|length }}
7{{ markup|length }}
8--DATA--
9return array('array' => array(1, 4), 'string' => 'foo', 'number' => 1000, 'markup' => new Twig_Markup('foo', 'UTF-8'))
10--EXPECT--
112
123
134
143
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length_utf8.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length_utf8.test
new file mode 100644
index 00000000..5d5e2436
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length_utf8.test
@@ -0,0 +1,12 @@
1--TEST--
2"length" filter
3--CONDITION--
4function_exists('mb_get_info')
5--TEMPLATE--
6{{ string|length }}
7{{ markup|length }}
8--DATA--
9return array('string' => 'été', 'markup' => new Twig_Markup('foo', 'UTF-8'))
10--EXPECT--
113
123
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/merge.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/merge.test
new file mode 100644
index 00000000..2bd3d4c0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/merge.test
@@ -0,0 +1,16 @@
1--TEST--
2"merge" filter
3--TEMPLATE--
4{{ items|merge({'bar': 'foo'})|join }}
5{{ items|merge({'bar': 'foo'})|keys|join }}
6{{ {'bar': 'foo'}|merge(items)|join }}
7{{ {'bar': 'foo'}|merge(items)|keys|join }}
8{{ numerics|merge([4, 5, 6])|join }}
9--DATA--
10return array('items' => array('foo' => 'bar'), 'numerics' => array(1, 2, 3))
11--EXPECT--
12barfoo
13foobar
14foobar
15barfoo
16123456
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/nl2br.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/nl2br.test
new file mode 100644
index 00000000..6545a9bb
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/nl2br.test
@@ -0,0 +1,14 @@
1--TEST--
2"nl2br" filter
3--TEMPLATE--
4{{ "I like Twig.\nYou will like it too.\n\nEverybody like it!"|nl2br }}
5{{ text|nl2br }}
6--DATA--
7return array('text' => "If you have some <strong>HTML</strong>\nit will be escaped.")
8--EXPECT--
9I like Twig.<br />
10You will like it too.<br />
11<br />
12Everybody like it!
13If you have some &lt;strong&gt;HTML&lt;/strong&gt;<br />
14it will be escaped.
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format.test
new file mode 100644
index 00000000..639a8659
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format.test
@@ -0,0 +1,18 @@
1--TEST--
2"number_format" filter
3--TEMPLATE--
4{{ 20|number_format }}
5{{ 20.25|number_format }}
6{{ 20.25|number_format(2) }}
7{{ 20.25|number_format(2, ',') }}
8{{ 1020.25|number_format(2, ',') }}
9{{ 1020.25|number_format(2, ',', '.') }}
10--DATA--
11return array();
12--EXPECT--
1320
1420
1520.25
1620,25
171,020,25
181.020,25
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format_default.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format_default.test
new file mode 100644
index 00000000..c6903cc7
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format_default.test
@@ -0,0 +1,21 @@
1--TEST--
2"number_format" filter with defaults.
3--TEMPLATE--
4{{ 20|number_format }}
5{{ 20.25|number_format }}
6{{ 20.25|number_format(1) }}
7{{ 20.25|number_format(2, ',') }}
8{{ 1020.25|number_format }}
9{{ 1020.25|number_format(2, ',') }}
10{{ 1020.25|number_format(2, ',', '.') }}
11--DATA--
12$twig->getExtension('core')->setNumberFormat(2, '!', '=');
13return array();
14--EXPECT--
1520!00
1620!25
1720!3
1820,25
191=020!25
201=020,25
211.020,25
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace.test
new file mode 100644
index 00000000..4021660b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace.test
@@ -0,0 +1,8 @@
1--TEST--
2"replace" filter
3--TEMPLATE--
4{{ "I like %this% and %that%."|replace({'%this%': "foo", '%that%': "bar"}) }}
5--DATA--
6return array()
7--EXPECT--
8I like foo and bar.
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/reverse.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/reverse.test
new file mode 100644
index 00000000..7948ac45
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/reverse.test
@@ -0,0 +1,18 @@
1--TEST--
2"reverse" filter
3--TEMPLATE--
4{{ [1, 2, 3, 4]|reverse|join('') }}
5{{ '1234évènement'|reverse }}
6{{ arr|reverse|join('') }}
7{{ {'a': 'c', 'b': 'a'}|reverse()|join(',') }}
8{{ {'a': 'c', 'b': 'a'}|reverse(preserveKeys=true)|join(glue=',') }}
9{{ {'a': 'c', 'b': 'a'}|reverse(preserve_keys=true)|join(glue=',') }}
10--DATA--
11return array('arr' => new ArrayObject(array(1, 2, 3, 4)))
12--EXPECT--
134321
14tnemenèvé4321
154321
16a,c
17a,c
18a,c
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test
new file mode 100644
index 00000000..b37ad651
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test
@@ -0,0 +1,42 @@
1--TEST--
2"slice" filter
3--TEMPLATE--
4{{ [1, 2, 3, 4][1:2]|join('') }}
5{{ {a: 1, b: 2, c: 3, d: 4}[1:2]|join('') }}
6{{ [1, 2, 3, 4][start:length]|join('') }}
7{{ [1, 2, 3, 4]|slice(1, 2)|join('') }}
8{{ [1, 2, 3, 4]|slice(1, 2)|keys|join('') }}
9{{ [1, 2, 3, 4]|slice(1, 2, true)|keys|join('') }}
10{{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|join('') }}
11{{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|keys|join('') }}
12{{ '1234'|slice(1, 2) }}
13{{ '1234'[1:2] }}
14{{ arr|slice(1, 2)|join('') }}
15{{ arr[1:2]|join('') }}
16
17{{ [1, 2, 3, 4]|slice(1)|join('') }}
18{{ [1, 2, 3, 4][1:]|join('') }}
19{{ '1234'|slice(1) }}
20{{ '1234'[1:] }}
21{{ '1234'[:1] }}
22--DATA--
23return array('start' => 1, 'length' => 2, 'arr' => new ArrayObject(array(1, 2, 3, 4)))
24--EXPECT--
2523
2623
2723
2823
2901
3012
3123
32bc
3323
3423
3523
3623
37
38234
39234
40234
41234
421
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/sort.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/sort.test
new file mode 100644
index 00000000..21d575f1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/sort.test
@@ -0,0 +1,10 @@
1--TEST--
2"sort" filter
3--TEMPLATE--
4{{ array1|sort|join }}
5{{ array2|sort|join }}
6--DATA--
7return array('array1' => array(4, 1), 'array2' => array('foo', 'bar'))
8--EXPECT--
914
10barfoo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test
new file mode 100644
index 00000000..dbaf7dc9
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test
@@ -0,0 +1,8 @@
1--TEST--
2"§" custom filter
3--TEMPLATE--
4{{ 'foo'|§ }}
5--DATA--
6return array()
7--EXPECT--
8§foo§
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/split.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/split.test
new file mode 100644
index 00000000..ce8ec9ce
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/split.test
@@ -0,0 +1,18 @@
1--TEST--
2"split" filter
3--TEMPLATE--
4{{ "one,two,three,four,five"|split(',')|join('-') }}
5{{ foo|split(',')|join('-') }}
6{{ foo|split(',', 3)|join('-') }}
7{{ baz|split('')|join('-') }}
8{{ baz|split('', 2)|join('-') }}
9{{ foo|split(',', -2)|join('-') }}
10--DATA--
11return array('foo' => "one,two,three,four,five", 'baz' => '12345',)
12--EXPECT--
13one-two-three-four-five
14one-two-three-four-five
15one-two-three,four,five
161-2-3-4-5
1712-34-5
18one-two-three \ No newline at end of file
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/trim.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/trim.test
new file mode 100644
index 00000000..31920625
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/trim.test
@@ -0,0 +1,12 @@
1--TEST--
2"trim" filter
3--TEMPLATE--
4{{ " I like Twig. "|trim }}
5{{ text|trim }}
6{{ " foo/"|trim("/") }}
7--DATA--
8return array('text' => " If you have some <strong>HTML</strong> it will be escaped. ")
9--EXPECT--
10I like Twig.
11If you have some &lt;strong&gt;HTML&lt;/strong&gt; it will be escaped.
12 foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode.test
new file mode 100644
index 00000000..de956e7a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode.test
@@ -0,0 +1,12 @@
1--TEST--
2"url_encode" filter
3--TEMPLATE--
4{{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode }}
5{{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode|raw }}
6{{ {}|url_encode|default("default") }}
7--DATA--
8return array()
9--EXPECT--
10foo=bar&amp;number=3&amp;sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&amp;spa+ce=
11foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa+ce=
12default
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test
new file mode 100644
index 00000000..16ae1e8b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test
@@ -0,0 +1,12 @@
1--TEST--
2"attribute" function
3--TEMPLATE--
4{{ attribute(obj, method) }}
5{{ attribute(array, item) }}
6{{ attribute(obj, "bar", ["a", "b"]) }}
7--DATA--
8return array('obj' => new TwigTestFoo(), 'method' => 'foo', 'array' => array('foo' => 'bar'), 'item' => 'foo')
9--EXPECT--
10foo
11bar
12bar_a-b
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/block.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/block.test
new file mode 100644
index 00000000..8e54059a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/block.test
@@ -0,0 +1,12 @@
1--TEST--
2"block" function
3--TEMPLATE--
4{% extends 'base.twig' %}
5{% block bar %}BAR{% endblock %}
6--TEMPLATE(base.twig)--
7{% block foo %}{{ block('bar') }}{% endblock %}
8{% block bar %}BAR_BASE{% endblock %}
9--DATA--
10return array()
11--EXPECT--
12BARBAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/constant.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/constant.test
new file mode 100644
index 00000000..63128791
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/constant.test
@@ -0,0 +1,10 @@
1--TEST--
2"constant" function
3--TEMPLATE--
4{{ constant('DATE_W3C') == expect ? 'true' : 'false' }}
5{{ constant('ARRAY_AS_PROPS', object) }}
6--DATA--
7return array('expect' => DATE_W3C, 'object' => new ArrayObject(array('hi')));
8--EXPECT--
9true
102
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/cycle.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/cycle.test
new file mode 100644
index 00000000..522a63b8
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/cycle.test
@@ -0,0 +1,16 @@
1--TEST--
2"cycle" function
3--TEMPLATE--
4{% for i in 0..6 %}
5{{ cycle(array1, i) }}-{{ cycle(array2, i) }}
6{% endfor %}
7--DATA--
8return array('array1' => array('odd', 'even'), 'array2' => array('apple', 'orange', 'citrus'))
9--EXPECT--
10odd-apple
11even-orange
12odd-citrus
13even-apple
14odd-orange
15even-citrus
16odd-apple
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test
new file mode 100644
index 00000000..a4c97167
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test
@@ -0,0 +1,27 @@
1--TEST--
2"date" function
3--TEMPLATE--
4{{ date() == date('now') ? 'OK' : 'KO' }}
5{{ date() > date('-1day') ? 'OK' : 'KO' }}
6{{ date(date1) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
7{{ date(date2) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
8{{ date(date3) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
9{{ date(date4) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
10{{ date(date5) == date('1964-01-02 03:04') ? 'OK' : 'KO' }}
11--DATA--
12date_default_timezone_set('UTC');
13return array(
14 'date1' => mktime(13, 45, 0, 10, 4, 2010),
15 'date2' => new DateTime('2010-10-04 13:45'),
16 'date3' => '2010-10-04 13:45',
17 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT
18 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(),
19)
20--EXPECT--
21OK
22OK
23OK
24OK
25OK
26OK
27OK
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date_namedargs.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date_namedargs.test
new file mode 100644
index 00000000..b9dd9e38
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date_namedargs.test
@@ -0,0 +1,11 @@
1--TEST--
2"date" function
3--TEMPLATE--
4{{ date(date, "America/New_York")|date('d/m/Y H:i:s P', false) }}
5{{ date(timezone="America/New_York", date=date)|date('d/m/Y H:i:s P', false) }}
6--DATA--
7date_default_timezone_set('UTC');
8return array('date' => mktime(13, 45, 0, 10, 4, 2010))
9--EXPECT--
1004/10/2010 09:45:00 -04:00
1104/10/2010 09:45:00 -04:00
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump.test
new file mode 100644
index 00000000..f4072375
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump.test
@@ -0,0 +1,16 @@
1--TEST--
2"dump" function
3--CONDITION--
4!extension_loaded('xdebug')
5--TEMPLATE--
6{{ dump('foo') }}
7{{ dump('foo', 'bar') }}
8--DATA--
9return array('foo' => 'foo', 'bar' => 'bar')
10--CONFIG--
11return array('debug' => true, 'autoescape' => false);
12--EXPECT--
13string(3) "foo"
14
15string(3) "foo"
16string(3) "bar"
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump_array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump_array.test
new file mode 100644
index 00000000..889b7a92
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump_array.test
@@ -0,0 +1,19 @@
1--TEST--
2"dump" function, xdebug is not loaded or xdebug <2.2-dev is loaded
3--CONDITION--
4!extension_loaded('xdebug') || (($r = new ReflectionExtension('xdebug')) && version_compare($r->getVersion(), '2.2-dev', '<'))
5--TEMPLATE--
6{{ dump() }}
7--DATA--
8return array('foo' => 'foo', 'bar' => 'bar')
9--CONFIG--
10return array('debug' => true, 'autoescape' => false);
11--EXPECT--
12array(3) {
13 ["foo"]=>
14 string(3) "foo"
15 ["bar"]=>
16 string(3) "bar"
17 ["global"]=>
18 string(6) "global"
19}
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dynamic_function.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dynamic_function.test
new file mode 100644
index 00000000..913fbc99
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dynamic_function.test
@@ -0,0 +1,10 @@
1--TEST--
2dynamic function
3--TEMPLATE--
4{{ foo_path('bar') }}
5{{ a_foo_b_bar('bar') }}
6--DATA--
7return array()
8--EXPECT--
9foo/bar
10a/b/bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test
new file mode 100644
index 00000000..b7653b4e
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test
@@ -0,0 +1,13 @@
1--TEST--
2"include" function
3--TEMPLATE--
4{% set tmp = include("foo.twig") %}
5
6FOO{{ tmp }}BAR
7--TEMPLATE(foo.twig)--
8FOOBAR
9--DATA--
10return array()
11--EXPECT--
12FOO
13FOOBARBAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test
new file mode 100644
index 00000000..56f8f3b5
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test
@@ -0,0 +1,10 @@
1--TEST--
2"include" function is safe for auto-escaping
3--TEMPLATE--
4{{ include("foo.twig") }}
5--TEMPLATE(foo.twig)--
6<p>Test</p>
7--DATA--
8return array()
9--EXPECT--
10<p>Test</p>
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/basic.test
new file mode 100644
index 00000000..a434182a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/basic.test
@@ -0,0 +1,17 @@
1--TEST--
2"include" function
3--TEMPLATE--
4FOO
5{{ include("foo.twig") }}
6
7BAR
8--TEMPLATE(foo.twig)--
9FOOBAR
10--DATA--
11return array()
12--EXPECT--
13FOO
14
15FOOBAR
16
17BAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/expression.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/expression.test
new file mode 100644
index 00000000..aba30ce3
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/expression.test
@@ -0,0 +1,17 @@
1--TEST--
2"include" function allows expressions for the template to include
3--TEMPLATE--
4FOO
5{{ include(foo) }}
6
7BAR
8--TEMPLATE(foo.twig)--
9FOOBAR
10--DATA--
11return array('foo' => 'foo.twig')
12--EXPECT--
13FOO
14
15FOOBAR
16
17BAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/ignore_missing.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/ignore_missing.test
new file mode 100644
index 00000000..43a2ccc2
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/ignore_missing.test
@@ -0,0 +1,10 @@
1--TEST--
2"include" function
3--TEMPLATE--
4{{ include(["foo.twig", "bar.twig"], ignore_missing = true) }}
5{{ include("foo.twig", ignore_missing = true) }}
6{{ include("foo.twig", ignore_missing = true, variables = {}) }}
7{{ include("foo.twig", ignore_missing = true, variables = {}, with_context = true) }}
8--DATA--
9return array()
10--EXPECT--
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing.test
new file mode 100644
index 00000000..4d2f6cf1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing.test
@@ -0,0 +1,8 @@
1--TEST--
2"include" function
3--TEMPLATE--
4{{ include("foo.twig") }}
5--DATA--
6return array();
7--EXCEPTION--
8Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2.
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing_nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing_nested.test
new file mode 100644
index 00000000..78fddc7a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing_nested.test
@@ -0,0 +1,16 @@
1--TEST--
2"include" function
3--TEMPLATE--
4{% extends "base.twig" %}
5
6{% block content %}
7 {{ parent() }}
8{% endblock %}
9--TEMPLATE(base.twig)--
10{% block content %}
11 {{ include("foo.twig") }}
12{% endblock %}
13--DATA--
14return array();
15--EXCEPTION--
16Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3.
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test
new file mode 100644
index 00000000..788a2ab0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test
@@ -0,0 +1,10 @@
1--TEST--
2"include" tag sandboxed
3--TEMPLATE--
4{{ include("foo.twig", sandboxed = true) }}
5--TEMPLATE(foo.twig)--
6{{ foo|e }}
7--DATA--
8return array()
9--EXCEPTION--
10Twig_Sandbox_SecurityError: Filter "e" is not allowed in "index.twig" at line 2.
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/template_instance.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/template_instance.test
new file mode 100644
index 00000000..18d405a0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/template_instance.test
@@ -0,0 +1,10 @@
1--TEST--
2"include" function accepts Twig_Template instance
3--TEMPLATE--
4{{ include(foo) }} FOO
5--TEMPLATE(foo.twig)--
6BAR
7--DATA--
8return array('foo' => $twig->loadTemplate('foo.twig'))
9--EXPECT--
10BAR FOO
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/templates_as_array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/templates_as_array.test
new file mode 100644
index 00000000..1a810068
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/templates_as_array.test
@@ -0,0 +1,12 @@
1--TEST--
2"include" function
3--TEMPLATE--
4{{ include(["foo.twig", "bar.twig"]) }}
5{{- include(["bar.twig", "foo.twig"]) }}
6--TEMPLATE(foo.twig)--
7foo
8--DATA--
9return array()
10--EXPECT--
11foo
12foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_context.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_context.test
new file mode 100644
index 00000000..35611fbb
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_context.test
@@ -0,0 +1,16 @@
1--TEST--
2"include" function accept variables and with_context
3--TEMPLATE--
4{{ include("foo.twig") }}
5{{- include("foo.twig", with_context = false) }}
6{{- include("foo.twig", {'foo1': 'bar'}) }}
7{{- include("foo.twig", {'foo1': 'bar'}, with_context = false) }}
8--TEMPLATE(foo.twig)--
9{% for k, v in _context %}{{ k }},{% endfor %}
10--DATA--
11return array('foo' => 'bar')
12--EXPECT--
13foo,global,_parent,
14global,_parent,
15foo,global,foo1,_parent,
16foo1,global,_parent,
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_variables.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_variables.test
new file mode 100644
index 00000000..b2ace940
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_variables.test
@@ -0,0 +1,12 @@
1--TEST--
2"include" function accept variables
3--TEMPLATE--
4{{ include("foo.twig", {'foo': 'bar'}) }}
5{{- include("foo.twig", vars) }}
6--TEMPLATE(foo.twig)--
7{{ foo }}
8--DATA--
9return array('vars' => array('foo' => 'bar'))
10--EXPECT--
11bar
12bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/range.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/range.test
new file mode 100644
index 00000000..e0377c8d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/range.test
@@ -0,0 +1,8 @@
1--TEST--
2"range" function
3--TEMPLATE--
4{{ range(low=0+1, high=10+0, step=2)|join(',') }}
5--DATA--
6return array()
7--EXPECT--
81,3,5,7,9
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test
new file mode 100644
index 00000000..30c3df51
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test
@@ -0,0 +1,8 @@
1--TEST--
2"§" custom function
3--TEMPLATE--
4{{ §('foo') }}
5--DATA--
6return array()
7--EXPECT--
8§foo§
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test
new file mode 100644
index 00000000..41428da1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test
@@ -0,0 +1,11 @@
1--TEST--
2"template_from_string" function
3--TEMPLATE--
4{% include template_from_string(template) %}
5
6{% include template_from_string("Hello {{ name }}") %}
7--DATA--
8return array('name' => 'Fabien', 'template' => "Hello {{ name }}")
9--EXPECT--
10Hello Fabien
11Hello Fabien
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/default_values.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/default_values.test
new file mode 100644
index 00000000..4ccff7b6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/default_values.test
@@ -0,0 +1,16 @@
1--TEST--
2macro
3--TEMPLATE--
4{% from _self import test %}
5
6{% macro test(a, b = 'bar') -%}
7{{ a }}{{ b }}
8{%- endmacro %}
9
10{{ test('foo') }}
11{{ test('bar', 'foo') }}
12--DATA--
13return array();
14--EXPECT--
15foobar
16barfoo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/nested_calls.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/nested_calls.test
new file mode 100644
index 00000000..cd254281
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/nested_calls.test
@@ -0,0 +1,18 @@
1--TEST--
2macro
3--TEMPLATE--
4{% import _self as macros %}
5
6{% macro foo(data) %}
7 {{ data }}
8{% endmacro %}
9
10{% macro bar() %}
11 <br />
12{% endmacro %}
13
14{{ macros.foo(macros.bar()) }}
15--DATA--
16return array();
17--EXPECT--
18<br />
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/reserved_variables.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/reserved_variables.test
new file mode 100644
index 00000000..cbfb921b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/reserved_variables.test
@@ -0,0 +1,14 @@
1--TEST--
2macro
3--TEMPLATE--
4{% from _self import test %}
5
6{% macro test(this) -%}
7 {{ this }}
8{%- endmacro %}
9
10{{ test(this) }}
11--DATA--
12return array('this' => 'foo');
13--EXPECT--
14foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test
new file mode 100644
index 00000000..6a366cdf
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test
@@ -0,0 +1,22 @@
1--TEST--
2macro
3--TEMPLATE--
4{% import _self as test %}
5{% from _self import test %}
6
7{% macro test(a, b) -%}
8 {{ a|default('a') }}<br />
9 {{- b|default('b') }}<br />
10{%- endmacro %}
11
12{{ test.test() }}
13{{ test() }}
14{{ test.test(1, "c") }}
15{{ test(1, "c") }}
16--DATA--
17return array();
18--EXPECT--
19a<br />b<br />
20a<br />b<br />
211<br />c<br />
221<br />c<br />
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test
new file mode 100644
index 00000000..685626f2
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test
@@ -0,0 +1,14 @@
1--TEST--
2macro with a filter
3--TEMPLATE--
4{% import _self as test %}
5
6{% macro test() %}
7 {% filter escape %}foo<br />{% endfilter %}
8{% endmacro %}
9
10{{ test.test() }}
11--DATA--
12return array();
13--EXPECT--
14foo&lt;br /&gt;
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test
new file mode 100644
index 00000000..65f6cd2b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test
@@ -0,0 +1,8 @@
1--TEST--
2Twig outputs 0 nodes correctly
3--TEMPLATE--
4{{ foo }}0{{ foo }}
5--DATA--
6return array('foo' => 'foo')
7--EXPECT--
8foo0foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test
new file mode 100644
index 00000000..110aef82
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test
@@ -0,0 +1,17 @@
1--TEST--
2Twig is able to deal with SimpleXMLElement instances as variables
3--CONDITION--
4version_compare(phpversion(), '5.3.0', '>=')
5--TEMPLATE--
6Hello '{{ images.image.0.group }}'!
7{{ images.children().count() }}
8{% for image in images %}
9 - {{ image.group }}
10{% endfor %}
11--DATA--
12return array('images' => new SimpleXMLElement('<images><image><group>foo</group></image><image><group>bar</group></image></images>'))
13--EXPECT--
14Hello 'foo'!
152
16 - foo
17 - bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/strings_like_numbers.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/strings_like_numbers.test
new file mode 100644
index 00000000..e18e1107
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/strings_like_numbers.test
@@ -0,0 +1,8 @@
1--TEST--
2Twig does not confuse strings with integers in getAttribute()
3--TEMPLATE--
4{{ hash['2e2'] }}
5--DATA--
6return array('hash' => array('2e2' => 'works'))
7--EXPECT--
8works
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/basic.test
new file mode 100644
index 00000000..2f6a3e1a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/basic.test
@@ -0,0 +1,26 @@
1--TEST--
2"autoescape" tag applies escaping on its children
3--TEMPLATE--
4{% autoescape %}
5{{ var }}<br />
6{% endautoescape %}
7{% autoescape 'html' %}
8{{ var }}<br />
9{% endautoescape %}
10{% autoescape false %}
11{{ var }}<br />
12{% endautoescape %}
13{% autoescape true %}
14{{ var }}<br />
15{% endautoescape %}
16{% autoescape false %}
17{{ var }}<br />
18{% endautoescape %}
19--DATA--
20return array('var' => '<br />')
21--EXPECT--
22&lt;br /&gt;<br />
23&lt;br /&gt;<br />
24<br /><br />
25&lt;br /&gt;<br />
26<br /><br />
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/blocks.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/blocks.test
new file mode 100644
index 00000000..05ab83ce
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/blocks.test
@@ -0,0 +1,12 @@
1--TEST--
2"autoescape" tag applies escaping on embedded blocks
3--TEMPLATE--
4{% autoescape 'html' %}
5 {% block foo %}
6 {{ var }}
7 {% endblock %}
8{% endautoescape %}
9--DATA--
10return array('var' => '<br />')
11--EXPECT--
12&lt;br /&gt;
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/double_escaping.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/double_escaping.test
new file mode 100644
index 00000000..9c097246
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/double_escaping.test
@@ -0,0 +1,10 @@
1--TEST--
2"autoescape" tag does not double-escape
3--TEMPLATE--
4{% autoescape 'html' %}
5{{ var|escape }}
6{% endautoescape %}
7--DATA--
8return array('var' => '<br />')
9--EXPECT--
10&lt;br /&gt;
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/functions.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/functions.test
new file mode 100644
index 00000000..ce7ea789
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/functions.test
@@ -0,0 +1,83 @@
1--TEST--
2"autoescape" tag applies escaping after calling functions
3--TEMPLATE--
4
5autoescape false
6{% autoescape false %}
7
8safe_br
9{{ safe_br() }}
10
11unsafe_br
12{{ unsafe_br() }}
13
14{% endautoescape %}
15
16autoescape 'html'
17{% autoescape 'html' %}
18
19safe_br
20{{ safe_br() }}
21
22unsafe_br
23{{ unsafe_br() }}
24
25unsafe_br()|raw
26{{ (unsafe_br())|raw }}
27
28safe_br()|escape
29{{ (safe_br())|escape }}
30
31safe_br()|raw
32{{ (safe_br())|raw }}
33
34unsafe_br()|escape
35{{ (unsafe_br())|escape }}
36
37{% endautoescape %}
38
39autoescape js
40{% autoescape 'js' %}
41
42safe_br
43{{ safe_br() }}
44
45{% endautoescape %}
46--DATA--
47return array()
48--EXPECT--
49
50autoescape false
51
52safe_br
53<br />
54
55unsafe_br
56<br />
57
58
59autoescape 'html'
60
61safe_br
62<br />
63
64unsafe_br
65&lt;br /&gt;
66
67unsafe_br()|raw
68<br />
69
70safe_br()|escape
71&lt;br /&gt;
72
73safe_br()|raw
74<br />
75
76unsafe_br()|escape
77&lt;br /&gt;
78
79
80autoescape js
81
82safe_br
83\x3Cbr\x20\x2F\x3E
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/literal.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/literal.test
new file mode 100644
index 00000000..e389d4dd
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/literal.test
@@ -0,0 +1,45 @@
1--TEST--
2"autoescape" tag does not apply escaping on literals
3--TEMPLATE--
4{% autoescape 'html' %}
5
61. Simple literal
7{{ "<br />" }}
8
92. Conditional expression with only literals
10{{ true ? "<br />" : "<br>" }}
11
123. Conditional expression with a variable
13{{ true ? "<br />" : someVar }}
14
154. Nested conditionals with only literals
16{{ true ? (true ? "<br />" : "<br>") : "\n" }}
17
185. Nested conditionals with a variable
19{{ true ? (true ? "<br />" : someVar) : "\n" }}
20
216. Nested conditionals with a variable marked safe
22{{ true ? (true ? "<br />" : someVar|raw) : "\n" }}
23
24{% endautoescape %}
25--DATA--
26return array()
27--EXPECT--
28
291. Simple literal
30<br />
31
322. Conditional expression with only literals
33<br />
34
353. Conditional expression with a variable
36&lt;br /&gt;
37
384. Nested conditionals with only literals
39<br />
40
415. Nested conditionals with a variable
42&lt;br /&gt;
43
446. Nested conditionals with a variable marked safe
45<br />
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/nested.test
new file mode 100644
index 00000000..798e6fea
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/nested.test
@@ -0,0 +1,26 @@
1--TEST--
2"autoescape" tags can be nested at will
3--TEMPLATE--
4{{ var }}
5{% autoescape 'html' %}
6 {{ var }}
7 {% autoescape false %}
8 {{ var }}
9 {% autoescape 'html' %}
10 {{ var }}
11 {% endautoescape %}
12 {{ var }}
13 {% endautoescape %}
14 {{ var }}
15{% endautoescape %}
16{{ var }}
17--DATA--
18return array('var' => '<br />')
19--EXPECT--
20&lt;br /&gt;
21 &lt;br /&gt;
22 <br />
23 &lt;br /&gt;
24 <br />
25 &lt;br /&gt;
26&lt;br /&gt;
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/objects.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/objects.test
new file mode 100644
index 00000000..e896aa41
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/objects.test
@@ -0,0 +1,26 @@
1--TEST--
2"autoescape" tag applies escaping to object method calls
3--TEMPLATE--
4{% autoescape 'html' %}
5{{ user.name }}
6{{ user.name|lower }}
7{{ user }}
8{% endautoescape %}
9--DATA--
10class UserForAutoEscapeTest
11{
12 public function getName()
13 {
14 return 'Fabien<br />';
15 }
16
17 public function __toString()
18 {
19 return 'Fabien<br />';
20 }
21}
22return array('user' => new UserForAutoEscapeTest())
23--EXPECT--
24Fabien&lt;br /&gt;
25fabien&lt;br /&gt;
26Fabien&lt;br /&gt;
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/raw.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/raw.test
new file mode 100644
index 00000000..9f1cedd3
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/raw.test
@@ -0,0 +1,10 @@
1--TEST--
2"autoescape" tag does not escape when raw is used as a filter
3--TEMPLATE--
4{% autoescape 'html' %}
5{{ var|raw }}
6{% endautoescape %}
7--DATA--
8return array('var' => '<br />')
9--EXPECT--
10<br />
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test
new file mode 100644
index 00000000..cf8cceef
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test
@@ -0,0 +1,17 @@
1--TEST--
2"autoescape" tag accepts an escaping strategy
3--TEMPLATE--
4{% autoescape true js %}{{ var }}{% endautoescape %}
5
6{% autoescape true html %}{{ var }}{% endautoescape %}
7
8{% autoescape 'js' %}{{ var }}{% endautoescape %}
9
10{% autoescape 'html' %}{{ var }}{% endautoescape %}
11--DATA--
12return array('var' => '<br />"')
13--EXPECT--
14\x3Cbr\x20\x2F\x3E\x22
15&lt;br /&gt;&quot;
16\x3Cbr\x20\x2F\x3E\x22
17&lt;br /&gt;&quot;
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/type.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/type.test
new file mode 100644
index 00000000..4f415201
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/type.test
@@ -0,0 +1,69 @@
1--TEST--
2escape types
3--TEMPLATE--
4
51. autoescape 'html' |escape('js')
6
7{% autoescape 'html' %}
8<a onclick="alert(&quot;{{ msg|escape('js') }}&quot;)"></a>
9{% endautoescape %}
10
112. autoescape 'html' |escape('js')
12
13{% autoescape 'html' %}
14<a onclick="alert(&quot;{{ msg|escape('js') }}&quot;)"></a>
15{% endautoescape %}
16
173. autoescape 'js' |escape('js')
18
19{% autoescape 'js' %}
20<a onclick="alert(&quot;{{ msg|escape('js') }}&quot;)"></a>
21{% endautoescape %}
22
234. no escape
24
25{% autoescape false %}
26<a onclick="alert(&quot;{{ msg }}&quot;)"></a>
27{% endautoescape %}
28
295. |escape('js')|escape('html')
30
31{% autoescape false %}
32<a onclick="alert(&quot;{{ msg|escape('js')|escape('html') }}&quot;)"></a>
33{% endautoescape %}
34
356. autoescape 'html' |escape('js')|escape('html')
36
37{% autoescape 'html' %}
38<a onclick="alert(&quot;{{ msg|escape('js')|escape('html') }}&quot;)"></a>
39{% endautoescape %}
40
41--DATA--
42return array('msg' => "<>\n'\"")
43--EXPECT--
44
451. autoescape 'html' |escape('js')
46
47<a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
48
492. autoescape 'html' |escape('js')
50
51<a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
52
533. autoescape 'js' |escape('js')
54
55<a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
56
574. no escape
58
59<a onclick="alert(&quot;<>
60'"&quot;)"></a>
61
625. |escape('js')|escape('html')
63
64<a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
65
666. autoescape 'html' |escape('js')|escape('html')
67
68<a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
69
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test
new file mode 100644
index 00000000..7821a9aa
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test
@@ -0,0 +1,131 @@
1--TEST--
2"autoescape" tag applies escaping after calling filters
3--TEMPLATE--
4{% autoescape 'html' %}
5
6(escape_and_nl2br is an escaper filter)
7
81. Don't escape escaper filter output
9( var is escaped by |escape_and_nl2br, line-breaks are added,
10 the output is not escaped )
11{{ var|escape_and_nl2br }}
12
132. Don't escape escaper filter output
14( var is escaped by |escape_and_nl2br, line-breaks are added,
15 the output is not escaped, |raw is redundant )
16{{ var|escape_and_nl2br|raw }}
17
183. Explicit escape
19( var is escaped by |escape_and_nl2br, line-breaks are added,
20 the output is explicitly escaped by |escape )
21{{ var|escape_and_nl2br|escape }}
22
234. Escape non-escaper filter output
24( var is upper-cased by |upper,
25 the output is auto-escaped )
26{{ var|upper }}
27
285. Escape if last filter is not an escaper
29( var is escaped by |escape_and_nl2br, line-breaks are added,
30 the output is upper-cased by |upper,
31 the output is auto-escaped as |upper is not an escaper )
32{{ var|escape_and_nl2br|upper }}
33
346. Don't escape escaper filter output
35( var is upper cased by upper,
36 the output is escaped by |escape_and_nl2br, line-breaks are added,
37 the output is not escaped as |escape_and_nl2br is an escaper )
38{{ var|upper|escape_and_nl2br }}
39
407. Escape if last filter is not an escaper
41( the output of |format is "<b>" ~ var ~ "</b>",
42 the output is auto-escaped )
43{{ "<b>%s</b>"|format(var) }}
44
458. Escape if last filter is not an escaper
46( the output of |format is "<b>" ~ var ~ "</b>",
47 |raw is redundant,
48 the output is auto-escaped )
49{{ "<b>%s</b>"|raw|format(var) }}
50
519. Don't escape escaper filter output
52( the output of |format is "<b>" ~ var ~ "</b>",
53 the output is not escaped due to |raw filter at the end )
54{{ "<b>%s</b>"|format(var)|raw }}
55
5610. Don't escape escaper filter output
57( the output of |format is "<b>" ~ var ~ "</b>",
58 the output is not escaped due to |raw filter at the end,
59 the |raw filter on var is redundant )
60{{ "<b>%s</b>"|format(var|raw)|raw }}
61
62{% endautoescape %}
63--DATA--
64return array('var' => "<Fabien>\nTwig")
65--EXPECT--
66
67(escape_and_nl2br is an escaper filter)
68
691. Don't escape escaper filter output
70( var is escaped by |escape_and_nl2br, line-breaks are added,
71 the output is not escaped )
72&lt;Fabien&gt;<br />
73Twig
74
752. Don't escape escaper filter output
76( var is escaped by |escape_and_nl2br, line-breaks are added,
77 the output is not escaped, |raw is redundant )
78&lt;Fabien&gt;<br />
79Twig
80
813. Explicit escape
82( var is escaped by |escape_and_nl2br, line-breaks are added,
83 the output is explicitly escaped by |escape )
84&amp;lt;Fabien&amp;gt;&lt;br /&gt;
85Twig
86
874. Escape non-escaper filter output
88( var is upper-cased by |upper,
89 the output is auto-escaped )
90&lt;FABIEN&gt;
91TWIG
92
935. Escape if last filter is not an escaper
94( var is escaped by |escape_and_nl2br, line-breaks are added,
95 the output is upper-cased by |upper,
96 the output is auto-escaped as |upper is not an escaper )
97&amp;LT;FABIEN&amp;GT;&lt;BR /&gt;
98TWIG
99
1006. Don't escape escaper filter output
101( var is upper cased by upper,
102 the output is escaped by |escape_and_nl2br, line-breaks are added,
103 the output is not escaped as |escape_and_nl2br is an escaper )
104&lt;FABIEN&gt;<br />
105TWIG
106
1077. Escape if last filter is not an escaper
108( the output of |format is "<b>" ~ var ~ "</b>",
109 the output is auto-escaped )
110&lt;b&gt;&lt;Fabien&gt;
111Twig&lt;/b&gt;
112
1138. Escape if last filter is not an escaper
114( the output of |format is "<b>" ~ var ~ "</b>",
115 |raw is redundant,
116 the output is auto-escaped )
117&lt;b&gt;&lt;Fabien&gt;
118Twig&lt;/b&gt;
119
1209. Don't escape escaper filter output
121( the output of |format is "<b>" ~ var ~ "</b>",
122 the output is not escaped due to |raw filter at the end )
123<b><Fabien>
124Twig</b>
125
12610. Don't escape escaper filter output
127( the output of |format is "<b>" ~ var ~ "</b>",
128 the output is not escaped due to |raw filter at the end,
129 the |raw filter on var is redundant )
130<b><Fabien>
131Twig</b>
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test
new file mode 100644
index 00000000..f58a1e09
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test
@@ -0,0 +1,23 @@
1--TEST--
2"autoescape" tag do not applies escaping on filter arguments
3--TEMPLATE--
4{% autoescape 'html' %}
5{{ var|nl2br("<br />") }}
6{{ var|nl2br("<br />"|escape) }}
7{{ var|nl2br(sep) }}
8{{ var|nl2br(sep|raw) }}
9{{ var|nl2br(sep|escape) }}
10{% endautoescape %}
11--DATA--
12return array('var' => "<Fabien>\nTwig", 'sep' => '<br />')
13--EXPECT--
14&lt;Fabien&gt;<br />
15Twig
16&lt;Fabien&gt;&lt;br /&gt;
17Twig
18&lt;Fabien&gt;<br />
19Twig
20&lt;Fabien&gt;<br />
21Twig
22&lt;Fabien&gt;&lt;br /&gt;
23Twig
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_pre_escape_filters.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_pre_escape_filters.test
new file mode 100644
index 00000000..134c77ea
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_pre_escape_filters.test
@@ -0,0 +1,68 @@
1--TEST--
2"autoescape" tag applies escaping after calling filters, and before calling pre_escape filters
3--TEMPLATE--
4{% autoescape 'html' %}
5
6(nl2br is pre_escaped for "html" and declared safe for "html")
7
81. Pre-escape and don't post-escape
9( var|escape|nl2br )
10{{ var|nl2br }}
11
122. Don't double-pre-escape
13( var|escape|nl2br )
14{{ var|escape|nl2br }}
15
163. Don't escape safe values
17( var|raw|nl2br )
18{{ var|raw|nl2br }}
19
204. Don't escape safe values
21( var|escape|nl2br|nl2br )
22{{ var|nl2br|nl2br }}
23
245. Re-escape values that are escaped for an other contexts
25( var|escape_something|escape|nl2br )
26{{ var|escape_something|nl2br }}
27
286. Still escape when using filters not declared safe
29( var|escape|nl2br|upper|escape )
30{{ var|nl2br|upper }}
31
32{% endautoescape %}
33--DATA--
34return array('var' => "<Fabien>\nTwig")
35--EXPECT--
36
37(nl2br is pre_escaped for "html" and declared safe for "html")
38
391. Pre-escape and don't post-escape
40( var|escape|nl2br )
41&lt;Fabien&gt;<br />
42Twig
43
442. Don't double-pre-escape
45( var|escape|nl2br )
46&lt;Fabien&gt;<br />
47Twig
48
493. Don't escape safe values
50( var|raw|nl2br )
51<Fabien><br />
52Twig
53
544. Don't escape safe values
55( var|escape|nl2br|nl2br )
56&lt;Fabien&gt;<br /><br />
57Twig
58
595. Re-escape values that are escaped for an other contexts
60( var|escape_something|escape|nl2br )
61&lt;FABIEN&gt;<br />
62TWIG
63
646. Still escape when using filters not declared safe
65( var|escape|nl2br|upper|escape )
66&amp;LT;FABIEN&amp;GT;&lt;BR /&gt;
67TWIG
68
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_preserves_safety_filters.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_preserves_safety_filters.test
new file mode 100644
index 00000000..32d3943b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_preserves_safety_filters.test
@@ -0,0 +1,50 @@
1--TEST--
2"autoescape" tag handles filters preserving the safety
3--TEMPLATE--
4{% autoescape 'html' %}
5
6(preserves_safety is preserving safety for "html")
7
81. Unsafe values are still unsafe
9( var|preserves_safety|escape )
10{{ var|preserves_safety }}
11
122. Safe values are still safe
13( var|escape|preserves_safety )
14{{ var|escape|preserves_safety }}
15
163. Re-escape values that are escaped for an other contexts
17( var|escape_something|preserves_safety|escape )
18{{ var|escape_something|preserves_safety }}
19
204. Still escape when using filters not declared safe
21( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape )
22{{ var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'}) }}
23
24{% endautoescape %}
25--DATA--
26return array('var' => "<Fabien>\nTwig")
27--EXPECT--
28
29(preserves_safety is preserving safety for "html")
30
311. Unsafe values are still unsafe
32( var|preserves_safety|escape )
33&lt;FABIEN&gt;
34TWIG
35
362. Safe values are still safe
37( var|escape|preserves_safety )
38&LT;FABIEN&GT;
39TWIG
40
413. Re-escape values that are escaped for an other contexts
42( var|escape_something|preserves_safety|escape )
43&lt;FABIEN&gt;
44TWIG
45
464. Still escape when using filters not declared safe
47( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape )
48&amp;LT;FABPOT&amp;GT;
49TWIG
50
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/basic.test
new file mode 100644
index 00000000..360dcf03
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/basic.test
@@ -0,0 +1,11 @@
1--TEST--
2"block" tag
3--TEMPLATE--
4{% block title1 %}FOO{% endblock %}
5{% block title2 foo|lower %}
6--TEMPLATE(foo.twig)--
7{% block content %}{% endblock %}
8--DATA--
9return array('foo' => 'bar')
10--EXPECT--
11FOObar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/block_unique_name.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/block_unique_name.test
new file mode 100644
index 00000000..5c205c0a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/block_unique_name.test
@@ -0,0 +1,11 @@
1--TEST--
2"block" tag
3--TEMPLATE--
4{% block content %}
5 {% block content %}
6 {% endblock %}
7{% endblock %}
8--DATA--
9return array()
10--EXCEPTION--
11Twig_Error_Syntax: The block 'content' has already been defined line 2 in "index.twig" at line 3
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test
new file mode 100644
index 00000000..be17fedf
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test
@@ -0,0 +1,10 @@
1--TEST--
2"§" special chars in a block name
3--TEMPLATE--
4{% block § %}
5§
6{% endblock § %}
7--DATA--
8return array()
9--EXPECT--
10§
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/basic.test
new file mode 100644
index 00000000..f44296ea
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/basic.test
@@ -0,0 +1,35 @@
1--TEST--
2"embed" tag
3--TEMPLATE--
4FOO
5{% embed "foo.twig" %}
6 {% block c1 %}
7 {{ parent() }}
8 block1extended
9 {% endblock %}
10{% endembed %}
11
12BAR
13--TEMPLATE(foo.twig)--
14A
15{% block c1 %}
16 block1
17{% endblock %}
18B
19{% block c2 %}
20 block2
21{% endblock %}
22C
23--DATA--
24return array()
25--EXPECT--
26FOO
27
28A
29 block1
30
31 block1extended
32 B
33 block2
34C
35BAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test
new file mode 100644
index 00000000..71ab2e01
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test
@@ -0,0 +1,16 @@
1--TEST--
2"embed" tag
3--TEMPLATE(index.twig)--
4FOO
5{% embed "foo.twig" %}
6 {% block c1 %}
7 {{ nothing }}
8 {% endblock %}
9{% endembed %}
10BAR
11--TEMPLATE(foo.twig)--
12{% block c1 %}{% endblock %}
13--DATA--
14return array()
15--EXCEPTION--
16Twig_Error_Runtime: Variable "nothing" does not exist in "index.twig" at line 5
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/multiple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/multiple.test
new file mode 100644
index 00000000..da161e6d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/multiple.test
@@ -0,0 +1,50 @@
1--TEST--
2"embed" tag
3--TEMPLATE--
4FOO
5{% embed "foo.twig" %}
6 {% block c1 %}
7 {{ parent() }}
8 block1extended
9 {% endblock %}
10{% endembed %}
11
12{% embed "foo.twig" %}
13 {% block c1 %}
14 {{ parent() }}
15 block1extended
16 {% endblock %}
17{% endembed %}
18
19BAR
20--TEMPLATE(foo.twig)--
21A
22{% block c1 %}
23 block1
24{% endblock %}
25B
26{% block c2 %}
27 block2
28{% endblock %}
29C
30--DATA--
31return array()
32--EXPECT--
33FOO
34
35A
36 block1
37
38 block1extended
39 B
40 block2
41C
42
43A
44 block1
45
46 block1extended
47 B
48 block2
49C
50BAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/nested.test
new file mode 100644
index 00000000..81563dce
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/nested.test
@@ -0,0 +1,42 @@
1--TEST--
2"embed" tag
3--TEMPLATE--
4{% embed "foo.twig" %}
5 {% block c1 %}
6 {{ parent() }}
7 {% embed "foo.twig" %}
8 {% block c1 %}
9 {{ parent() }}
10 block1extended
11 {% endblock %}
12 {% endembed %}
13
14 {% endblock %}
15{% endembed %}
16--TEMPLATE(foo.twig)--
17A
18{% block c1 %}
19 block1
20{% endblock %}
21B
22{% block c2 %}
23 block2
24{% endblock %}
25C
26--DATA--
27return array()
28--EXPECT--
29A
30 block1
31
32
33A
34 block1
35
36 block1extended
37 B
38 block2
39C
40 B
41 block2
42C
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/with_extends.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/with_extends.test
new file mode 100644
index 00000000..cf7953d3
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/with_extends.test
@@ -0,0 +1,57 @@
1--TEST--
2"embed" tag
3--TEMPLATE--
4{% extends "base.twig" %}
5
6{% block c1 %}
7 {{ parent() }}
8 blockc1baseextended
9{% endblock %}
10
11{% block c2 %}
12 {{ parent() }}
13
14 {% embed "foo.twig" %}
15 {% block c1 %}
16 {{ parent() }}
17 block1extended
18 {% endblock %}
19 {% endembed %}
20{% endblock %}
21--TEMPLATE(base.twig)--
22A
23{% block c1 %}
24 blockc1base
25{% endblock %}
26{% block c2 %}
27 blockc2base
28{% endblock %}
29B
30--TEMPLATE(foo.twig)--
31A
32{% block c1 %}
33 block1
34{% endblock %}
35B
36{% block c2 %}
37 block2
38{% endblock %}
39C
40--DATA--
41return array()
42--EXPECT--
43A
44 blockc1base
45
46 blockc1baseextended
47 blockc2base
48
49
50
51A
52 block1
53
54 block1extended
55 B
56 block2
57CB \ No newline at end of file
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/basic.test
new file mode 100644
index 00000000..82094f2f
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/basic.test
@@ -0,0 +1,10 @@
1--TEST--
2"filter" tag applies a filter on its children
3--TEMPLATE--
4{% filter upper %}
5Some text with a {{ var }}
6{% endfilter %}
7--DATA--
8return array('var' => 'var')
9--EXPECT--
10SOME TEXT WITH A VAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/json_encode.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/json_encode.test
new file mode 100644
index 00000000..3e7148bf
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/json_encode.test
@@ -0,0 +1,8 @@
1--TEST--
2"filter" tag applies a filter on its children
3--TEMPLATE--
4{% filter json_encode|raw %}test{% endfilter %}
5--DATA--
6return array()
7--EXPECT--
8"test"
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/multiple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/multiple.test
new file mode 100644
index 00000000..75512ef9
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/multiple.test
@@ -0,0 +1,10 @@
1--TEST--
2"filter" tags accept multiple chained filters
3--TEMPLATE--
4{% filter lower|title %}
5 {{ var }}
6{% endfilter %}
7--DATA--
8return array('var' => 'VAR')
9--EXPECT--
10 Var
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/nested.test
new file mode 100644
index 00000000..7e4e4eb3
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/nested.test
@@ -0,0 +1,16 @@
1--TEST--
2"filter" tags can be nested at will
3--TEMPLATE--
4{% filter lower|title %}
5 {{ var }}
6 {% filter upper %}
7 {{ var }}
8 {% endfilter %}
9 {{ var }}
10{% endfilter %}
11--DATA--
12return array('var' => 'var')
13--EXPECT--
14 Var
15 Var
16 Var
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_for_tag.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_for_tag.test
new file mode 100644
index 00000000..22745ead
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_for_tag.test
@@ -0,0 +1,13 @@
1--TEST--
2"filter" tag applies the filter on "for" tags
3--TEMPLATE--
4{% filter upper %}
5{% for item in items %}
6{{ item }}
7{% endfor %}
8{% endfilter %}
9--DATA--
10return array('items' => array('a', 'b'))
11--EXPECT--
12A
13B
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_if_tag.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_if_tag.test
new file mode 100644
index 00000000..afd95b29
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_if_tag.test
@@ -0,0 +1,29 @@
1--TEST--
2"filter" tag applies the filter on "if" tags
3--TEMPLATE--
4{% filter upper %}
5{% if items %}
6{{ items|join(', ') }}
7{% endif %}
8
9{% if items.3 is defined %}
10FOO
11{% else %}
12{{ items.1 }}
13{% endif %}
14
15{% if items.3 is defined %}
16FOO
17{% elseif items.1 %}
18{{ items.0 }}
19{% endif %}
20
21{% endfilter %}
22--DATA--
23return array('items' => array('a', 'b'))
24--EXPECT--
25A, B
26
27B
28
29A
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/condition.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/condition.test
new file mode 100644
index 00000000..380531f7
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/condition.test
@@ -0,0 +1,14 @@
1--TEST--
2"for" tag takes a condition
3--TEMPLATE--
4{% for i in 1..5 if i is odd -%}
5 {{ loop.index }}.{{ i }}{{ foo.bar }}
6{% endfor %}
7--DATA--
8return array('foo' => array('bar' => 'X'))
9--CONFIG--
10return array('strict_variables' => false)
11--EXPECT--
121.1X
132.3X
143.5X
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/context.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/context.test
new file mode 100644
index 00000000..ddc69307
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/context.test
@@ -0,0 +1,18 @@
1--TEST--
2"for" tag keeps the context safe
3--TEMPLATE--
4{% for item in items %}
5 {% for item in items %}
6 * {{ item }}
7 {% endfor %}
8 * {{ item }}
9{% endfor %}
10--DATA--
11return array('items' => array('a', 'b'))
12--EXPECT--
13 * a
14 * b
15 * a
16 * a
17 * b
18 * b
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/else.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/else.test
new file mode 100644
index 00000000..20ccc880
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/else.test
@@ -0,0 +1,23 @@
1--TEST--
2"for" tag can use an "else" clause
3--TEMPLATE--
4{% for item in items %}
5 * {{ item }}
6{% else %}
7 no item
8{% endfor %}
9--DATA--
10return array('items' => array('a', 'b'))
11--EXPECT--
12 * a
13 * b
14--DATA--
15return array('items' => array())
16--EXPECT--
17 no item
18--DATA--
19return array()
20--CONFIG--
21return array('strict_variables' => false)
22--EXPECT--
23 no item
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/inner_variables.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/inner_variables.test
new file mode 100644
index 00000000..49fb9ca6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/inner_variables.test
@@ -0,0 +1,17 @@
1--TEST--
2"for" tag does not reset inner variables
3--TEMPLATE--
4{% for i in 1..2 %}
5 {% for j in 0..2 %}
6 {{k}}{% set k = k+1 %} {{ loop.parent.loop.index }}
7 {% endfor %}
8{% endfor %}
9--DATA--
10return array('k' => 0)
11--EXPECT--
12 0 1
13 1 1
14 2 1
15 3 2
16 4 2
17 5 2
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys.test
new file mode 100644
index 00000000..4e22cb47
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys.test
@@ -0,0 +1,11 @@
1--TEST--
2"for" tag can iterate over keys
3--TEMPLATE--
4{% for key in items|keys %}
5 * {{ key }}
6{% endfor %}
7--DATA--
8return array('items' => array('a', 'b'))
9--EXPECT--
10 * 0
11 * 1
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys_and_values.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys_and_values.test
new file mode 100644
index 00000000..4c211689
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys_and_values.test
@@ -0,0 +1,11 @@
1--TEST--
2"for" tag can iterate over keys and values
3--TEMPLATE--
4{% for key, item in items %}
5 * {{ key }}/{{ item }}
6{% endfor %}
7--DATA--
8return array('items' => array('a', 'b'))
9--EXPECT--
10 * 0/a
11 * 1/b
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context.test
new file mode 100644
index 00000000..93bc76a1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context.test
@@ -0,0 +1,19 @@
1--TEST--
2"for" tag adds a loop variable to the context
3--TEMPLATE--
4{% for item in items %}
5 * {{ loop.index }}/{{ loop.index0 }}
6 * {{ loop.revindex }}/{{ loop.revindex0 }}
7 * {{ loop.first }}/{{ loop.last }}/{{ loop.length }}
8
9{% endfor %}
10--DATA--
11return array('items' => array('a', 'b'))
12--EXPECT--
13 * 1/0
14 * 2/1
15 * 1//2
16
17 * 2/1
18 * 1/0
19 * /1/2
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context_local.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context_local.test
new file mode 100644
index 00000000..58af2c32
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context_local.test
@@ -0,0 +1,10 @@
1--TEST--
2"for" tag adds a loop variable to the context locally
3--TEMPLATE--
4{% for item in items %}
5{% endfor %}
6{% if loop is not defined %}WORKS{% endif %}
7--DATA--
8return array('items' => array())
9--EXPECT--
10WORKS
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined.test
new file mode 100644
index 00000000..4301ef2f
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined.test
@@ -0,0 +1,10 @@
1--TEST--
2"for" tag
3--TEMPLATE--
4{% for i, item in items if i > 0 %}
5 {{ loop.last }}
6{% endfor %}
7--DATA--
8return array('items' => array('a', 'b'))
9--EXCEPTION--
10Twig_Error_Syntax: The "loop.last" variable is not defined when looping with a condition in "index.twig" at line 3
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined_cond.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined_cond.test
new file mode 100644
index 00000000..c7e723a5
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined_cond.test
@@ -0,0 +1,9 @@
1--TEST--
2"for" tag
3--TEMPLATE--
4{% for i, item in items if loop.last > 0 %}
5{% endfor %}
6--DATA--
7return array('items' => array('a', 'b'))
8--EXCEPTION--
9Twig_Error_Syntax: The "loop" variable cannot be used in a looping condition in "index.twig" at line 2
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/nested_else.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/nested_else.test
new file mode 100644
index 00000000..f8b9f6bc
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/nested_else.test
@@ -0,0 +1,17 @@
1--TEST--
2"for" tag can use an "else" clause
3--TEMPLATE--
4{% for item in items %}
5 {% for item in items1 %}
6 * {{ item }}
7 {% else %}
8 no {{ item }}
9 {% endfor %}
10{% else %}
11 no item1
12{% endfor %}
13--DATA--
14return array('items' => array('a', 'b'), 'items1' => array())
15--EXPECT--
16no a
17 no b
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects.test
new file mode 100644
index 00000000..50344379
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects.test
@@ -0,0 +1,43 @@
1--TEST--
2"for" tag iterates over iterable objects
3--TEMPLATE--
4{% for item in items %}
5 * {{ item }}
6 * {{ loop.index }}/{{ loop.index0 }}
7 * {{ loop.first }}
8
9{% endfor %}
10
11{% for key, value in items %}
12 * {{ key }}/{{ value }}
13{% endfor %}
14
15{% for key in items|keys %}
16 * {{ key }}
17{% endfor %}
18--DATA--
19class ItemsIterator implements Iterator
20{
21 protected $values = array('foo' => 'bar', 'bar' => 'foo');
22 public function current() { return current($this->values); }
23 public function key() { return key($this->values); }
24 public function next() { return next($this->values); }
25 public function rewind() { return reset($this->values); }
26 public function valid() { return false !== current($this->values); }
27}
28return array('items' => new ItemsIterator())
29--EXPECT--
30 * bar
31 * 1/0
32 * 1
33
34 * foo
35 * 2/1
36 *
37
38
39 * foo/bar
40 * bar/foo
41
42 * foo
43 * bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects_countable.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects_countable.test
new file mode 100644
index 00000000..4a1ff611
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects_countable.test
@@ -0,0 +1,47 @@
1--TEST--
2"for" tag iterates over iterable and countable objects
3--TEMPLATE--
4{% for item in items %}
5 * {{ item }}
6 * {{ loop.index }}/{{ loop.index0 }}
7 * {{ loop.revindex }}/{{ loop.revindex0 }}
8 * {{ loop.first }}/{{ loop.last }}/{{ loop.length }}
9
10{% endfor %}
11
12{% for key, value in items %}
13 * {{ key }}/{{ value }}
14{% endfor %}
15
16{% for key in items|keys %}
17 * {{ key }}
18{% endfor %}
19--DATA--
20class ItemsIteratorCountable implements Iterator, Countable
21{
22 protected $values = array('foo' => 'bar', 'bar' => 'foo');
23 public function current() { return current($this->values); }
24 public function key() { return key($this->values); }
25 public function next() { return next($this->values); }
26 public function rewind() { return reset($this->values); }
27 public function valid() { return false !== current($this->values); }
28 public function count() { return count($this->values); }
29}
30return array('items' => new ItemsIteratorCountable())
31--EXPECT--
32 * bar
33 * 1/0
34 * 2/1
35 * 1//2
36
37 * foo
38 * 2/1
39 * 1/0
40 * /1/2
41
42
43 * foo/bar
44 * bar/foo
45
46 * foo
47 * bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/recursive.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/recursive.test
new file mode 100644
index 00000000..17b2e222
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/recursive.test
@@ -0,0 +1,18 @@
1--TEST--
2"for" tags can be nested
3--TEMPLATE--
4{% for key, item in items %}
5* {{ key }} ({{ loop.length }}):
6{% for value in item %}
7 * {{ value }} ({{ loop.length }})
8{% endfor %}
9{% endfor %}
10--DATA--
11return array('items' => array('a' => array('a1', 'a2', 'a3'), 'b' => array('b1')))
12--EXPECT--
13* a (2):
14 * a1 (3)
15 * a2 (3)
16 * a3 (3)
17* b (2):
18 * b1 (1)
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/values.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/values.test
new file mode 100644
index 00000000..82f2ae8a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/values.test
@@ -0,0 +1,11 @@
1--TEST--
2"for" tag iterates over item values
3--TEMPLATE--
4{% for item in items %}
5 * {{ item }}
6{% endfor %}
7--DATA--
8return array('items' => array('a', 'b'))
9--EXPECT--
10 * a
11 * b
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/from.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/from.test
new file mode 100644
index 00000000..5f5da0ec
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/from.test
@@ -0,0 +1,14 @@
1--TEST--
2global variables
3--TEMPLATE--
4{% include "included.twig" %}
5{% from "included.twig" import foobar %}
6{{ foobar() }}
7--TEMPLATE(included.twig)--
8{% macro foobar() %}
9called foobar
10{% endmacro %}
11--DATA--
12return array();
13--EXPECT--
14called foobar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/basic.test
new file mode 100644
index 00000000..c1c3d276
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/basic.test
@@ -0,0 +1,22 @@
1--TEST--
2"if" creates a condition
3--TEMPLATE--
4{% if a is defined %}
5 {{ a }}
6{% elseif b is defined %}
7 {{ b }}
8{% else %}
9 NOTHING
10{% endif %}
11--DATA--
12return array('a' => 'a')
13--EXPECT--
14 a
15--DATA--
16return array('b' => 'b')
17--EXPECT--
18 b
19--DATA--
20return array()
21--EXPECT--
22 NOTHING
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/expression.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/expression.test
new file mode 100644
index 00000000..edfb73df
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/expression.test
@@ -0,0 +1,22 @@
1--TEST--
2"if" takes an expression as a test
3--TEMPLATE--
4{% if a < 2 %}
5 A1
6{% elseif a > 10 %}
7 A2
8{% else %}
9 A3
10{% endif %}
11--DATA--
12return array('a' => 1)
13--EXPECT--
14 A1
15--DATA--
16return array('a' => 12)
17--EXPECT--
18 A2
19--DATA--
20return array('a' => 7)
21--EXPECT--
22 A3
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/basic.test
new file mode 100644
index 00000000..8fe1a6c1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/basic.test
@@ -0,0 +1,16 @@
1--TEST--
2"include" tag
3--TEMPLATE--
4FOO
5{% include "foo.twig" %}
6
7BAR
8--TEMPLATE(foo.twig)--
9FOOBAR
10--DATA--
11return array()
12--EXPECT--
13FOO
14
15FOOBAR
16BAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/expression.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/expression.test
new file mode 100644
index 00000000..eaeeb112
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/expression.test
@@ -0,0 +1,16 @@
1--TEST--
2"include" tag allows expressions for the template to include
3--TEMPLATE--
4FOO
5{% include foo %}
6
7BAR
8--TEMPLATE(foo.twig)--
9FOOBAR
10--DATA--
11return array('foo' => 'foo.twig')
12--EXPECT--
13FOO
14
15FOOBAR
16BAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test
new file mode 100644
index 00000000..24aed06d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test
@@ -0,0 +1,10 @@
1--TEST--
2"include" tag
3--TEMPLATE--
4{% include ["foo.twig", "bar.twig"] ignore missing %}
5{% include "foo.twig" ignore missing %}
6{% include "foo.twig" ignore missing with {} %}
7{% include "foo.twig" ignore missing with {} only %}
8--DATA--
9return array()
10--EXPECT--
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing.test
new file mode 100644
index 00000000..f25e8715
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing.test
@@ -0,0 +1,8 @@
1--TEST--
2"include" tag
3--TEMPLATE--
4{% include "foo.twig" %}
5--DATA--
6return array();
7--EXCEPTION--
8Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2.
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing_nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing_nested.test
new file mode 100644
index 00000000..86c18644
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing_nested.test
@@ -0,0 +1,16 @@
1--TEST--
2"include" tag
3--TEMPLATE--
4{% extends "base.twig" %}
5
6{% block content %}
7 {{ parent() }}
8{% endblock %}
9--TEMPLATE(base.twig)--
10{% block content %}
11 {% include "foo.twig" %}
12{% endblock %}
13--DATA--
14return array();
15--EXCEPTION--
16Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3.
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/only.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/only.test
new file mode 100644
index 00000000..77760a09
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/only.test
@@ -0,0 +1,16 @@
1--TEST--
2"include" tag accept variables and only
3--TEMPLATE--
4{% include "foo.twig" %}
5{% include "foo.twig" only %}
6{% include "foo.twig" with {'foo1': 'bar'} %}
7{% include "foo.twig" with {'foo1': 'bar'} only %}
8--TEMPLATE(foo.twig)--
9{% for k, v in _context %}{{ k }},{% endfor %}
10--DATA--
11return array('foo' => 'bar')
12--EXPECT--
13foo,global,_parent,
14global,_parent,
15foo,global,foo1,_parent,
16foo1,global,_parent,
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/template_instance.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/template_instance.test
new file mode 100644
index 00000000..6ba064a3
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/template_instance.test
@@ -0,0 +1,10 @@
1--TEST--
2"include" tag accepts Twig_Template instance
3--TEMPLATE--
4{% include foo %} FOO
5--TEMPLATE(foo.twig)--
6BAR
7--DATA--
8return array('foo' => $twig->loadTemplate('foo.twig'))
9--EXPECT--
10BAR FOO
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/templates_as_array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/templates_as_array.test
new file mode 100644
index 00000000..ab670ee0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/templates_as_array.test
@@ -0,0 +1,12 @@
1--TEST--
2"include" tag
3--TEMPLATE--
4{% include ["foo.twig", "bar.twig"] %}
5{% include ["bar.twig", "foo.twig"] %}
6--TEMPLATE(foo.twig)--
7foo
8--DATA--
9return array()
10--EXPECT--
11foo
12foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/with_variables.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/with_variables.test
new file mode 100644
index 00000000..41384ac7
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/with_variables.test
@@ -0,0 +1,12 @@
1--TEST--
2"include" tag accept variables
3--TEMPLATE--
4{% include "foo.twig" with {'foo': 'bar'} %}
5{% include "foo.twig" with vars %}
6--TEMPLATE(foo.twig)--
7{{ foo }}
8--DATA--
9return array('vars' => array('foo' => 'bar'))
10--EXPECT--
11bar
12bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/basic.test
new file mode 100644
index 00000000..0778a4b4
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/basic.test
@@ -0,0 +1,14 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends "foo.twig" %}
5
6{% block content %}
7FOO
8{% endblock %}
9--TEMPLATE(foo.twig)--
10{% block content %}{% endblock %}
11--DATA--
12return array()
13--EXPECT--
14FOO
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/conditional.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/conditional.test
new file mode 100644
index 00000000..8576e773
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/conditional.test
@@ -0,0 +1,14 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends standalone ? foo : 'bar.twig' %}
5
6{% block content %}{{ parent() }}FOO{% endblock %}
7--TEMPLATE(foo.twig)--
8{% block content %}FOO{% endblock %}
9--TEMPLATE(bar.twig)--
10{% block content %}BAR{% endblock %}
11--DATA--
12return array('foo' => 'foo.twig', 'standalone' => true)
13--EXPECT--
14FOOFOO
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/dynamic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/dynamic.test
new file mode 100644
index 00000000..ee06ddce
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/dynamic.test
@@ -0,0 +1,14 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends foo %}
5
6{% block content %}
7FOO
8{% endblock %}
9--TEMPLATE(foo.twig)--
10{% block content %}{% endblock %}
11--DATA--
12return array('foo' => 'foo.twig')
13--EXPECT--
14FOO
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/empty.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/empty.test
new file mode 100644
index 00000000..784f3571
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/empty.test
@@ -0,0 +1,10 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends "foo.twig" %}
5--TEMPLATE(foo.twig)--
6{% block content %}FOO{% endblock %}
7--DATA--
8return array()
9--EXPECT--
10FOO
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array.test
new file mode 100644
index 00000000..a1cb1ce8
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array.test
@@ -0,0 +1,12 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends ["foo.twig", "bar.twig"] %}
5--TEMPLATE(bar.twig)--
6{% block content %}
7foo
8{% endblock %}
9--DATA--
10return array()
11--EXPECT--
12foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple.test
new file mode 100644
index 00000000..dfc2b6c4
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple.test
@@ -0,0 +1,12 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends "layout.twig" %}{% block content %}{{ parent() }}index {% endblock %}
5--TEMPLATE(layout.twig)--
6{% extends "base.twig" %}{% block content %}{{ parent() }}layout {% endblock %}
7--TEMPLATE(base.twig)--
8{% block content %}base {% endblock %}
9--DATA--
10return array()
11--EXPECT--
12base layout index
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks.test
new file mode 100644
index 00000000..faca9259
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks.test
@@ -0,0 +1,22 @@
1--TEST--
2"block" tag
3--TEMPLATE--
4{% extends "foo.twig" %}
5
6{% block content %}
7 {% block subcontent %}
8 {% block subsubcontent %}
9 SUBSUBCONTENT
10 {% endblock %}
11 {% endblock %}
12{% endblock %}
13--TEMPLATE(foo.twig)--
14{% block content %}
15 {% block subcontent %}
16 SUBCONTENT
17 {% endblock %}
18{% endblock %}
19--DATA--
20return array()
21--EXPECT--
22SUBSUBCONTENT
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks_parent_only.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks_parent_only.test
new file mode 100644
index 00000000..0ad11d0c
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks_parent_only.test
@@ -0,0 +1,15 @@
1--TEST--
2"block" tag
3--TEMPLATE--
4{% block content %}
5 CONTENT
6 {%- block subcontent -%}
7 SUBCONTENT
8 {%- endblock -%}
9 ENDCONTENT
10{% endblock %}
11--TEMPLATE(foo.twig)--
12--DATA--
13return array()
14--EXPECT--
15CONTENTSUBCONTENTENDCONTENT
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_inheritance.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_inheritance.test
new file mode 100644
index 00000000..71e3cdfd
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_inheritance.test
@@ -0,0 +1,16 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends "layout.twig" %}
5{% block inside %}INSIDE{% endblock inside %}
6--TEMPLATE(layout.twig)--
7{% extends "base.twig" %}
8{% block body %}
9 {% block inside '' %}
10{% endblock body %}
11--TEMPLATE(base.twig)--
12{% block body '' %}
13--DATA--
14return array()
15--EXPECT--
16INSIDE
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent.test
new file mode 100644
index 00000000..4f975db8
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent.test
@@ -0,0 +1,12 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends "foo.twig" %}
5
6{% block content %}{{ parent() }}FOO{{ parent() }}{% endblock %}
7--TEMPLATE(foo.twig)--
8{% block content %}BAR{% endblock %}
9--DATA--
10return array()
11--EXPECT--
12BARFOOBAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_change.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_change.test
new file mode 100644
index 00000000..a8bc90ce
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_change.test
@@ -0,0 +1,16 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends foo ? 'foo.twig' : 'bar.twig' %}
5--TEMPLATE(foo.twig)--
6FOO
7--TEMPLATE(bar.twig)--
8BAR
9--DATA--
10return array('foo' => true)
11--EXPECT--
12FOO
13--DATA--
14return array('foo' => false)
15--EXPECT--
16BAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_in_a_block.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_in_a_block.test
new file mode 100644
index 00000000..c9e86b1a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_in_a_block.test
@@ -0,0 +1,8 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% block content %}
5 {% extends "foo.twig" %}
6{% endblock %}
7--EXCEPTION--
8Twig_Error_Syntax: Cannot extend from a block in "index.twig" at line 3
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_isolation.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_isolation.test
new file mode 100644
index 00000000..62816713
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_isolation.test
@@ -0,0 +1,20 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends "base.twig" %}
5{% block content %}{% include "included.twig" %}{% endblock %}
6
7{% block footer %}Footer{% endblock %}
8--TEMPLATE(included.twig)--
9{% extends "base.twig" %}
10{% block content %}Included Content{% endblock %}
11--TEMPLATE(base.twig)--
12{% block content %}Default Content{% endblock %}
13
14{% block footer %}Default Footer{% endblock %}
15--DATA--
16return array()
17--EXPECT--
18Included Content
19Default Footer
20Footer
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_nested.test
new file mode 100644
index 00000000..71e7c208
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_nested.test
@@ -0,0 +1,28 @@
1--TEST--
2"extends" tag
3--TEMPLATE--
4{% extends "foo.twig" %}
5
6{% block content %}
7 {% block inside %}
8 INSIDE OVERRIDDEN
9 {% endblock %}
10
11 BEFORE
12 {{ parent() }}
13 AFTER
14{% endblock %}
15--TEMPLATE(foo.twig)--
16{% block content %}
17 BAR
18{% endblock %}
19--DATA--
20return array()
21--EXPECT--
22
23INSIDE OVERRIDDEN
24
25 BEFORE
26 BAR
27
28 AFTER
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test
new file mode 100644
index 00000000..a9eaa4c1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test
@@ -0,0 +1,8 @@
1--TEST--
2"parent" tag
3--TEMPLATE--
4{% block content %}
5 {{ parent() }}
6{% endblock %}
7--EXCEPTION--
8Twig_Error_Syntax: Calling "parent" on a template that does not extend nor "use" another template is forbidden in "index.twig" at line 3
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test
new file mode 100644
index 00000000..63c73055
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test
@@ -0,0 +1,14 @@
1--TEST--
2"parent" tag
3--TEMPLATE--
4{% use 'foo.twig' %}
5
6{% block content %}
7 {{ parent() }}
8{% endblock %}
9--TEMPLATE(foo.twig)--
10{% block content %}BAR{% endblock %}
11--DATA--
12return array()
13--EXPECT--
14BAR
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/template_instance.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/template_instance.test
new file mode 100644
index 00000000..d1876a52
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/template_instance.test
@@ -0,0 +1,14 @@
1--TEST--
2"extends" tag accepts Twig_Template instance
3--TEMPLATE--
4{% extends foo %}
5
6{% block content %}
7{{ parent() }}FOO
8{% endblock %}
9--TEMPLATE(foo.twig)--
10{% block content %}BAR{% endblock %}
11--DATA--
12return array('foo' => $twig->loadTemplate('foo.twig'))
13--EXPECT--
14BARFOO
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/use.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/use.test
new file mode 100644
index 00000000..8f9ece7c
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/use.test
@@ -0,0 +1,44 @@
1--TEST--
2"parent" function
3--TEMPLATE--
4{% extends "parent.twig" %}
5
6{% use "use1.twig" %}
7{% use "use2.twig" %}
8
9{% block content_parent %}
10 {{ parent() }}
11{% endblock %}
12
13{% block content_use1 %}
14 {{ parent() }}
15{% endblock %}
16
17{% block content_use2 %}
18 {{ parent() }}
19{% endblock %}
20
21{% block content %}
22 {{ block('content_use1_only') }}
23 {{ block('content_use2_only') }}
24{% endblock %}
25--TEMPLATE(parent.twig)--
26{% block content_parent 'content_parent' %}
27{% block content_use1 'content_parent' %}
28{% block content_use2 'content_parent' %}
29{% block content '' %}
30--TEMPLATE(use1.twig)--
31{% block content_use1 'content_use1' %}
32{% block content_use2 'content_use1' %}
33{% block content_use1_only 'content_use1_only' %}
34--TEMPLATE(use2.twig)--
35{% block content_use2 'content_use2' %}
36{% block content_use2_only 'content_use2_only' %}
37--DATA--
38return array()
39--EXPECT--
40 content_parent
41 content_use1
42 content_use2
43 content_use1_only
44 content_use2_only
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/basic.test
new file mode 100644
index 00000000..eef0c10d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/basic.test
@@ -0,0 +1,17 @@
1--TEST--
2"macro" tag
3--TEMPLATE--
4{% import _self as macros %}
5
6{{ macros.input('username') }}
7{{ macros.input('password', null, 'password', 1) }}
8
9{% macro input(name, value, type, size) %}
10 <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
11{% endmacro %}
12--DATA--
13return array()
14--EXPECT--
15 <input type="text" name="username" value="" size="20">
16
17 <input type="password" name="password" value="" size="1">
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/endmacro_name.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/endmacro_name.test
new file mode 100644
index 00000000..ae6203bb
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/endmacro_name.test
@@ -0,0 +1,16 @@
1--TEST--
2"macro" tag supports name for endmacro
3--TEMPLATE--
4{% import _self as macros %}
5
6{{ macros.foo() }}
7{{ macros.bar() }}
8
9{% macro foo() %}foo{% endmacro %}
10{% macro bar() %}bar{% endmacro bar %}
11--DATA--
12return array()
13--EXPECT--
14foo
15bar
16
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/external.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/external.test
new file mode 100644
index 00000000..5cd3dae6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/external.test
@@ -0,0 +1,17 @@
1--TEST--
2"macro" tag
3--TEMPLATE--
4{% import 'forms.twig' as forms %}
5
6{{ forms.input('username') }}
7{{ forms.input('password', null, 'password', 1) }}
8--TEMPLATE(forms.twig)--
9{% macro input(name, value, type, size) %}
10 <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
11{% endmacro %}
12--DATA--
13return array()
14--EXPECT--
15 <input type="text" name="username" value="" size="20">
16
17 <input type="password" name="password" value="" size="1">
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from.test
new file mode 100644
index 00000000..205f5918
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from.test
@@ -0,0 +1,18 @@
1--TEST--
2"macro" tag
3--TEMPLATE--
4{% from 'forms.twig' import foo %}
5{% from 'forms.twig' import foo as foobar, bar %}
6
7{{ foo('foo') }}
8{{ foobar('foo') }}
9{{ bar('foo') }}
10--TEMPLATE(forms.twig)--
11{% macro foo(name) %}foo{{ name }}{% endmacro %}
12{% macro bar(name) %}bar{{ name }}{% endmacro %}
13--DATA--
14return array()
15--EXPECT--
16foofoo
17foofoo
18barfoo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/global.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/global.test
new file mode 100644
index 00000000..6b371768
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/global.test
@@ -0,0 +1,14 @@
1--TEST--
2"macro" tag
3--TEMPLATE--
4{% from 'forms.twig' import foo %}
5
6{{ foo('foo') }}
7{{ foo() }}
8--TEMPLATE(forms.twig)--
9{% macro foo(name) %}{{ name|default('foo') }}{{ global }}{% endmacro %}
10--DATA--
11return array()
12--EXPECT--
13fooglobal
14fooglobal
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/self_import.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/self_import.test
new file mode 100644
index 00000000..17756cb6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/self_import.test
@@ -0,0 +1,17 @@
1--TEST--
2"macro" tag
3--TEMPLATE--
4{% import _self as forms %}
5
6{{ forms.input('username') }}
7{{ forms.input('password', null, 'password', 1) }}
8
9{% macro input(name, value, type, size) %}
10 <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
11{% endmacro %}
12--DATA--
13return array()
14--EXPECT--
15 <input type="text" name="username" value="" size="20">
16
17 <input type="password" name="password" value="" size="1">
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test
new file mode 100644
index 00000000..37217707
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test
@@ -0,0 +1,14 @@
1--TEST--
2"§" as a macro name
3--TEMPLATE--
4{% import _self as macros %}
5
6{{ macros.§('foo') }}
7
8{% macro §(foo) %}
9 §{{ foo }}§
10{% endmacro %}
11--DATA--
12return array()
13--EXPECT--
14§foo§
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/basic.test
new file mode 100644
index 00000000..0445e853
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/basic.test
@@ -0,0 +1,10 @@
1--TEST--
2"raw" tag
3--TEMPLATE--
4{% raw %}
5{{ foo }}
6{% endraw %}
7--DATA--
8return array()
9--EXPECT--
10{{ foo }}
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/mixed_usage_with_raw.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/mixed_usage_with_raw.test
new file mode 100644
index 00000000..2fd9fb26
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/mixed_usage_with_raw.test
@@ -0,0 +1,10 @@
1--TEST--
2"raw" tag
3--TEMPLATE--
4{% raw %}
5{{ foo }}
6{% endverbatim %}
7--DATA--
8return array()
9--EXCEPTION--
10Twig_Error_Syntax: Unexpected end of file: Unclosed "raw" block in "index.twig" at line 2
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/whitespace_control.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/whitespace_control.test
new file mode 100644
index 00000000..352bb187
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/whitespace_control.test
@@ -0,0 +1,56 @@
1--TEST--
2"raw" tag
3--TEMPLATE--
41***
5
6{%- raw %}
7 {{ 'bla' }}
8{% endraw %}
9
101***
112***
12
13{%- raw -%}
14 {{ 'bla' }}
15{% endraw %}
16
172***
183***
19
20{%- raw -%}
21 {{ 'bla' }}
22{% endraw -%}
23
243***
254***
26
27{%- raw -%}
28 {{ 'bla' }}
29{%- endraw %}
30
314***
325***
33
34{%- raw -%}
35 {{ 'bla' }}
36{%- endraw -%}
37
385***
39--DATA--
40return array()
41--EXPECT--
421***
43 {{ 'bla' }}
44
45
461***
472***{{ 'bla' }}
48
49
502***
513***{{ 'bla' }}
523***
534***{{ 'bla' }}
54
554***
565***{{ 'bla' }}5***
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid1.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid1.test
new file mode 100644
index 00000000..683c59a0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid1.test
@@ -0,0 +1,11 @@
1--TEST--
2sandbox tag
3--TEMPLATE--
4{%- sandbox %}
5 {%- include "foo.twig" %}
6 a
7{%- endsandbox %}
8--TEMPLATE(foo.twig)--
9foo
10--EXCEPTION--
11Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 4
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid2.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid2.test
new file mode 100644
index 00000000..3dcfa88c
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid2.test
@@ -0,0 +1,14 @@
1--TEST--
2sandbox tag
3--TEMPLATE--
4{%- sandbox %}
5 {%- include "foo.twig" %}
6
7 {% if 1 %}
8 {%- include "foo.twig" %}
9 {% endif %}
10{%- endsandbox %}
11--TEMPLATE(foo.twig)--
12foo
13--EXCEPTION--
14Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 5
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/simple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/simple.test
new file mode 100644
index 00000000..de20f3db
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/simple.test
@@ -0,0 +1,22 @@
1--TEST--
2sandbox tag
3--TEMPLATE--
4{%- sandbox %}
5 {%- include "foo.twig" %}
6{%- endsandbox %}
7
8{%- sandbox %}
9 {%- include "foo.twig" %}
10 {%- include "foo.twig" %}
11{%- endsandbox %}
12
13{%- sandbox %}{% include "foo.twig" %}{% endsandbox %}
14--TEMPLATE(foo.twig)--
15foo
16--DATA--
17return array()
18--EXPECT--
19foo
20foo
21foo
22foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/basic.test
new file mode 100644
index 00000000..a5a9f830
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/basic.test
@@ -0,0 +1,20 @@
1--TEST--
2"set" tag
3--TEMPLATE--
4{% set foo = 'foo' %}
5{% set bar = 'foo<br />' %}
6
7{{ foo }}
8{{ bar }}
9
10{% set foo, bar = 'foo', 'bar' %}
11
12{{ foo }}{{ bar }}
13--DATA--
14return array()
15--EXPECT--
16foo
17foo&lt;br /&gt;
18
19
20foobar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture-empty.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture-empty.test
new file mode 100644
index 00000000..ec657f00
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture-empty.test
@@ -0,0 +1,9 @@
1--TEST--
2"set" tag block empty capture
3--TEMPLATE--
4{% set foo %}{% endset %}
5
6{% if foo %}FAIL{% endif %}
7--DATA--
8return array()
9--EXPECT--
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture.test
new file mode 100644
index 00000000..f156a1a7
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture.test
@@ -0,0 +1,10 @@
1--TEST--
2"set" tag block capture
3--TEMPLATE--
4{% set foo %}f<br />o<br />o{% endset %}
5
6{{ foo }}
7--DATA--
8return array()
9--EXPECT--
10f<br />o<br />o
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/expression.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/expression.test
new file mode 100644
index 00000000..8ff434a0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/expression.test
@@ -0,0 +1,12 @@
1--TEST--
2"set" tag
3--TEMPLATE--
4{% set foo, bar = 'foo' ~ 'bar', 'bar' ~ 'foo' %}
5
6{{ foo }}
7{{ bar }}
8--DATA--
9return array()
10--EXPECT--
11foobar
12barfoo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/spaceless/simple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/spaceless/simple.test
new file mode 100644
index 00000000..dd06dec2
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/spaceless/simple.test
@@ -0,0 +1,12 @@
1--TEST--
2"spaceless" tag removes whites between HTML tags
3--TEMPLATE--
4{% spaceless %}
5
6 <div> <div> foo </div> </div>
7
8{% endspaceless %}
9--DATA--
10return array()
11--EXPECT--
12<div><div> foo </div></div>
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test
new file mode 100644
index 00000000..789b4ba8
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test
@@ -0,0 +1,8 @@
1--TEST--
2"§" custom tag
3--TEMPLATE--
4{% § %}
5--DATA--
6return array()
7--EXPECT--
8§
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/trim_block.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/trim_block.test
new file mode 100644
index 00000000..1d2273f8
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/trim_block.test
@@ -0,0 +1,74 @@
1--TEST--
2Whitespace trimming on tags.
3--TEMPLATE--
4{{ 5 * '{#-'|length }}
5{{ '{{-'|length * 5 + '{%-'|length }}
6
7Trim on control tag:
8{% for i in range(1, 9) -%}
9 {{ i }}
10{%- endfor %}
11
12
13Trim on output tag:
14{% for i in range(1, 9) %}
15 {{- i -}}
16{% endfor %}
17
18
19Trim comments:
20
21{#- Invisible -#}
22
23After the comment.
24
25Trim leading space:
26{% if leading %}
27
28 {{- leading }}
29{% endif %}
30
31{%- if leading %}
32 {{- leading }}
33
34{%- endif %}
35
36
37Trim trailing space:
38{% if trailing -%}
39 {{ trailing -}}
40
41{% endif -%}
42
43Combined:
44
45{%- if both -%}
46<ul>
47 <li> {{- both -}} </li>
48</ul>
49
50{%- endif -%}
51
52end
53--DATA--
54return array('leading' => 'leading space', 'trailing' => 'trailing space', 'both' => 'both')
55--EXPECT--
5615
5718
58
59Trim on control tag:
60123456789
61
62Trim on output tag:
63123456789
64
65Trim comments:After the comment.
66
67Trim leading space:
68leading space
69leading space
70
71Trim trailing space:
72trailing spaceCombined:<ul>
73 <li>both</li>
74</ul>end
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/aliases.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/aliases.test
new file mode 100644
index 00000000..f887006f
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/aliases.test
@@ -0,0 +1,12 @@
1--TEST--
2"use" tag
3--TEMPLATE--
4{% use "blocks.twig" with content as foo %}
5
6{{ block('foo') }}
7--TEMPLATE(blocks.twig)--
8{% block content 'foo' %}
9--DATA--
10return array()
11--EXPECT--
12foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/basic.test
new file mode 100644
index 00000000..7364d76d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/basic.test
@@ -0,0 +1,12 @@
1--TEST--
2"use" tag
3--TEMPLATE--
4{% use "blocks.twig" %}
5
6{{ block('content') }}
7--TEMPLATE(blocks.twig)--
8{% block content 'foo' %}
9--DATA--
10return array()
11--EXPECT--
12foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep.test
new file mode 100644
index 00000000..b551a1e6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep.test
@@ -0,0 +1,22 @@
1--TEST--
2"use" tag
3--TEMPLATE--
4{% use "foo.twig" %}
5
6{{ block('content') }}
7{{ block('foo') }}
8{{ block('bar') }}
9--TEMPLATE(foo.twig)--
10{% use "bar.twig" %}
11
12{% block content 'foo' %}
13{% block foo 'foo' %}
14--TEMPLATE(bar.twig)--
15{% block content 'bar' %}
16{% block bar 'bar' %}
17--DATA--
18return array()
19--EXPECT--
20foo
21foo
22bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep_empty.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep_empty.test
new file mode 100644
index 00000000..05cca682
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep_empty.test
@@ -0,0 +1,10 @@
1--TEST--
2"use" tag
3--TEMPLATE--
4{% use "foo.twig" %}
5--TEMPLATE(foo.twig)--
6{% use "bar.twig" %}
7--TEMPLATE(bar.twig)--
8--DATA--
9return array()
10--EXPECT--
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple.test
new file mode 100644
index 00000000..198be0c5
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple.test
@@ -0,0 +1,21 @@
1--TEST--
2"use" tag
3--TEMPLATE--
4{% use "foo.twig" %}
5{% use "bar.twig" %}
6
7{{ block('content') }}
8{{ block('foo') }}
9{{ block('bar') }}
10--TEMPLATE(foo.twig)--
11{% block content 'foo' %}
12{% block foo 'foo' %}
13--TEMPLATE(bar.twig)--
14{% block content 'bar' %}
15{% block bar 'bar' %}
16--DATA--
17return array()
18--EXPECT--
19bar
20foo
21bar
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple_aliases.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple_aliases.test
new file mode 100644
index 00000000..8de871a8
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple_aliases.test
@@ -0,0 +1,23 @@
1--TEST--
2"use" tag
3--TEMPLATE--
4{% use "foo.twig" with content as foo_content %}
5{% use "bar.twig" %}
6
7{{ block('content') }}
8{{ block('foo') }}
9{{ block('bar') }}
10{{ block('foo_content') }}
11--TEMPLATE(foo.twig)--
12{% block content 'foo' %}
13{% block foo 'foo' %}
14--TEMPLATE(bar.twig)--
15{% block content 'bar' %}
16{% block bar 'bar' %}
17--DATA--
18return array()
19--EXPECT--
20bar
21foo
22bar
23foo
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/basic.test
new file mode 100644
index 00000000..a95be557
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/basic.test
@@ -0,0 +1,10 @@
1--TEST--
2"verbatim" tag
3--TEMPLATE--
4{% verbatim %}
5{{ foo }}
6{% endverbatim %}
7--DATA--
8return array()
9--EXPECT--
10{{ foo }}
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/mixed_usage_with_raw.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/mixed_usage_with_raw.test
new file mode 100644
index 00000000..941dddcc
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/mixed_usage_with_raw.test
@@ -0,0 +1,10 @@
1--TEST--
2"verbatim" tag
3--TEMPLATE--
4{% verbatim %}
5{{ foo }}
6{% endraw %}
7--DATA--
8return array()
9--EXCEPTION--
10Twig_Error_Syntax: Unexpected end of file: Unclosed "verbatim" block in "index.twig" at line 2
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/whitespace_control.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/whitespace_control.test
new file mode 100644
index 00000000..eb610444
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/whitespace_control.test
@@ -0,0 +1,56 @@
1--TEST--
2"verbatim" tag
3--TEMPLATE--
41***
5
6{%- verbatim %}
7 {{ 'bla' }}
8{% endverbatim %}
9
101***
112***
12
13{%- verbatim -%}
14 {{ 'bla' }}
15{% endverbatim %}
16
172***
183***
19
20{%- verbatim -%}
21 {{ 'bla' }}
22{% endverbatim -%}
23
243***
254***
26
27{%- verbatim -%}
28 {{ 'bla' }}
29{%- endverbatim %}
30
314***
325***
33
34{%- verbatim -%}
35 {{ 'bla' }}
36{%- endverbatim -%}
37
385***
39--DATA--
40return array()
41--EXPECT--
421***
43 {{ 'bla' }}
44
45
461***
472***{{ 'bla' }}
48
49
502***
513***{{ 'bla' }}
523***
534***{{ 'bla' }}
54
554***
565***{{ 'bla' }}5***
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/array.test
new file mode 100644
index 00000000..1429d375
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/array.test
@@ -0,0 +1,24 @@
1--TEST--
2array index test
3--TEMPLATE--
4{% for key, value in days %}
5{{ key }}
6{% endfor %}
7--DATA--
8return array('days' => array(
9 1 => array('money' => 9),
10 2 => array('money' => 21),
11 3 => array('money' => 38),
12 4 => array('money' => 6),
13 18 => array('money' => 6),
14 19 => array('money' => 3),
15 31 => array('money' => 11),
16));
17--EXPECT--
181
192
203
214
2218
2319
2431
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test
new file mode 100644
index 00000000..60218ac0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test
@@ -0,0 +1,14 @@
1--TEST--
2"const" test
3--TEMPLATE--
4{{ 8 is constant('E_NOTICE') ? 'ok' : 'no' }}
5{{ 'bar' is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }}
6{{ value is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }}
7{{ 2 is constant('ARRAY_AS_PROPS', object) ? 'ok' : 'no' }}
8--DATA--
9return array('value' => 'bar', 'object' => new ArrayObject(array('hi')));
10--EXPECT--
11ok
12ok
13ok
14ok \ No newline at end of file
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/defined.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/defined.test
new file mode 100644
index 00000000..cbfe03de
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/defined.test
@@ -0,0 +1,108 @@
1--TEST--
2"defined" test
3--TEMPLATE--
4{{ definedVar is defined ? 'ok' : 'ko' }}
5{{ definedVar is not defined ? 'ko' : 'ok' }}
6{{ undefinedVar is defined ? 'ko' : 'ok' }}
7{{ undefinedVar is not defined ? 'ok' : 'ko' }}
8{{ zeroVar is defined ? 'ok' : 'ko' }}
9{{ nullVar is defined ? 'ok' : 'ko' }}
10{{ nested.definedVar is defined ? 'ok' : 'ko' }}
11{{ nested['definedVar'] is defined ? 'ok' : 'ko' }}
12{{ nested.definedVar is not defined ? 'ko' : 'ok' }}
13{{ nested.undefinedVar is defined ? 'ko' : 'ok' }}
14{{ nested['undefinedVar'] is defined ? 'ko' : 'ok' }}
15{{ nested.undefinedVar is not defined ? 'ok' : 'ko' }}
16{{ nested.zeroVar is defined ? 'ok' : 'ko' }}
17{{ nested.nullVar is defined ? 'ok' : 'ko' }}
18{{ nested.definedArray.0 is defined ? 'ok' : 'ko' }}
19{{ nested['definedArray'][0] is defined ? 'ok' : 'ko' }}
20{{ object.foo is defined ? 'ok' : 'ko' }}
21{{ object.undefinedMethod is defined ? 'ko' : 'ok' }}
22{{ object.getFoo() is defined ? 'ok' : 'ko' }}
23{{ object.getFoo('a') is defined ? 'ok' : 'ko' }}
24{{ object.undefinedMethod() is defined ? 'ko' : 'ok' }}
25{{ object.undefinedMethod('a') is defined ? 'ko' : 'ok' }}
26{{ object.self.foo is defined ? 'ok' : 'ko' }}
27{{ object.self.undefinedMethod is defined ? 'ko' : 'ok' }}
28{{ object.undefinedMethod.self is defined ? 'ko' : 'ok' }}
29--DATA--
30return array(
31 'definedVar' => 'defined',
32 'zeroVar' => 0,
33 'nullVar' => null,
34 'nested' => array(
35 'definedVar' => 'defined',
36 'zeroVar' => 0,
37 'nullVar' => null,
38 'definedArray' => array(0),
39 ),
40 'object' => new TwigTestFoo(),
41);
42--EXPECT--
43ok
44ok
45ok
46ok
47ok
48ok
49ok
50ok
51ok
52ok
53ok
54ok
55ok
56ok
57ok
58ok
59ok
60ok
61ok
62ok
63ok
64ok
65ok
66ok
67ok
68--DATA--
69return array(
70 'definedVar' => 'defined',
71 'zeroVar' => 0,
72 'nullVar' => null,
73 'nested' => array(
74 'definedVar' => 'defined',
75 'zeroVar' => 0,
76 'nullVar' => null,
77 'definedArray' => array(0),
78 ),
79 'object' => new TwigTestFoo(),
80);
81--CONFIG--
82return array('strict_variables' => false)
83--EXPECT--
84ok
85ok
86ok
87ok
88ok
89ok
90ok
91ok
92ok
93ok
94ok
95ok
96ok
97ok
98ok
99ok
100ok
101ok
102ok
103ok
104ok
105ok
106ok
107ok
108ok
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/empty.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/empty.test
new file mode 100644
index 00000000..a776d032
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/empty.test
@@ -0,0 +1,45 @@
1--TEST--
2"empty" test
3--TEMPLATE--
4{{ foo is empty ? 'ok' : 'ko' }}
5{{ bar is empty ? 'ok' : 'ko' }}
6{{ foobar is empty ? 'ok' : 'ko' }}
7{{ array is empty ? 'ok' : 'ko' }}
8{{ zero is empty ? 'ok' : 'ko' }}
9{{ string is empty ? 'ok' : 'ko' }}
10{{ countable_empty is empty ? 'ok' : 'ko' }}
11{{ countable_not_empty is empty ? 'ok' : 'ko' }}
12{{ markup_empty is empty ? 'ok' : 'ko' }}
13{{ markup_not_empty is empty ? 'ok' : 'ko' }}
14--DATA--
15
16class CountableStub implements Countable
17{
18 private $items;
19
20 public function __construct(array $items)
21 {
22 $this->items = $items;
23 }
24
25 public function count()
26 {
27 return count($this->items);
28 }
29}
30return array(
31 'foo' => '', 'bar' => null, 'foobar' => false, 'array' => array(), 'zero' => 0, 'string' => '0',
32 'countable_empty' => new CountableStub(array()), 'countable_not_empty' => new CountableStub(array(1, 2)),
33 'markup_empty' => new Twig_Markup('', 'UTF-8'), 'markup_not_empty' => new Twig_Markup('test', 'UTF-8'),
34);
35--EXPECT--
36ok
37ok
38ok
39ok
40ko
41ko
42ok
43ko
44ok
45ko
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/even.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/even.test
new file mode 100644
index 00000000..695b4c2f
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/even.test
@@ -0,0 +1,14 @@
1--TEST--
2"even" test
3--TEMPLATE--
4{{ 1 is even ? 'ko' : 'ok' }}
5{{ 2 is even ? 'ok' : 'ko' }}
6{{ 1 is not even ? 'ok' : 'ko' }}
7{{ 2 is not even ? 'ko' : 'ok' }}
8--DATA--
9return array()
10--EXPECT--
11ok
12ok
13ok
14ok
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in.test
new file mode 100644
index 00000000..45c72fd2
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in.test
@@ -0,0 +1,48 @@
1--TEST--
2Twig supports the in operator
3--TEMPLATE--
4{% if bar in foo %}
5TRUE
6{% endif %}
7{% if not (bar in foo) %}
8{% else %}
9TRUE
10{% endif %}
11{% if bar not in foo %}
12{% else %}
13TRUE
14{% endif %}
15{% if 'a' in bar %}
16TRUE
17{% endif %}
18{% if 'c' not in bar %}
19TRUE
20{% endif %}
21{% if '' not in bar %}
22TRUE
23{% endif %}
24{% if '' in '' %}
25TRUE
26{% endif %}
27{% if '0' not in '' %}
28TRUE
29{% endif %}
30{% if 'a' not in '0' %}
31TRUE
32{% endif %}
33{% if '0' in '0' %}
34TRUE
35{% endif %}
36--DATA--
37return array('bar' => 'bar', 'foo' => array('bar' => 'bar'))
38--EXPECT--
39TRUE
40TRUE
41TRUE
42TRUE
43TRUE
44TRUE
45TRUE
46TRUE
47TRUE
48TRUE
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in_with_objects.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in_with_objects.test
new file mode 100644
index 00000000..8e08061b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in_with_objects.test
@@ -0,0 +1,19 @@
1--TEST--
2Twig supports the in operator when using objects
3--TEMPLATE--
4{% if object in object_list %}
5TRUE
6{% endif %}
7--DATA--
8$foo = new TwigTestFoo();
9$foo1 = new TwigTestFoo();
10
11$foo->position = $foo1;
12$foo1->position = $foo;
13
14return array(
15 'object' => $foo,
16 'object_list' => array($foo1, $foo),
17);
18--EXPECT--
19TRUE
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/iterable.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/iterable.test
new file mode 100644
index 00000000..ec525501
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/iterable.test
@@ -0,0 +1,19 @@
1--TEST--
2"iterable" test
3--TEMPLATE--
4{{ foo is iterable ? 'ok' : 'ko' }}
5{{ traversable is iterable ? 'ok' : 'ko' }}
6{{ obj is iterable ? 'ok' : 'ko' }}
7{{ val is iterable ? 'ok' : 'ko' }}
8--DATA--
9return array(
10 'foo' => array(),
11 'traversable' => new ArrayIterator(array()),
12 'obj' => new stdClass(),
13 'val' => 'test',
14);
15--EXPECT--
16ok
17ok
18ko
19ko \ No newline at end of file
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/odd.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/odd.test
new file mode 100644
index 00000000..1b8311e3
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/odd.test
@@ -0,0 +1,10 @@
1--TEST--
2"odd" test
3--TEMPLATE--
4{{ 1 is odd ? 'ok' : 'ko' }}
5{{ 2 is odd ? 'ko' : 'ok' }}
6--DATA--
7return array()
8--EXPECT--
9ok
10ok \ No newline at end of file
diff --git a/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php b/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php
new file mode 100644
index 00000000..5feb8f4e
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php
@@ -0,0 +1,217 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
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// This function is defined to check that escaping strategies
13// like html works even if a function with the same name is defined.
14function html()
15{
16 return 'foo';
17}
18
19class Twig_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
20{
21 public function getExtensions()
22 {
23 $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(), array(), array());
24
25 return array(
26 new Twig_Extension_Debug(),
27 new Twig_Extension_Sandbox($policy, false),
28 new Twig_Extension_StringLoader(),
29 new TwigTestExtension(),
30 );
31 }
32
33 public function getFixturesDir()
34 {
35 return dirname(__FILE__).'/Fixtures/';
36 }
37}
38
39function test_foo($value = 'foo')
40{
41 return $value;
42}
43
44class TwigTestFoo implements Iterator
45{
46 const BAR_NAME = 'bar';
47
48 public $position = 0;
49 public $array = array(1, 2);
50
51 public function bar($param1 = null, $param2 = null)
52 {
53 return 'bar'.($param1 ? '_'.$param1 : '').($param2 ? '-'.$param2 : '');
54 }
55
56 public function getFoo()
57 {
58 return 'foo';
59 }
60
61 public function getSelf()
62 {
63 return $this;
64 }
65
66 public function is()
67 {
68 return 'is';
69 }
70
71 public function in()
72 {
73 return 'in';
74 }
75
76 public function not()
77 {
78 return 'not';
79 }
80
81 public function strToLower($value)
82 {
83 return strtolower($value);
84 }
85
86 public function rewind()
87 {
88 $this->position = 0;
89 }
90
91 public function current()
92 {
93 return $this->array[$this->position];
94 }
95
96 public function key()
97 {
98 return 'a';
99 }
100
101 public function next()
102 {
103 ++$this->position;
104 }
105
106 public function valid()
107 {
108 return isset($this->array[$this->position]);
109 }
110}
111
112class TwigTestTokenParser_§ extends Twig_TokenParser
113{
114 public function parse(Twig_Token $token)
115 {
116 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
117
118 return new Twig_Node_Print(new Twig_Node_Expression_Constant('§', -1), -1);
119 }
120
121 public function getTag()
122 {
123 return '§';
124 }
125}
126
127class TwigTestExtension extends Twig_Extension
128{
129 public function getTokenParsers()
130 {
131 return array(
132 new TwigTestTokenParser_§(),
133 );
134 }
135
136 public function getFilters()
137 {
138 return array(
139 '§' => new Twig_Filter_Method($this, '§Filter'),
140 'escape_and_nl2br' => new Twig_Filter_Method($this, 'escape_and_nl2br', array('needs_environment' => true, 'is_safe' => array('html'))),
141 'nl2br' => new Twig_Filter_Method($this, 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
142 'escape_something' => new Twig_Filter_Method($this, 'escape_something', array('is_safe' => array('something'))),
143 'preserves_safety' => new Twig_Filter_Method($this, 'preserves_safety', array('preserves_safety' => array('html'))),
144 '*_path' => new Twig_Filter_Method($this, 'dynamic_path'),
145 '*_foo_*_bar' => new Twig_Filter_Method($this, 'dynamic_foo'),
146 );
147 }
148
149 public function getFunctions()
150 {
151 return array(
152 '§' => new Twig_Function_Method($this, '§Function'),
153 'safe_br' => new Twig_Function_Method($this, 'br', array('is_safe' => array('html'))),
154 'unsafe_br' => new Twig_Function_Method($this, 'br'),
155 '*_path' => new Twig_Function_Method($this, 'dynamic_path'),
156 '*_foo_*_bar' => new Twig_Function_Method($this, 'dynamic_foo'),
157 );
158 }
159
160 public function §Filter($value)
161 {
162 return "§{$value}§";
163 }
164
165 public function §Function($value)
166 {
167 return "§{$value}§";
168 }
169
170 /**
171 * nl2br which also escapes, for testing escaper filters
172 */
173 public function escape_and_nl2br($env, $value, $sep = '<br />')
174 {
175 return $this->nl2br(twig_escape_filter($env, $value, 'html'), $sep);
176 }
177
178 /**
179 * nl2br only, for testing filters with pre_escape
180 */
181 public function nl2br($value, $sep = '<br />')
182 {
183 // not secure if $value contains html tags (not only entities)
184 // don't use
185 return str_replace("\n", "$sep\n", $value);
186 }
187
188 public function dynamic_path($element, $item)
189 {
190 return $element.'/'.$item;
191 }
192
193 public function dynamic_foo($foo, $bar, $item)
194 {
195 return $foo.'/'.$bar.'/'.$item;
196 }
197
198 public function escape_something($value)
199 {
200 return strtoupper($value);
201 }
202
203 public function preserves_safety($value)
204 {
205 return strtoupper($value);
206 }
207
208 public function br()
209 {
210 return '<br />';
211 }
212
213 public function getName()
214 {
215 return 'integration_test';
216 }
217}
diff --git a/vendor/twig/twig/test/Twig/Tests/LexerTest.php b/vendor/twig/twig/test/Twig/Tests/LexerTest.php
new file mode 100644
index 00000000..9f3c7510
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/LexerTest.php
@@ -0,0 +1,301 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase
12{
13 public function testNameLabelForTag()
14 {
15 $template = '{% § %}';
16
17 $lexer = new Twig_Lexer(new Twig_Environment());
18 $stream = $lexer->tokenize($template);
19
20 $stream->expect(Twig_Token::BLOCK_START_TYPE);
21 $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue());
22 }
23
24 public function testNameLabelForFunction()
25 {
26 $template = '{{ §() }}';
27
28 $lexer = new Twig_Lexer(new Twig_Environment());
29 $stream = $lexer->tokenize($template);
30
31 $stream->expect(Twig_Token::VAR_START_TYPE);
32 $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue());
33 }
34
35 public function testBracketsNesting()
36 {
37 $template = '{{ {"a":{"b":"c"}} }}';
38
39 $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '{'));
40 $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '}'));
41 }
42
43 protected function countToken($template, $type, $value = null)
44 {
45 $lexer = new Twig_Lexer(new Twig_Environment());
46 $stream = $lexer->tokenize($template);
47
48 $count = 0;
49 $tokens = array();
50 while (!$stream->isEOF()) {
51 $token = $stream->next();
52 if ($type === $token->getType()) {
53 if (null === $value || $value === $token->getValue()) {
54 ++$count;
55 }
56 }
57 }
58
59 return $count;
60 }
61
62 public function testLineDirective()
63 {
64 $template = "foo\n"
65 . "bar\n"
66 . "{% line 10 %}\n"
67 . "{{\n"
68 . "baz\n"
69 . "}}\n";
70
71 $lexer = new Twig_Lexer(new Twig_Environment());
72 $stream = $lexer->tokenize($template);
73
74 // foo\nbar\n
75 $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
76 // \n (after {% line %})
77 $this->assertSame(10, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
78 // {{
79 $this->assertSame(11, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine());
80 // baz
81 $this->assertSame(12, $stream->expect(Twig_Token::NAME_TYPE)->getLine());
82 }
83
84 public function testLineDirectiveInline()
85 {
86 $template = "foo\n"
87 . "bar{% line 10 %}{{\n"
88 . "baz\n"
89 . "}}\n";
90
91 $lexer = new Twig_Lexer(new Twig_Environment());
92 $stream = $lexer->tokenize($template);
93
94 // foo\nbar
95 $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
96 // {{
97 $this->assertSame(10, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine());
98 // baz
99 $this->assertSame(11, $stream->expect(Twig_Token::NAME_TYPE)->getLine());
100 }
101
102 public function testLongComments()
103 {
104 $template = '{# '.str_repeat('*', 100000).' #}';
105
106 $lexer = new Twig_Lexer(new Twig_Environment());
107 $lexer->tokenize($template);
108
109 // should not throw an exception
110 }
111
112 public function testLongRaw()
113 {
114 $template = '{% raw %}'.str_repeat('*', 100000).'{% endraw %}';
115
116 $lexer = new Twig_Lexer(new Twig_Environment());
117 $stream = $lexer->tokenize($template);
118
119 // should not throw an exception
120 }
121
122 public function testLongVar()
123 {
124 $template = '{{ '.str_repeat('x', 100000).' }}';
125
126 $lexer = new Twig_Lexer(new Twig_Environment());
127 $stream = $lexer->tokenize($template);
128
129 // should not throw an exception
130 }
131
132 public function testLongBlock()
133 {
134 $template = '{% '.str_repeat('x', 100000).' %}';
135
136 $lexer = new Twig_Lexer(new Twig_Environment());
137 $stream = $lexer->tokenize($template);
138
139 // should not throw an exception
140 }
141
142 public function testBigNumbers()
143 {
144 $template = '{{ 922337203685477580700 }}';
145
146 $lexer = new Twig_Lexer(new Twig_Environment());
147 $stream = $lexer->tokenize($template);
148 $node = $stream->next();
149 $node = $stream->next();
150 $this->assertEquals(922337203685477580700, $node->getValue());
151 }
152
153 public function testStringWithEscapedDelimiter()
154 {
155 $tests = array(
156 "{{ 'foo \' bar' }}" => 'foo \' bar',
157 '{{ "foo \" bar" }}' => "foo \" bar",
158 );
159 $lexer = new Twig_Lexer(new Twig_Environment());
160 foreach ($tests as $template => $expected) {
161 $stream = $lexer->tokenize($template);
162 $stream->expect(Twig_Token::VAR_START_TYPE);
163 $stream->expect(Twig_Token::STRING_TYPE, $expected);
164 }
165 }
166
167 public function testStringWithInterpolation()
168 {
169 $template = 'foo {{ "bar #{ baz + 1 }" }}';
170
171 $lexer = new Twig_Lexer(new Twig_Environment());
172 $stream = $lexer->tokenize($template);
173 $stream->expect(Twig_Token::TEXT_TYPE, 'foo ');
174 $stream->expect(Twig_Token::VAR_START_TYPE);
175 $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
176 $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
177 $stream->expect(Twig_Token::NAME_TYPE, 'baz');
178 $stream->expect(Twig_Token::OPERATOR_TYPE, '+');
179 $stream->expect(Twig_Token::NUMBER_TYPE, '1');
180 $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
181 $stream->expect(Twig_Token::VAR_END_TYPE);
182 }
183
184 public function testStringWithEscapedInterpolation()
185 {
186 $template = '{{ "bar \#{baz+1}" }}';
187
188 $lexer = new Twig_Lexer(new Twig_Environment());
189 $stream = $lexer->tokenize($template);
190 $stream->expect(Twig_Token::VAR_START_TYPE);
191 $stream->expect(Twig_Token::STRING_TYPE, 'bar #{baz+1}');
192 $stream->expect(Twig_Token::VAR_END_TYPE);
193 }
194
195 public function testStringWithHash()
196 {
197 $template = '{{ "bar # baz" }}';
198
199 $lexer = new Twig_Lexer(new Twig_Environment());
200 $stream = $lexer->tokenize($template);
201 $stream->expect(Twig_Token::VAR_START_TYPE);
202 $stream->expect(Twig_Token::STRING_TYPE, 'bar # baz');
203 $stream->expect(Twig_Token::VAR_END_TYPE);
204 }
205
206 /**
207 * @expectedException Twig_Error_Syntax
208 * @expectedExceptionMessage Unclosed """
209 */
210 public function testStringWithUnterminatedInterpolation()
211 {
212 $template = '{{ "bar #{x" }}';
213
214 $lexer = new Twig_Lexer(new Twig_Environment());
215 $stream = $lexer->tokenize($template);
216 }
217
218 public function testStringWithNestedInterpolations()
219 {
220 $template = '{{ "bar #{ "foo#{bar}" }" }}';
221
222 $lexer = new Twig_Lexer(new Twig_Environment());
223 $stream = $lexer->tokenize($template);
224 $stream->expect(Twig_Token::VAR_START_TYPE);
225 $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
226 $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
227 $stream->expect(Twig_Token::STRING_TYPE, 'foo');
228 $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
229 $stream->expect(Twig_Token::NAME_TYPE, 'bar');
230 $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
231 $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
232 $stream->expect(Twig_Token::VAR_END_TYPE);
233 }
234
235 public function testStringWithNestedInterpolationsInBlock()
236 {
237 $template = '{% foo "bar #{ "foo#{bar}" }" %}';
238
239 $lexer = new Twig_Lexer(new Twig_Environment());
240 $stream = $lexer->tokenize($template);
241 $stream->expect(Twig_Token::BLOCK_START_TYPE);
242 $stream->expect(Twig_Token::NAME_TYPE, 'foo');
243 $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
244 $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
245 $stream->expect(Twig_Token::STRING_TYPE, 'foo');
246 $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
247 $stream->expect(Twig_Token::NAME_TYPE, 'bar');
248 $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
249 $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
250 $stream->expect(Twig_Token::BLOCK_END_TYPE);
251 }
252
253 public function testOperatorEndingWithALetterAtTheEndOfALine()
254 {
255 $template = "{{ 1 and\n0}}";
256
257 $lexer = new Twig_Lexer(new Twig_Environment());
258 $stream = $lexer->tokenize($template);
259 $stream->expect(Twig_Token::VAR_START_TYPE);
260 $stream->expect(Twig_Token::NUMBER_TYPE, 1);
261 $stream->expect(Twig_Token::OPERATOR_TYPE, 'and');
262 }
263
264 /**
265 * @expectedException Twig_Error_Syntax
266 * @expectedExceptionMessage Unclosed "variable" at line 3
267 */
268 public function testUnterminatedVariable()
269 {
270 $template = '
271
272{{
273
274bar
275
276
277';
278
279 $lexer = new Twig_Lexer(new Twig_Environment());
280 $stream = $lexer->tokenize($template);
281 }
282
283 /**
284 * @expectedException Twig_Error_Syntax
285 * @expectedExceptionMessage Unclosed "block" at line 3
286 */
287 public function testUnterminatedBlock()
288 {
289 $template = '
290
291{%
292
293bar
294
295
296';
297
298 $lexer = new Twig_Lexer(new Twig_Environment());
299 $stream = $lexer->tokenize($template);
300 }
301}
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/ArrayTest.php b/vendor/twig/twig/test/Twig/Tests/Loader/ArrayTest.php
new file mode 100644
index 00000000..1369a6bd
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/ArrayTest.php
@@ -0,0 +1,97 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Loader_ArrayTest extends PHPUnit_Framework_TestCase
13{
14 public function testGetSource()
15 {
16 $loader = new Twig_Loader_Array(array('foo' => 'bar'));
17
18 $this->assertEquals('bar', $loader->getSource('foo'));
19 }
20
21 /**
22 * @expectedException Twig_Error_Loader
23 */
24 public function testGetSourceWhenTemplateDoesNotExist()
25 {
26 $loader = new Twig_Loader_Array(array());
27
28 $loader->getSource('foo');
29 }
30
31 public function testGetCacheKey()
32 {
33 $loader = new Twig_Loader_Array(array('foo' => 'bar'));
34
35 $this->assertEquals('bar', $loader->getCacheKey('foo'));
36 }
37
38 /**
39 * @expectedException Twig_Error_Loader
40 */
41 public function testGetCacheKeyWhenTemplateDoesNotExist()
42 {
43 $loader = new Twig_Loader_Array(array());
44
45 $loader->getCacheKey('foo');
46 }
47
48 public function testSetTemplate()
49 {
50 $loader = new Twig_Loader_Array(array());
51 $loader->setTemplate('foo', 'bar');
52
53 $this->assertEquals('bar', $loader->getSource('foo'));
54 }
55
56 public function testIsFresh()
57 {
58 $loader = new Twig_Loader_Array(array('foo' => 'bar'));
59 $this->assertTrue($loader->isFresh('foo', time()));
60 }
61
62 /**
63 * @expectedException Twig_Error_Loader
64 */
65 public function testIsFreshWhenTemplateDoesNotExist()
66 {
67 $loader = new Twig_Loader_Array(array());
68
69 $loader->isFresh('foo', time());
70 }
71
72 public function testTemplateReference()
73 {
74 $name = new Twig_Test_Loader_TemplateReference('foo');
75 $loader = new Twig_Loader_Array(array('foo' => 'bar'));
76
77 $loader->getCacheKey($name);
78 $loader->getSource($name);
79 $loader->isFresh($name, time());
80 $loader->setTemplate($name, 'foobar');
81 }
82}
83
84class Twig_Test_Loader_TemplateReference
85{
86 private $name;
87
88 public function __construct($name)
89 {
90 $this->name = $name;
91 }
92
93 public function __toString()
94 {
95 return $this->name;
96 }
97}
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php b/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php
new file mode 100644
index 00000000..4fe0db94
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php
@@ -0,0 +1,79 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Loader_ChainTest extends PHPUnit_Framework_TestCase
13{
14 public function testGetSource()
15 {
16 $loader = new Twig_Loader_Chain(array(
17 new Twig_Loader_Array(array('foo' => 'bar')),
18 new Twig_Loader_Array(array('foo' => 'foobar', 'bar' => 'foo')),
19 ));
20
21 $this->assertEquals('bar', $loader->getSource('foo'));
22 $this->assertEquals('foo', $loader->getSource('bar'));
23 }
24
25 /**
26 * @expectedException Twig_Error_Loader
27 */
28 public function testGetSourceWhenTemplateDoesNotExist()
29 {
30 $loader = new Twig_Loader_Chain(array());
31
32 $loader->getSource('foo');
33 }
34
35 public function testGetCacheKey()
36 {
37 $loader = new Twig_Loader_Chain(array(
38 new Twig_Loader_Array(array('foo' => 'bar')),
39 new Twig_Loader_Array(array('foo' => 'foobar', 'bar' => 'foo')),
40 ));
41
42 $this->assertEquals('bar', $loader->getCacheKey('foo'));
43 $this->assertEquals('foo', $loader->getCacheKey('bar'));
44 }
45
46 /**
47 * @expectedException Twig_Error_Loader
48 */
49 public function testGetCacheKeyWhenTemplateDoesNotExist()
50 {
51 $loader = new Twig_Loader_Chain(array());
52
53 $loader->getCacheKey('foo');
54 }
55
56 public function testAddLoader()
57 {
58 $loader = new Twig_Loader_Chain();
59 $loader->addLoader(new Twig_Loader_Array(array('foo' => 'bar')));
60
61 $this->assertEquals('bar', $loader->getSource('foo'));
62 }
63
64 public function testExists()
65 {
66 $loader1 = $this->getMock('Twig_Loader_Array', array('exists', 'getSource'), array(), '', false);
67 $loader1->expects($this->once())->method('exists')->will($this->returnValue(false));
68 $loader1->expects($this->never())->method('getSource');
69
70 $loader2 = $this->getMock('Twig_LoaderInterface');
71 $loader2->expects($this->once())->method('getSource')->will($this->returnValue('content'));
72
73 $loader = new Twig_Loader_Chain();
74 $loader->addLoader($loader1);
75 $loader->addLoader($loader2);
76
77 $this->assertTrue($loader->exists('foo'));
78 }
79}
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php b/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php
new file mode 100644
index 00000000..4c874b6b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php
@@ -0,0 +1,97 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase
13{
14 /**
15 * @dataProvider getSecurityTests
16 */
17 public function testSecurity($template)
18 {
19 $loader = new Twig_Loader_Filesystem(array(dirname(__FILE__).'/../Fixtures'));
20
21 try {
22 $loader->getCacheKey($template);
23 $this->fail();
24 } catch (Twig_Error_Loader $e) {
25 $this->assertNotContains('Unable to find template', $e->getMessage());
26 }
27 }
28
29 public function getSecurityTests()
30 {
31 return array(
32 array("AutoloaderTest\0.php"),
33 array('..\\AutoloaderTest.php'),
34 array('..\\\\\\AutoloaderTest.php'),
35 array('../AutoloaderTest.php'),
36 array('..////AutoloaderTest.php'),
37 array('./../AutoloaderTest.php'),
38 array('.\\..\\AutoloaderTest.php'),
39 array('././././././../AutoloaderTest.php'),
40 array('.\\./.\\./.\\./../AutoloaderTest.php'),
41 array('foo/../../AutoloaderTest.php'),
42 array('foo\\..\\..\\AutoloaderTest.php'),
43 array('foo/../bar/../../AutoloaderTest.php'),
44 array('foo/bar/../../../AutoloaderTest.php'),
45 array('filters/../../AutoloaderTest.php'),
46 array('filters//..//..//AutoloaderTest.php'),
47 array('filters\\..\\..\\AutoloaderTest.php'),
48 array('filters\\\\..\\\\..\\\\AutoloaderTest.php'),
49 array('filters\\//../\\/\\..\\AutoloaderTest.php'),
50 array('/../AutoloaderTest.php'),
51 );
52 }
53
54 public function testPaths()
55 {
56 $basePath = dirname(__FILE__).'/Fixtures';
57
58 $loader = new Twig_Loader_Filesystem(array($basePath.'/normal', $basePath.'/normal_bis'));
59 $loader->setPaths(array($basePath.'/named', $basePath.'/named_bis'), 'named');
60 $loader->addPath($basePath.'/named_ter', 'named');
61 $loader->addPath($basePath.'/normal_ter');
62 $loader->prependPath($basePath.'/normal_final');
63 $loader->prependPath($basePath.'/named_final', 'named');
64
65 $this->assertEquals(array(
66 $basePath.'/normal_final',
67 $basePath.'/normal',
68 $basePath.'/normal_bis',
69 $basePath.'/normal_ter',
70 ), $loader->getPaths());
71 $this->assertEquals(array(
72 $basePath.'/named_final',
73 $basePath.'/named',
74 $basePath.'/named_bis',
75 $basePath.'/named_ter',
76 ), $loader->getPaths('named'));
77
78 $this->assertEquals("path (final)\n", $loader->getSource('index.html'));
79 $this->assertEquals("path (final)\n", $loader->getSource('@__main__/index.html'));
80 $this->assertEquals("named path (final)\n", $loader->getSource('@named/index.html'));
81 }
82
83 public function testEmptyConstructor()
84 {
85 $loader = new Twig_Loader_Filesystem();
86 $this->assertEquals(array(), $loader->getPaths());
87 }
88
89 public function testGetNamespaces()
90 {
91 $loader = new Twig_Loader_Filesystem(sys_get_temp_dir());
92 $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE), $loader->getNamespaces());
93
94 $loader->addPath(sys_get_temp_dir(), 'named');
95 $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE, 'named'), $loader->getNamespaces());
96 }
97}
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named/index.html
new file mode 100644
index 00000000..9e5449c7
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named/index.html
@@ -0,0 +1 @@
named path
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_bis/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_bis/index.html
new file mode 100644
index 00000000..d3a272b1
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_bis/index.html
@@ -0,0 +1 @@
named path (bis)
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_final/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_final/index.html
new file mode 100644
index 00000000..9f05d150
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_final/index.html
@@ -0,0 +1 @@
named path (final)
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_ter/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_ter/index.html
new file mode 100644
index 00000000..24fb68ad
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_ter/index.html
@@ -0,0 +1 @@
named path (ter)
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal/index.html
new file mode 100644
index 00000000..e7a8fd4d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal/index.html
@@ -0,0 +1 @@
path
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_bis/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_bis/index.html
new file mode 100644
index 00000000..bfa91604
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_bis/index.html
@@ -0,0 +1 @@
path (bis)
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_final/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_final/index.html
new file mode 100644
index 00000000..73a089bb
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_final/index.html
@@ -0,0 +1 @@
path (final)
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_ter/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_ter/index.html
new file mode 100644
index 00000000..b7ad97d8
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_ter/index.html
@@ -0,0 +1 @@
path (ter)
diff --git a/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php b/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php
new file mode 100644
index 00000000..3fafd335
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php
@@ -0,0 +1,29 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_NativeExtensionTest extends PHPUnit_Framework_TestCase
13{
14 public function testGetProperties()
15 {
16 $twig = new Twig_Environment(new Twig_Loader_String(), array(
17 'debug' => true,
18 'cache' => false,
19 'autoescape' => false
20 ));
21
22 $d1 = new DateTime();
23 $d2 = new DateTime();
24 $output = $twig->render('{{ d1.date }}{{ d2.date }}', compact('d1', 'd2'));
25
26 // If it fails, PHP will crash.
27 $this->assertEquals($output, $d1->date . $d2->date);
28 }
29}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/AutoEscapeTest.php b/vendor/twig/twig/test/Twig/Tests/Node/AutoEscapeTest.php
new file mode 100644
index 00000000..608446bc
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/AutoEscapeTest.php
@@ -0,0 +1,44 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_AutoEscapeTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_AutoEscape::__construct
16 */
17 public function testConstructor()
18 {
19 $body = new Twig_Node(array(new Twig_Node_Text('foo', 1)));
20 $node = new Twig_Node_AutoEscape(true, $body, 1);
21
22 $this->assertEquals($body, $node->getNode('body'));
23 $this->assertEquals(true, $node->getAttribute('value'));
24 }
25
26 /**
27 * @covers Twig_Node_AutoEscape::compile
28 * @dataProvider getTests
29 */
30 public function testCompile($node, $source, $environment = null)
31 {
32 parent::testCompile($node, $source, $environment);
33 }
34
35 public function getTests()
36 {
37 $body = new Twig_Node(array(new Twig_Node_Text('foo', 1)));
38 $node = new Twig_Node_AutoEscape(true, $body, 1);
39
40 return array(
41 array($node, "// line 1\necho \"foo\";"),
42 );
43 }
44}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/BlockReferenceTest.php b/vendor/twig/twig/test/Twig/Tests/Node/BlockReferenceTest.php
new file mode 100644
index 00000000..96d0e101
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/BlockReferenceTest.php
@@ -0,0 +1,43 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_BlockReferenceTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_BlockReference::__construct
16 */
17 public function testConstructor()
18 {
19 $node = new Twig_Node_BlockReference('foo', 1);
20
21 $this->assertEquals('foo', $node->getAttribute('name'));
22 }
23
24 /**
25 * @covers Twig_Node_BlockReference::compile
26 * @dataProvider getTests
27 */
28 public function testCompile($node, $source, $environment = null)
29 {
30 parent::testCompile($node, $source, $environment);
31 }
32
33 public function getTests()
34 {
35 return array(
36 array(new Twig_Node_BlockReference('foo', 1), <<<EOF
37// line 1
38\$this->displayBlock('foo', \$context, \$blocks);
39EOF
40 ),
41 );
42 }
43}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/BlockTest.php b/vendor/twig/twig/test/Twig/Tests/Node/BlockTest.php
new file mode 100644
index 00000000..024049de
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/BlockTest.php
@@ -0,0 +1,51 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_BlockTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Block::__construct
16 */
17 public function testConstructor()
18 {
19 $body = new Twig_Node_Text('foo', 1);
20 $node = new Twig_Node_Block('foo', $body, 1);
21
22 $this->assertEquals($body, $node->getNode('body'));
23 $this->assertEquals('foo', $node->getAttribute('name'));
24 }
25
26 /**
27 * @covers Twig_Node_Block::compile
28 * @dataProvider getTests
29 */
30 public function testCompile($node, $source, $environment = null)
31 {
32 parent::testCompile($node, $source, $environment);
33 }
34
35 public function getTests()
36 {
37 $body = new Twig_Node_Text('foo', 1);
38 $node = new Twig_Node_Block('foo', $body, 1);
39
40 return array(
41 array($node, <<<EOF
42// line 1
43public function block_foo(\$context, array \$blocks = array())
44{
45 echo "foo";
46}
47EOF
48 ),
49 );
50 }
51}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/DoTest.php b/vendor/twig/twig/test/Twig/Tests/Node/DoTest.php
new file mode 100644
index 00000000..a406e22d
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/DoTest.php
@@ -0,0 +1,44 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_DoTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Do::__construct
16 */
17 public function testConstructor()
18 {
19 $expr = new Twig_Node_Expression_Constant('foo', 1);
20 $node = new Twig_Node_Do($expr, 1);
21
22 $this->assertEquals($expr, $node->getNode('expr'));
23 }
24
25 /**
26 * @covers Twig_Node_Do::compile
27 * @dataProvider getTests
28 */
29 public function testCompile($node, $source, $environment = null)
30 {
31 parent::testCompile($node, $source, $environment);
32 }
33
34 public function getTests()
35 {
36 $tests = array();
37
38 $expr = new Twig_Node_Expression_Constant('foo', 1);
39 $node = new Twig_Node_Do($expr, 1);
40 $tests[] = array($node, "// line 1\n\"foo\";");
41
42 return $tests;
43 }
44}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/ArrayTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ArrayTest.php
new file mode 100644
index 00000000..c6a9044b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ArrayTest.php
@@ -0,0 +1,49 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_ArrayTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Array::__construct
16 */
17 public function testConstructor()
18 {
19 $elements = array(new Twig_Node_Expression_Constant('foo', 1), $foo = new Twig_Node_Expression_Constant('bar', 1));
20 $node = new Twig_Node_Expression_Array($elements, 1);
21
22 $this->assertEquals($foo, $node->getNode(1));
23 }
24
25 /**
26 * @covers Twig_Node_Expression_Array::compile
27 * @dataProvider getTests
28 */
29 public function testCompile($node, $source, $environment = null)
30 {
31 parent::testCompile($node, $source, $environment);
32 }
33
34 public function getTests()
35 {
36 $elements = array(
37 new Twig_Node_Expression_Constant('foo', 1),
38 new Twig_Node_Expression_Constant('bar', 1),
39
40 new Twig_Node_Expression_Constant('bar', 1),
41 new Twig_Node_Expression_Constant('foo', 1),
42 );
43 $node = new Twig_Node_Expression_Array($elements, 1);
44
45 return array(
46 array($node, 'array("foo" => "bar", "bar" => "foo")'),
47 );
48 }
49}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/AssignNameTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/AssignNameTest.php
new file mode 100644
index 00000000..b156dcc0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/AssignNameTest.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_AssignNameTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_AssignName::__construct
16 */
17 public function testConstructor()
18 {
19 $node = new Twig_Node_Expression_AssignName('foo', 1);
20
21 $this->assertEquals('foo', $node->getAttribute('name'));
22 }
23
24 /**
25 * @covers Twig_Node_Expression_AssignName::compile
26 * @dataProvider getTests
27 */
28 public function testCompile($node, $source, $environment = null)
29 {
30 parent::testCompile($node, $source, $environment);
31 }
32
33 public function getTests()
34 {
35 $node = new Twig_Node_Expression_AssignName('foo', 1);
36
37 return array(
38 array($node, '$context["foo"]'),
39 );
40 }
41}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AddTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AddTest.php
new file mode 100644
index 00000000..a0f49cb3
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AddTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Binary_AddTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Binary_Add::__construct
16 */
17 public function testConstructor()
18 {
19 $left = new Twig_Node_Expression_Constant(1, 1);
20 $right = new Twig_Node_Expression_Constant(2, 1);
21 $node = new Twig_Node_Expression_Binary_Add($left, $right, 1);
22
23 $this->assertEquals($left, $node->getNode('left'));
24 $this->assertEquals($right, $node->getNode('right'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Binary_Add::compile
29 * @covers Twig_Node_Expression_Binary_Add::operator
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $left = new Twig_Node_Expression_Constant(1, 1);
40 $right = new Twig_Node_Expression_Constant(2, 1);
41 $node = new Twig_Node_Expression_Binary_Add($left, $right, 1);
42
43 return array(
44 array($node, '(1 + 2)'),
45 );
46 }
47}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AndTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AndTest.php
new file mode 100644
index 00000000..50e551a7
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AndTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Binary_AndTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Binary_And::__construct
16 */
17 public function testConstructor()
18 {
19 $left = new Twig_Node_Expression_Constant(1, 1);
20 $right = new Twig_Node_Expression_Constant(2, 1);
21 $node = new Twig_Node_Expression_Binary_And($left, $right, 1);
22
23 $this->assertEquals($left, $node->getNode('left'));
24 $this->assertEquals($right, $node->getNode('right'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Binary_And::compile
29 * @covers Twig_Node_Expression_Binary_And::operator
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $left = new Twig_Node_Expression_Constant(1, 1);
40 $right = new Twig_Node_Expression_Constant(2, 1);
41 $node = new Twig_Node_Expression_Binary_And($left, $right, 1);
42
43 return array(
44 array($node, '(1 && 2)'),
45 );
46 }
47}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ConcatTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ConcatTest.php
new file mode 100644
index 00000000..140329fa
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ConcatTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Binary_ConcatTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Binary_Concat::__construct
16 */
17 public function testConstructor()
18 {
19 $left = new Twig_Node_Expression_Constant(1, 1);
20 $right = new Twig_Node_Expression_Constant(2, 1);
21 $node = new Twig_Node_Expression_Binary_Concat($left, $right, 1);
22
23 $this->assertEquals($left, $node->getNode('left'));
24 $this->assertEquals($right, $node->getNode('right'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Binary_Concat::compile
29 * @covers Twig_Node_Expression_Binary_Concat::operator
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $left = new Twig_Node_Expression_Constant(1, 1);
40 $right = new Twig_Node_Expression_Constant(2, 1);
41 $node = new Twig_Node_Expression_Binary_Concat($left, $right, 1);
42
43 return array(
44 array($node, '(1 . 2)'),
45 );
46 }
47}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/DivTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/DivTest.php
new file mode 100644
index 00000000..0c1a3c7f
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/DivTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Binary_DivTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Binary_Div::__construct
16 */
17 public function testConstructor()
18 {
19 $left = new Twig_Node_Expression_Constant(1, 1);
20 $right = new Twig_Node_Expression_Constant(2, 1);
21 $node = new Twig_Node_Expression_Binary_Div($left, $right, 1);
22
23 $this->assertEquals($left, $node->getNode('left'));
24 $this->assertEquals($right, $node->getNode('right'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Binary_Div::compile
29 * @covers Twig_Node_Expression_Binary_Div::operator
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $left = new Twig_Node_Expression_Constant(1, 1);
40 $right = new Twig_Node_Expression_Constant(2, 1);
41 $node = new Twig_Node_Expression_Binary_Div($left, $right, 1);
42
43 return array(
44 array($node, '(1 / 2)'),
45 );
46 }
47}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/FloorDivTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/FloorDivTest.php
new file mode 100644
index 00000000..ead1fde8
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/FloorDivTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Binary_FloorDivTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Binary_FloorDiv::__construct
16 */
17 public function testConstructor()
18 {
19 $left = new Twig_Node_Expression_Constant(1, 1);
20 $right = new Twig_Node_Expression_Constant(2, 1);
21 $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 1);
22
23 $this->assertEquals($left, $node->getNode('left'));
24 $this->assertEquals($right, $node->getNode('right'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Binary_FloorDiv::compile
29 * @covers Twig_Node_Expression_Binary_FloorDiv::operator
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $left = new Twig_Node_Expression_Constant(1, 1);
40 $right = new Twig_Node_Expression_Constant(2, 1);
41 $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 1);
42
43 return array(
44 array($node, 'intval(floor((1 / 2)))'),
45 );
46 }
47}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ModTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ModTest.php
new file mode 100644
index 00000000..4fe1a1fc
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ModTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Binary_ModTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Binary_Mod::__construct
16 */
17 public function testConstructor()
18 {
19 $left = new Twig_Node_Expression_Constant(1, 1);
20 $right = new Twig_Node_Expression_Constant(2, 1);
21 $node = new Twig_Node_Expression_Binary_Mod($left, $right, 1);
22
23 $this->assertEquals($left, $node->getNode('left'));
24 $this->assertEquals($right, $node->getNode('right'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Binary_Mod::compile
29 * @covers Twig_Node_Expression_Binary_Mod::operator
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $left = new Twig_Node_Expression_Constant(1, 1);
40 $right = new Twig_Node_Expression_Constant(2, 1);
41 $node = new Twig_Node_Expression_Binary_Mod($left, $right, 1);
42
43 return array(
44 array($node, '(1 % 2)'),
45 );
46 }
47}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/MulTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/MulTest.php
new file mode 100644
index 00000000..12bb35c9
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/MulTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Binary_MulTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Binary_Mul::__construct
16 */
17 public function testConstructor()
18 {
19 $left = new Twig_Node_Expression_Constant(1, 1);
20 $right = new Twig_Node_Expression_Constant(2, 1);
21 $node = new Twig_Node_Expression_Binary_Mul($left, $right, 1);
22
23 $this->assertEquals($left, $node->getNode('left'));
24 $this->assertEquals($right, $node->getNode('right'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Binary_Mul::compile
29 * @covers Twig_Node_Expression_Binary_Mul::operator
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $left = new Twig_Node_Expression_Constant(1, 1);
40 $right = new Twig_Node_Expression_Constant(2, 1);
41 $node = new Twig_Node_Expression_Binary_Mul($left, $right, 1);
42
43 return array(
44 array($node, '(1 * 2)'),
45 );
46 }
47}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/OrTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/OrTest.php
new file mode 100644
index 00000000..9534c41c
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/OrTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Binary_OrTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Binary_Or::__construct
16 */
17 public function testConstructor()
18 {
19 $left = new Twig_Node_Expression_Constant(1, 1);
20 $right = new Twig_Node_Expression_Constant(2, 1);
21 $node = new Twig_Node_Expression_Binary_Or($left, $right, 1);
22
23 $this->assertEquals($left, $node->getNode('left'));
24 $this->assertEquals($right, $node->getNode('right'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Binary_Or::compile
29 * @covers Twig_Node_Expression_Binary_Or::operator
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $left = new Twig_Node_Expression_Constant(1, 1);
40 $right = new Twig_Node_Expression_Constant(2, 1);
41 $node = new Twig_Node_Expression_Binary_Or($left, $right, 1);
42
43 return array(
44 array($node, '(1 || 2)'),
45 );
46 }
47}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/SubTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/SubTest.php
new file mode 100644
index 00000000..9074893b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/SubTest.php
@@ -0,0 +1,47 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Binary_SubTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Binary_Sub::__construct
16 */
17 public function testConstructor()
18 {
19 $left = new Twig_Node_Expression_Constant(1, 1);
20 $right = new Twig_Node_Expression_Constant(2, 1);
21 $node = new Twig_Node_Expression_Binary_Sub($left, $right, 1);
22
23 $this->assertEquals($left, $node->getNode('left'));
24 $this->assertEquals($right, $node->getNode('right'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Binary_Sub::compile
29 * @covers Twig_Node_Expression_Binary_Sub::operator
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $left = new Twig_Node_Expression_Constant(1, 1);
40 $right = new Twig_Node_Expression_Constant(2, 1);
41 $node = new Twig_Node_Expression_Binary_Sub($left, $right, 1);
42
43 return array(
44 array($node, '(1 - 2)'),
45 );
46 }
47}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php
new file mode 100644
index 00000000..53b5e6ee
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php
@@ -0,0 +1,67 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_CallTest extends PHPUnit_Framework_TestCase
13{
14 public function testGetArguments()
15 {
16 $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
17 $this->assertEquals(array('U'), $node->getArguments('date', array('format' => 'U')));
18 }
19
20 /**
21 * @expectedException Twig_Error_Syntax
22 * @expectedExceptionMessage Positional arguments cannot be used after named arguments for function "date".
23 */
24 public function testGetArgumentsWhenPositionalArgumentsAfterNamedArguments()
25 {
26 $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
27 $node->getArguments('date', array('timestamp' => 123456, 'Y-m-d'));
28 }
29
30 /**
31 * @expectedException Twig_Error_Syntax
32 * @expectedExceptionMessage Argument "format" is defined twice for function "date".
33 */
34 public function testGetArgumentsWhenArgumentIsDefinedTwice()
35 {
36 $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
37 $node->getArguments('date', array('Y-m-d', 'format' => 'U'));
38 }
39
40 /**
41 * @expectedException Twig_Error_Syntax
42 * @expectedExceptionMessage Unknown argument "unknown" for function "date".
43 */
44 public function testGetArgumentsWithWrongNamedArgumentName()
45 {
46 $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
47 $node->getArguments('date', array('Y-m-d', 'unknown' => ''));
48 }
49
50 /**
51 * @expectedException Twig_Error_Syntax
52 * @expectedExceptionMessage Unknown arguments "unknown1", "unknown2" for function "date".
53 */
54 public function testGetArgumentsWithWrongNamedArgumentNames()
55 {
56 $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
57 $node->getArguments('date', array('Y-m-d', 'unknown1' => '', 'unknown2' => ''));
58 }
59}
60
61class Twig_Tests_Node_Expression_Call extends Twig_Node_Expression_Call
62{
63 public function getArguments($callable, $arguments)
64 {
65 return parent::getArguments($callable, $arguments);
66 }
67}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConditionalTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConditionalTest.php
new file mode 100644
index 00000000..9906d512
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConditionalTest.php
@@ -0,0 +1,50 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_ConditionalTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Conditional::__construct
16 */
17 public function testConstructor()
18 {
19 $expr1 = new Twig_Node_Expression_Constant(1, 1);
20 $expr2 = new Twig_Node_Expression_Constant(2, 1);
21 $expr3 = new Twig_Node_Expression_Constant(3, 1);
22 $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 1);
23
24 $this->assertEquals($expr1, $node->getNode('expr1'));
25 $this->assertEquals($expr2, $node->getNode('expr2'));
26 $this->assertEquals($expr3, $node->getNode('expr3'));
27 }
28
29 /**
30 * @covers Twig_Node_Expression_Conditional::compile
31 * @dataProvider getTests
32 */
33 public function testCompile($node, $source, $environment = null)
34 {
35 parent::testCompile($node, $source, $environment);
36 }
37
38 public function getTests()
39 {
40 $tests = array();
41
42 $expr1 = new Twig_Node_Expression_Constant(1, 1);
43 $expr2 = new Twig_Node_Expression_Constant(2, 1);
44 $expr3 = new Twig_Node_Expression_Constant(3, 1);
45 $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 1);
46 $tests[] = array($node, '((1) ? (2) : (3))');
47
48 return $tests;
49 }
50}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConstantTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConstantTest.php
new file mode 100644
index 00000000..d0dec531
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConstantTest.php
@@ -0,0 +1,42 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_ConstantTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Constant::__construct
16 */
17 public function testConstructor()
18 {
19 $node = new Twig_Node_Expression_Constant('foo', 1);
20
21 $this->assertEquals('foo', $node->getAttribute('value'));
22 }
23
24 /**
25 * @covers Twig_Node_Expression_Constant::compile
26 * @dataProvider getTests
27 */
28 public function testCompile($node, $source, $environment = null)
29 {
30 parent::testCompile($node, $source, $environment);
31 }
32
33 public function getTests()
34 {
35 $tests = array();
36
37 $node = new Twig_Node_Expression_Constant('foo', 1);
38 $tests[] = array($node, '"foo"');
39
40 return $tests;
41 }
42}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php
new file mode 100644
index 00000000..8089b9cb
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php
@@ -0,0 +1,133 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Filter::__construct
16 */
17 public function testConstructor()
18 {
19 $expr = new Twig_Node_Expression_Constant('foo', 1);
20 $name = new Twig_Node_Expression_Constant('upper', 1);
21 $args = new Twig_Node();
22 $node = new Twig_Node_Expression_Filter($expr, $name, $args, 1);
23
24 $this->assertEquals($expr, $node->getNode('node'));
25 $this->assertEquals($name, $node->getNode('filter'));
26 $this->assertEquals($args, $node->getNode('arguments'));
27 }
28
29 /**
30 * @covers Twig_Node_Expression_Filter::compile
31 * @dataProvider getTests
32 */
33 public function testCompile($node, $source, $environment = null)
34 {
35 parent::testCompile($node, $source, $environment);
36 }
37
38 public function getTests()
39 {
40 $tests = array();
41
42 $expr = new Twig_Node_Expression_Constant('foo', 1);
43 $node = $this->createFilter($expr, 'upper');
44 $node = $this->createFilter($node, 'number_format', array(new Twig_Node_Expression_Constant(2, 1), new Twig_Node_Expression_Constant('.', 1), new Twig_Node_Expression_Constant(',', 1)));
45
46 if (function_exists('mb_get_info')) {
47 $tests[] = array($node, 'twig_number_format_filter($this->env, twig_upper_filter($this->env, "foo"), 2, ".", ",")');
48 } else {
49 $tests[] = array($node, 'twig_number_format_filter($this->env, strtoupper("foo"), 2, ".", ",")');
50 }
51
52 // named arguments
53 $date = new Twig_Node_Expression_Constant(0, 1);
54 $node = $this->createFilter($date, 'date', array(
55 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
56 'format' => new Twig_Node_Expression_Constant('d/m/Y H:i:s P', 1),
57 ));
58 $tests[] = array($node, 'twig_date_format_filter($this->env, 0, "d/m/Y H:i:s P", "America/Chicago")');
59
60 // skip an optional argument
61 $date = new Twig_Node_Expression_Constant(0, 1);
62 $node = $this->createFilter($date, 'date', array(
63 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
64 ));
65 $tests[] = array($node, 'twig_date_format_filter($this->env, 0, null, "America/Chicago")');
66
67 // underscores vs camelCase for named arguments
68 $string = new Twig_Node_Expression_Constant('abc', 1);
69 $node = $this->createFilter($string, 'reverse', array(
70 'preserve_keys' => new Twig_Node_Expression_Constant(true, 1),
71 ));
72 $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)');
73 $node = $this->createFilter($string, 'reverse', array(
74 'preserveKeys' => new Twig_Node_Expression_Constant(true, 1),
75 ));
76 $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)');
77
78 // filter as an anonymous function
79 if (version_compare(phpversion(), '5.3.0', '>=')) {
80 $node = $this->createFilter(new Twig_Node_Expression_Constant('foo', 1), 'anonymous');
81 $tests[] = array($node, 'call_user_func_array($this->env->getFilter(\'anonymous\')->getCallable(), array("foo"))');
82 }
83
84 return $tests;
85 }
86
87 /**
88 * @expectedException Twig_Error_Syntax
89 * @expectedExceptionMessage Unknown argument "foobar" for filter "date".
90 */
91 public function testCompileWithWrongNamedArgumentName()
92 {
93 $date = new Twig_Node_Expression_Constant(0, 1);
94 $node = $this->createFilter($date, 'date', array(
95 'foobar' => new Twig_Node_Expression_Constant('America/Chicago', 1),
96 ));
97
98 $compiler = $this->getCompiler();
99 $compiler->compile($node);
100 }
101
102 /**
103 * @expectedException Twig_Error_Syntax
104 * @expectedExceptionMessage Value for argument "from" is required for filter "replace".
105 */
106 public function testCompileWithMissingNamedArgument()
107 {
108 $value = new Twig_Node_Expression_Constant(0, 1);
109 $node = $this->createFilter($value, 'replace', array(
110 'to' => new Twig_Node_Expression_Constant('foo', 1),
111 ));
112
113 $compiler = $this->getCompiler();
114 $compiler->compile($node);
115 }
116
117 protected function createFilter($node, $name, array $arguments = array())
118 {
119 $name = new Twig_Node_Expression_Constant($name, 1);
120 $arguments = new Twig_Node($arguments);
121
122 return new Twig_Node_Expression_Filter($node, $name, $arguments, 1);
123 }
124
125 protected function getEnvironment()
126 {
127 if (version_compare(phpversion(), '5.3.0', '>=')) {
128 return include 'PHP53/FilterInclude.php';
129 }
130
131 return parent::getEnvironment();
132 }
133}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php
new file mode 100644
index 00000000..431dc387
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php
@@ -0,0 +1,99 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Function::__construct
16 */
17 public function testConstructor()
18 {
19 $name = 'function';
20 $args = new Twig_Node();
21 $node = new Twig_Node_Expression_Function($name, $args, 1);
22
23 $this->assertEquals($name, $node->getAttribute('name'));
24 $this->assertEquals($args, $node->getNode('arguments'));
25 }
26
27 /**
28 * @covers Twig_Node_Expression_Function::compile
29 * @dataProvider getTests
30 */
31 public function testCompile($node, $source, $environment = null)
32 {
33 parent::testCompile($node, $source, $environment);
34 }
35
36 public function getTests()
37 {
38 $environment = new Twig_Environment();
39 $environment->addFunction('foo', new Twig_Function_Function('foo', array()));
40 $environment->addFunction('bar', new Twig_Function_Function('bar', array('needs_environment' => true)));
41 $environment->addFunction('foofoo', new Twig_Function_Function('foofoo', array('needs_context' => true)));
42 $environment->addFunction('foobar', new Twig_Function_Function('foobar', array('needs_environment' => true, 'needs_context' => true)));
43
44 $tests = array();
45
46 $node = $this->createFunction('foo');
47 $tests[] = array($node, 'foo()', $environment);
48
49 $node = $this->createFunction('foo', array(new Twig_Node_Expression_Constant('bar', 1), new Twig_Node_Expression_Constant('foobar', 1)));
50 $tests[] = array($node, 'foo("bar", "foobar")', $environment);
51
52 $node = $this->createFunction('bar');
53 $tests[] = array($node, 'bar($this->env)', $environment);
54
55 $node = $this->createFunction('bar', array(new Twig_Node_Expression_Constant('bar', 1)));
56 $tests[] = array($node, 'bar($this->env, "bar")', $environment);
57
58 $node = $this->createFunction('foofoo');
59 $tests[] = array($node, 'foofoo($context)', $environment);
60
61 $node = $this->createFunction('foofoo', array(new Twig_Node_Expression_Constant('bar', 1)));
62 $tests[] = array($node, 'foofoo($context, "bar")', $environment);
63
64 $node = $this->createFunction('foobar');
65 $tests[] = array($node, 'foobar($this->env, $context)', $environment);
66
67 $node = $this->createFunction('foobar', array(new Twig_Node_Expression_Constant('bar', 1)));
68 $tests[] = array($node, 'foobar($this->env, $context, "bar")', $environment);
69
70 // named arguments
71 $node = $this->createFunction('date', array(
72 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
73 'date' => new Twig_Node_Expression_Constant(0, 1),
74 ));
75 $tests[] = array($node, 'twig_date_converter($this->env, 0, "America/Chicago")');
76
77 // function as an anonymous function
78 if (version_compare(phpversion(), '5.3.0', '>=')) {
79 $node = $this->createFunction('anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
80 $tests[] = array($node, 'call_user_func_array($this->env->getFunction(\'anonymous\')->getCallable(), array("foo"))');
81 }
82
83 return $tests;
84 }
85
86 protected function createFunction($name, array $arguments = array())
87 {
88 return new Twig_Node_Expression_Function($name, new Twig_Node($arguments), 1);
89 }
90
91 protected function getEnvironment()
92 {
93 if (version_compare(phpversion(), '5.3.0', '>=')) {
94 return include 'PHP53/FunctionInclude.php';
95 }
96
97 return parent::getEnvironment();
98 }
99}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php
new file mode 100644
index 00000000..6a63cce6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php
@@ -0,0 +1,62 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_GetAttrTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_GetAttr::__construct
16 */
17 public function testConstructor()
18 {
19 $expr = new Twig_Node_Expression_Name('foo', 1);
20 $attr = new Twig_Node_Expression_Constant('bar', 1);
21 $args = new Twig_Node_Expression_Array(array(), 1);
22 $args->addElement(new Twig_Node_Expression_Name('foo', 1));
23 $args->addElement(new Twig_Node_Expression_Constant('bar', 1));
24 $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ARRAY_CALL, 1);
25
26 $this->assertEquals($expr, $node->getNode('node'));
27 $this->assertEquals($attr, $node->getNode('attribute'));
28 $this->assertEquals($args, $node->getNode('arguments'));
29 $this->assertEquals(Twig_TemplateInterface::ARRAY_CALL, $node->getAttribute('type'));
30 }
31
32 /**
33 * @covers Twig_Node_Expression_GetAttr::compile
34 * @dataProvider getTests
35 */
36 public function testCompile($node, $source, $environment = null)
37 {
38 parent::testCompile($node, $source, $environment);
39 }
40
41 public function getTests()
42 {
43 $tests = array();
44
45 $expr = new Twig_Node_Expression_Name('foo', 1);
46 $attr = new Twig_Node_Expression_Constant('bar', 1);
47 $args = new Twig_Node_Expression_Array(array(), 1);
48 $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ANY_CALL, 1);
49 $tests[] = array($node, sprintf('%s%s, "bar")', $this->getAttributeGetter(), $this->getVariableGetter('foo')));
50
51 $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ARRAY_CALL, 1);
52 $tests[] = array($node, sprintf('%s%s, "bar", array(), "array")', $this->getAttributeGetter(), $this->getVariableGetter('foo')));
53
54 $args = new Twig_Node_Expression_Array(array(), 1);
55 $args->addElement(new Twig_Node_Expression_Name('foo', 1));
56 $args->addElement(new Twig_Node_Expression_Constant('bar', 1));
57 $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::METHOD_CALL, 1);
58 $tests[] = array($node, sprintf('%s%s, "bar", array(0 => %s, 1 => "bar"), "method")', $this->getAttributeGetter(), $this->getVariableGetter('foo'), $this->getVariableGetter('foo')));
59
60 return $tests;
61 }
62}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php
new file mode 100644
index 00000000..76d109b6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php
@@ -0,0 +1,49 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_NameTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Name::__construct
16 */
17 public function testConstructor()
18 {
19 $node = new Twig_Node_Expression_Name('foo', 1);
20
21 $this->assertEquals('foo', $node->getAttribute('name'));
22 }
23
24 /**
25 * @covers Twig_Node_Expression_Name::compile
26 * @dataProvider getTests
27 */
28 public function testCompile($node, $source, $environment = null)
29 {
30 parent::testCompile($node, $source, $environment);
31 }
32
33 public function getTests()
34 {
35 $node = new Twig_Node_Expression_Name('foo', 1);
36 $self = new Twig_Node_Expression_Name('_self', 1);
37 $context = new Twig_Node_Expression_Name('_context', 1);
38
39 $env = new Twig_Environment(null, array('strict_variables' => true));
40 $env1 = new Twig_Environment(null, array('strict_variables' => false));
41
42 return array(
43 version_compare(PHP_VERSION, '5.4.0') >= 0 ? array($node, '(isset($context["foo"]) ? $context["foo"] : $this->getContext($context, "foo"))', $env) : array($node, '$this->getContext($context, "foo")', $env),
44 array($node, $this->getVariableGetter('foo'), $env1),
45 array($self, '$this'),
46 array($context, '$context'),
47 );
48 }
49}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FilterInclude.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FilterInclude.php
new file mode 100644
index 00000000..15e3aa96
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FilterInclude.php
@@ -0,0 +1,6 @@
1<?php
2
3$env = new Twig_Environment();
4$env->addFilter(new Twig_SimpleFilter('anonymous', function () {}));
5
6return $env;
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FunctionInclude.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FunctionInclude.php
new file mode 100644
index 00000000..d2170ed2
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FunctionInclude.php
@@ -0,0 +1,6 @@
1<?php
2
3$env = new Twig_Environment();
4$env->addFunction(new Twig_SimpleFunction('anonymous', function () {}));
5
6return $env;
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/TestInclude.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/TestInclude.php
new file mode 100644
index 00000000..63662864
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/TestInclude.php
@@ -0,0 +1,6 @@
1<?php
2
3$env = new Twig_Environment();
4$env->addTest(new Twig_SimpleTest('anonymous', function () {}));
5
6return $env;
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/ParentTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ParentTest.php
new file mode 100644
index 00000000..4d40419b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ParentTest.php
@@ -0,0 +1,40 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_ParentTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Parent::__construct
16 */
17 public function testConstructor()
18 {
19 $node = new Twig_Node_Expression_Parent('foo', 1);
20
21 $this->assertEquals('foo', $node->getAttribute('name'));
22 }
23
24 /**
25 * @covers Twig_Node_Expression_Parent::compile
26 * @dataProvider getTests
27 */
28 public function testCompile($node, $source, $environment = null)
29 {
30 parent::testCompile($node, $source, $environment);
31 }
32
33 public function getTests()
34 {
35 $tests = array();
36 $tests[] = array(new Twig_Node_Expression_Parent('foo', 1), '$this->renderParentBlock("foo", $context, $blocks)');
37
38 return $tests;
39 }
40}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php
new file mode 100644
index 00000000..0664150a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php
@@ -0,0 +1,68 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_TestTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Test::__construct
16 */
17 public function testConstructor()
18 {
19 $expr = new Twig_Node_Expression_Constant('foo', 1);
20 $name = new Twig_Node_Expression_Constant('null', 1);
21 $args = new Twig_Node();
22 $node = new Twig_Node_Expression_Test($expr, $name, $args, 1);
23
24 $this->assertEquals($expr, $node->getNode('node'));
25 $this->assertEquals($args, $node->getNode('arguments'));
26 $this->assertEquals($name, $node->getAttribute('name'));
27 }
28
29 /**
30 * @covers Twig_Node_Expression_Test::compile
31 * @dataProvider getTests
32 */
33 public function testCompile($node, $source, $environment = null)
34 {
35 parent::testCompile($node, $source, $environment);
36 }
37
38 public function getTests()
39 {
40 $tests = array();
41
42 $expr = new Twig_Node_Expression_Constant('foo', 1);
43 $node = new Twig_Node_Expression_Test_Null($expr, 'null', new Twig_Node(array()), 1);
44 $tests[] = array($node, '(null === "foo")');
45
46 // test as an anonymous function
47 if (version_compare(phpversion(), '5.3.0', '>=')) {
48 $node = $this->createTest(new Twig_Node_Expression_Constant('foo', 1), 'anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
49 $tests[] = array($node, 'call_user_func_array($this->env->getTest(\'anonymous\')->getCallable(), array("foo", "foo"))');
50 }
51
52 return $tests;
53 }
54
55 protected function createTest($node, $name, array $arguments = array())
56 {
57 return new Twig_Node_Expression_Test($node, $name, new Twig_Node($arguments), 1);
58 }
59
60 protected function getEnvironment()
61 {
62 if (version_compare(phpversion(), '5.3.0', '>=')) {
63 return include 'PHP53/TestInclude.php';
64 }
65
66 return parent::getEnvironment();
67 }
68}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NegTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NegTest.php
new file mode 100644
index 00000000..d55ab333
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NegTest.php
@@ -0,0 +1,44 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Unary_NegTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Unary_Neg::__construct
16 */
17 public function testConstructor()
18 {
19 $expr = new Twig_Node_Expression_Constant(1, 1);
20 $node = new Twig_Node_Expression_Unary_Neg($expr, 1);
21
22 $this->assertEquals($expr, $node->getNode('node'));
23 }
24
25 /**
26 * @covers Twig_Node_Expression_Unary_Neg::compile
27 * @covers Twig_Node_Expression_Unary_Neg::operator
28 * @dataProvider getTests
29 */
30 public function testCompile($node, $source, $environment = null)
31 {
32 parent::testCompile($node, $source, $environment);
33 }
34
35 public function getTests()
36 {
37 $node = new Twig_Node_Expression_Constant(1, 1);
38 $node = new Twig_Node_Expression_Unary_Neg($node, 1);
39
40 return array(
41 array($node, '(-1)'),
42 );
43 }
44}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NotTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NotTest.php
new file mode 100644
index 00000000..625c2527
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NotTest.php
@@ -0,0 +1,44 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Unary_NotTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Unary_Not::__construct
16 */
17 public function testConstructor()
18 {
19 $expr = new Twig_Node_Expression_Constant(1, 1);
20 $node = new Twig_Node_Expression_Unary_Not($expr, 1);
21
22 $this->assertEquals($expr, $node->getNode('node'));
23 }
24
25 /**
26 * @covers Twig_Node_Expression_Unary_Not::compile
27 * @covers Twig_Node_Expression_Unary_Not::operator
28 * @dataProvider getTests
29 */
30 public function testCompile($node, $source, $environment = null)
31 {
32 parent::testCompile($node, $source, $environment);
33 }
34
35 public function getTests()
36 {
37 $node = new Twig_Node_Expression_Constant(1, 1);
38 $node = new Twig_Node_Expression_Unary_Not($node, 1);
39
40 return array(
41 array($node, '(!1)'),
42 );
43 }
44}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/PosTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/PosTest.php
new file mode 100644
index 00000000..047a0977
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/PosTest.php
@@ -0,0 +1,44 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_Expression_Unary_PosTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Expression_Unary_Pos::__construct
16 */
17 public function testConstructor()
18 {
19 $expr = new Twig_Node_Expression_Constant(1, 1);
20 $node = new Twig_Node_Expression_Unary_Pos($expr, 1);
21
22 $this->assertEquals($expr, $node->getNode('node'));
23 }
24
25 /**
26 * @covers Twig_Node_Expression_Unary_Pos::compile
27 * @covers Twig_Node_Expression_Unary_Pos::operator
28 * @dataProvider getTests
29 */
30 public function testCompile($node, $source, $environment = null)
31 {
32 parent::testCompile($node, $source, $environment);
33 }
34
35 public function getTests()
36 {
37 $node = new Twig_Node_Expression_Constant(1, 1);
38 $node = new Twig_Node_Expression_Unary_Pos($node, 1);
39
40 return array(
41 array($node, '(+1)'),
42 );
43 }
44}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php b/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php
new file mode 100644
index 00000000..21cc84e6
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php
@@ -0,0 +1,203 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_ForTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_For::__construct
16 */
17 public function testConstructor()
18 {
19 $keyTarget = new Twig_Node_Expression_AssignName('key', 1);
20 $valueTarget = new Twig_Node_Expression_AssignName('item', 1);
21 $seq = new Twig_Node_Expression_Name('items', 1);
22 $ifexpr = new Twig_Node_Expression_Constant(true, 1);
23 $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
24 $else = null;
25 $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
26 $node->setAttribute('with_loop', false);
27
28 $this->assertEquals($keyTarget, $node->getNode('key_target'));
29 $this->assertEquals($valueTarget, $node->getNode('value_target'));
30 $this->assertEquals($seq, $node->getNode('seq'));
31 $this->assertTrue($node->getAttribute('ifexpr'));
32 $this->assertEquals('Twig_Node_If', get_class($node->getNode('body')));
33 $this->assertEquals($body, $node->getNode('body')->getNode('tests')->getNode(1)->getNode(0));
34 $this->assertEquals(null, $node->getNode('else'));
35
36 $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1);
37 $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
38 $node->setAttribute('with_loop', false);
39 $this->assertEquals($else, $node->getNode('else'));
40 }
41
42 /**
43 * @covers Twig_Node_For::compile
44 * @dataProvider getTests
45 */
46 public function testCompile($node, $source, $environment = null)
47 {
48 parent::testCompile($node, $source, $environment);
49 }
50
51 public function getTests()
52 {
53 $tests = array();
54
55 $keyTarget = new Twig_Node_Expression_AssignName('key', 1);
56 $valueTarget = new Twig_Node_Expression_AssignName('item', 1);
57 $seq = new Twig_Node_Expression_Name('items', 1);
58 $ifexpr = null;
59 $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
60 $else = null;
61 $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
62 $node->setAttribute('with_loop', false);
63
64 $tests[] = array($node, <<<EOF
65// line 1
66\$context['_parent'] = (array) \$context;
67\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('items')});
68foreach (\$context['_seq'] as \$context["key"] => \$context["item"]) {
69 echo {$this->getVariableGetter('foo')};
70}
71\$_parent = \$context['_parent'];
72unset(\$context['_seq'], \$context['_iterated'], \$context['key'], \$context['item'], \$context['_parent'], \$context['loop']);
73\$context = array_intersect_key(\$context, \$_parent) + \$_parent;
74EOF
75 );
76
77 $keyTarget = new Twig_Node_Expression_AssignName('k', 1);
78 $valueTarget = new Twig_Node_Expression_AssignName('v', 1);
79 $seq = new Twig_Node_Expression_Name('values', 1);
80 $ifexpr = null;
81 $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
82 $else = null;
83 $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
84 $node->setAttribute('with_loop', true);
85
86 $tests[] = array($node, <<<EOF
87// line 1
88\$context['_parent'] = (array) \$context;
89\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')});
90\$context['loop'] = array(
91 'parent' => \$context['_parent'],
92 'index0' => 0,
93 'index' => 1,
94 'first' => true,
95);
96if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {
97 \$length = count(\$context['_seq']);
98 \$context['loop']['revindex0'] = \$length - 1;
99 \$context['loop']['revindex'] = \$length;
100 \$context['loop']['length'] = \$length;
101 \$context['loop']['last'] = 1 === \$length;
102}
103foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
104 echo {$this->getVariableGetter('foo')};
105 ++\$context['loop']['index0'];
106 ++\$context['loop']['index'];
107 \$context['loop']['first'] = false;
108 if (isset(\$context['loop']['length'])) {
109 --\$context['loop']['revindex0'];
110 --\$context['loop']['revindex'];
111 \$context['loop']['last'] = 0 === \$context['loop']['revindex0'];
112 }
113}
114\$_parent = \$context['_parent'];
115unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
116\$context = array_intersect_key(\$context, \$_parent) + \$_parent;
117EOF
118 );
119
120 $keyTarget = new Twig_Node_Expression_AssignName('k', 1);
121 $valueTarget = new Twig_Node_Expression_AssignName('v', 1);
122 $seq = new Twig_Node_Expression_Name('values', 1);
123 $ifexpr = new Twig_Node_Expression_Constant(true, 1);
124 $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
125 $else = null;
126 $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
127 $node->setAttribute('with_loop', true);
128
129 $tests[] = array($node, <<<EOF
130// line 1
131\$context['_parent'] = (array) \$context;
132\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')});
133\$context['loop'] = array(
134 'parent' => \$context['_parent'],
135 'index0' => 0,
136 'index' => 1,
137 'first' => true,
138);
139foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
140 if (true) {
141 echo {$this->getVariableGetter('foo')};
142 ++\$context['loop']['index0'];
143 ++\$context['loop']['index'];
144 \$context['loop']['first'] = false;
145 }
146}
147\$_parent = \$context['_parent'];
148unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
149\$context = array_intersect_key(\$context, \$_parent) + \$_parent;
150EOF
151 );
152
153 $keyTarget = new Twig_Node_Expression_AssignName('k', 1);
154 $valueTarget = new Twig_Node_Expression_AssignName('v', 1);
155 $seq = new Twig_Node_Expression_Name('values', 1);
156 $ifexpr = null;
157 $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
158 $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1);
159 $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
160 $node->setAttribute('with_loop', true);
161
162 $tests[] = array($node, <<<EOF
163// line 1
164\$context['_parent'] = (array) \$context;
165\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')});
166\$context['_iterated'] = false;
167\$context['loop'] = array(
168 'parent' => \$context['_parent'],
169 'index0' => 0,
170 'index' => 1,
171 'first' => true,
172);
173if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {
174 \$length = count(\$context['_seq']);
175 \$context['loop']['revindex0'] = \$length - 1;
176 \$context['loop']['revindex'] = \$length;
177 \$context['loop']['length'] = \$length;
178 \$context['loop']['last'] = 1 === \$length;
179}
180foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
181 echo {$this->getVariableGetter('foo')};
182 \$context['_iterated'] = true;
183 ++\$context['loop']['index0'];
184 ++\$context['loop']['index'];
185 \$context['loop']['first'] = false;
186 if (isset(\$context['loop']['length'])) {
187 --\$context['loop']['revindex0'];
188 --\$context['loop']['revindex'];
189 \$context['loop']['last'] = 0 === \$context['loop']['revindex0'];
190 }
191}
192if (!\$context['_iterated']) {
193 echo {$this->getVariableGetter('foo')};
194}
195\$_parent = \$context['_parent'];
196unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
197\$context = array_intersect_key(\$context, \$_parent) + \$_parent;
198EOF
199 );
200
201 return $tests;
202 }
203}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/IfTest.php b/vendor/twig/twig/test/Twig/Tests/Node/IfTest.php
new file mode 100644
index 00000000..92fc29dc
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/IfTest.php
@@ -0,0 +1,100 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_IfTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_If::__construct
16 */
17 public function testConstructor()
18 {
19 $t = new Twig_Node(array(
20 new Twig_Node_Expression_Constant(true, 1),
21 new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
22 ), array(), 1);
23 $else = null;
24 $node = new Twig_Node_If($t, $else, 1);
25
26 $this->assertEquals($t, $node->getNode('tests'));
27 $this->assertEquals(null, $node->getNode('else'));
28
29 $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1);
30 $node = new Twig_Node_If($t, $else, 1);
31 $this->assertEquals($else, $node->getNode('else'));
32 }
33
34 /**
35 * @covers Twig_Node_If::compile
36 * @dataProvider getTests
37 */
38 public function testCompile($node, $source, $environment = null)
39 {
40 parent::testCompile($node, $source, $environment);
41 }
42
43 public function getTests()
44 {
45 $tests = array();
46
47 $t = new Twig_Node(array(
48 new Twig_Node_Expression_Constant(true, 1),
49 new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
50 ), array(), 1);
51 $else = null;
52 $node = new Twig_Node_If($t, $else, 1);
53
54 $tests[] = array($node, <<<EOF
55// line 1
56if (true) {
57 echo {$this->getVariableGetter('foo')};
58}
59EOF
60 );
61
62 $t = new Twig_Node(array(
63 new Twig_Node_Expression_Constant(true, 1),
64 new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
65 new Twig_Node_Expression_Constant(false, 1),
66 new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1),
67 ), array(), 1);
68 $else = null;
69 $node = new Twig_Node_If($t, $else, 1);
70
71 $tests[] = array($node, <<<EOF
72// line 1
73if (true) {
74 echo {$this->getVariableGetter('foo')};
75} elseif (false) {
76 echo {$this->getVariableGetter('bar')};
77}
78EOF
79 );
80
81 $t = new Twig_Node(array(
82 new Twig_Node_Expression_Constant(true, 1),
83 new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
84 ), array(), 1);
85 $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1);
86 $node = new Twig_Node_If($t, $else, 1);
87
88 $tests[] = array($node, <<<EOF
89// line 1
90if (true) {
91 echo {$this->getVariableGetter('foo')};
92} else {
93 echo {$this->getVariableGetter('bar')};
94}
95EOF
96 );
97
98 return $tests;
99 }
100}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/ImportTest.php b/vendor/twig/twig/test/Twig/Tests/Node/ImportTest.php
new file mode 100644
index 00000000..db36581a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/ImportTest.php
@@ -0,0 +1,52 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_ImportTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Import::__construct
16 */
17 public function testConstructor()
18 {
19 $macro = new Twig_Node_Expression_Constant('foo.twig', 1);
20 $var = new Twig_Node_Expression_AssignName('macro', 1);
21 $node = new Twig_Node_Import($macro, $var, 1);
22
23 $this->assertEquals($macro, $node->getNode('expr'));
24 $this->assertEquals($var, $node->getNode('var'));
25 }
26
27 /**
28 * @covers Twig_Node_Import::compile
29 * @dataProvider getTests
30 */
31 public function testCompile($node, $source, $environment = null)
32 {
33 parent::testCompile($node, $source, $environment);
34 }
35
36 public function getTests()
37 {
38 $tests = array();
39
40 $macro = new Twig_Node_Expression_Constant('foo.twig', 1);
41 $var = new Twig_Node_Expression_AssignName('macro', 1);
42 $node = new Twig_Node_Import($macro, $var, 1);
43
44 $tests[] = array($node, <<<EOF
45// line 1
46\$context["macro"] = \$this->env->loadTemplate("foo.twig");
47EOF
48 );
49
50 return $tests;
51 }
52}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/IncludeTest.php b/vendor/twig/twig/test/Twig/Tests/Node/IncludeTest.php
new file mode 100644
index 00000000..3b7da6e0
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/IncludeTest.php
@@ -0,0 +1,96 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_IncludeTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Include::__construct
16 */
17 public function testConstructor()
18 {
19 $expr = new Twig_Node_Expression_Constant('foo.twig', 1);
20 $node = new Twig_Node_Include($expr, null, false, false, 1);
21
22 $this->assertEquals(null, $node->getNode('variables'));
23 $this->assertEquals($expr, $node->getNode('expr'));
24 $this->assertFalse($node->getAttribute('only'));
25
26 $vars = new Twig_Node_Expression_Array(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Constant(true, 1)), 1);
27 $node = new Twig_Node_Include($expr, $vars, true, false, 1);
28 $this->assertEquals($vars, $node->getNode('variables'));
29 $this->assertTrue($node->getAttribute('only'));
30 }
31
32 /**
33 * @covers Twig_Node_Include::compile
34 * @dataProvider getTests
35 */
36 public function testCompile($node, $source, $environment = null)
37 {
38 parent::testCompile($node, $source, $environment);
39 }
40
41 public function getTests()
42 {
43 $tests = array();
44
45 $expr = new Twig_Node_Expression_Constant('foo.twig', 1);
46 $node = new Twig_Node_Include($expr, null, false, false, 1);
47 $tests[] = array($node, <<<EOF
48// line 1
49\$this->env->loadTemplate("foo.twig")->display(\$context);
50EOF
51 );
52
53 $expr = new Twig_Node_Expression_Conditional(
54 new Twig_Node_Expression_Constant(true, 1),
55 new Twig_Node_Expression_Constant('foo', 1),
56 new Twig_Node_Expression_Constant('foo', 1),
57 0
58 );
59 $node = new Twig_Node_Include($expr, null, false, false, 1);
60 $tests[] = array($node, <<<EOF
61// line 1
62\$template = \$this->env->resolveTemplate(((true) ? ("foo") : ("foo")));
63\$template->display(\$context);
64EOF
65 );
66
67 $expr = new Twig_Node_Expression_Constant('foo.twig', 1);
68 $vars = new Twig_Node_Expression_Array(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Constant(true, 1)), 1);
69 $node = new Twig_Node_Include($expr, $vars, false, false, 1);
70 $tests[] = array($node, <<<EOF
71// line 1
72\$this->env->loadTemplate("foo.twig")->display(array_merge(\$context, array("foo" => true)));
73EOF
74 );
75
76 $node = new Twig_Node_Include($expr, $vars, true, false, 1);
77 $tests[] = array($node, <<<EOF
78// line 1
79\$this->env->loadTemplate("foo.twig")->display(array("foo" => true));
80EOF
81 );
82
83 $node = new Twig_Node_Include($expr, $vars, true, true, 1);
84 $tests[] = array($node, <<<EOF
85// line 1
86try {
87 \$this->env->loadTemplate("foo.twig")->display(array("foo" => true));
88} catch (Twig_Error_Loader \$e) {
89 // ignore missing template
90}
91EOF
92 );
93
94 return $tests;
95 }
96}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/MacroTest.php b/vendor/twig/twig/test/Twig/Tests/Node/MacroTest.php
new file mode 100644
index 00000000..4d2f641b
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/MacroTest.php
@@ -0,0 +1,73 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_MacroTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Macro::__construct
16 */
17 public function testConstructor()
18 {
19 $body = new Twig_Node_Text('foo', 1);
20 $arguments = new Twig_Node(array(new Twig_Node_Expression_Name('foo', 1)), array(), 1);
21 $node = new Twig_Node_Macro('foo', $body, $arguments, 1);
22
23 $this->assertEquals($body, $node->getNode('body'));
24 $this->assertEquals($arguments, $node->getNode('arguments'));
25 $this->assertEquals('foo', $node->getAttribute('name'));
26 }
27
28 /**
29 * @covers Twig_Node_Macro::compile
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $body = new Twig_Node_Text('foo', 1);
40 $arguments = new Twig_Node(array(
41 'foo' => new Twig_Node_Expression_Constant(null, 1),
42 'bar' => new Twig_Node_Expression_Constant('Foo', 1),
43 ), array(), 1);
44 $node = new Twig_Node_Macro('foo', $body, $arguments, 1);
45
46 return array(
47 array($node, <<<EOF
48// line 1
49public function getfoo(\$_foo = null, \$_bar = "Foo")
50{
51 \$context = \$this->env->mergeGlobals(array(
52 "foo" => \$_foo,
53 "bar" => \$_bar,
54 ));
55
56 \$blocks = array();
57
58 ob_start();
59 try {
60 echo "foo";
61 } catch (Exception \$e) {
62 ob_end_clean();
63
64 throw \$e;
65 }
66
67 return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());
68}
69EOF
70 ),
71 );
72 }
73}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php b/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php
new file mode 100644
index 00000000..9411e99e
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php
@@ -0,0 +1,196 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_ModuleTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Module::__construct
16 */
17 public function testConstructor()
18 {
19 $body = new Twig_Node_Text('foo', 1);
20 $parent = new Twig_Node_Expression_Constant('layout.twig', 1);
21 $blocks = new Twig_Node();
22 $macros = new Twig_Node();
23 $traits = new Twig_Node();
24 $filename = 'foo.twig';
25 $node = new Twig_Node_Module($body, $parent, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
26
27 $this->assertEquals($body, $node->getNode('body'));
28 $this->assertEquals($blocks, $node->getNode('blocks'));
29 $this->assertEquals($macros, $node->getNode('macros'));
30 $this->assertEquals($parent, $node->getNode('parent'));
31 $this->assertEquals($filename, $node->getAttribute('filename'));
32 }
33
34 /**
35 * @covers Twig_Node_Module::compile
36 * @covers Twig_Node_Module::compileTemplate
37 * @covers Twig_Node_Module::compileMacros
38 * @covers Twig_Node_Module::compileClassHeader
39 * @covers Twig_Node_Module::compileDisplayHeader
40 * @covers Twig_Node_Module::compileDisplayBody
41 * @covers Twig_Node_Module::compileDisplayFooter
42 * @covers Twig_Node_Module::compileClassFooter
43 * @dataProvider getTests
44 */
45 public function testCompile($node, $source, $environment = null)
46 {
47 parent::testCompile($node, $source, $environment);
48 }
49
50 public function getTests()
51 {
52 $twig = new Twig_Environment(new Twig_Loader_String());
53
54 $tests = array();
55
56 $body = new Twig_Node_Text('foo', 1);
57 $extends = null;
58 $blocks = new Twig_Node();
59 $macros = new Twig_Node();
60 $traits = new Twig_Node();
61 $filename = 'foo.twig';
62
63 $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
64 $tests[] = array($node, <<<EOF
65<?php
66
67/* foo.twig */
68class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
69{
70 public function __construct(Twig_Environment \$env)
71 {
72 parent::__construct(\$env);
73
74 \$this->parent = false;
75
76 \$this->blocks = array(
77 );
78 }
79
80 protected function doDisplay(array \$context, array \$blocks = array())
81 {
82 // line 1
83 echo "foo";
84 }
85
86 public function getTemplateName()
87 {
88 return "foo.twig";
89 }
90
91 public function getDebugInfo()
92 {
93 return array ( 19 => 1,);
94 }
95}
96EOF
97 , $twig);
98
99 $import = new Twig_Node_Import(new Twig_Node_Expression_Constant('foo.twig', 1), new Twig_Node_Expression_AssignName('macro', 1), 1);
100
101 $body = new Twig_Node(array($import));
102 $extends = new Twig_Node_Expression_Constant('layout.twig', 1);
103
104 $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
105 $tests[] = array($node, <<<EOF
106<?php
107
108/* foo.twig */
109class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
110{
111 public function __construct(Twig_Environment \$env)
112 {
113 parent::__construct(\$env);
114
115 \$this->parent = \$this->env->loadTemplate("layout.twig");
116
117 \$this->blocks = array(
118 );
119 }
120
121 protected function doGetParent(array \$context)
122 {
123 return "layout.twig";
124 }
125
126 protected function doDisplay(array \$context, array \$blocks = array())
127 {
128 // line 1
129 \$context["macro"] = \$this->env->loadTemplate("foo.twig");
130 \$this->parent->display(\$context, array_merge(\$this->blocks, \$blocks));
131 }
132
133 public function getTemplateName()
134 {
135 return "foo.twig";
136 }
137
138 public function isTraitable()
139 {
140 return false;
141 }
142
143 public function getDebugInfo()
144 {
145 return array ( 24 => 1,);
146 }
147}
148EOF
149 , $twig);
150
151 $body = new Twig_Node();
152 $extends = new Twig_Node_Expression_Conditional(
153 new Twig_Node_Expression_Constant(true, 1),
154 new Twig_Node_Expression_Constant('foo', 1),
155 new Twig_Node_Expression_Constant('foo', 1),
156 0
157 );
158
159 $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
160 $tests[] = array($node, <<<EOF
161<?php
162
163/* foo.twig */
164class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
165{
166 protected function doGetParent(array \$context)
167 {
168 return \$this->env->resolveTemplate(((true) ? ("foo") : ("foo")));
169 }
170
171 protected function doDisplay(array \$context, array \$blocks = array())
172 {
173 \$this->getParent(\$context)->display(\$context, array_merge(\$this->blocks, \$blocks));
174 }
175
176 public function getTemplateName()
177 {
178 return "foo.twig";
179 }
180
181 public function isTraitable()
182 {
183 return false;
184 }
185
186 public function getDebugInfo()
187 {
188 return array ();
189 }
190}
191EOF
192 , $twig);
193
194 return $tests;
195 }
196}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/PrintTest.php b/vendor/twig/twig/test/Twig/Tests/Node/PrintTest.php
new file mode 100644
index 00000000..6fe43a41
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/PrintTest.php
@@ -0,0 +1,41 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_PrintTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Print::__construct
16 */
17 public function testConstructor()
18 {
19 $expr = new Twig_Node_Expression_Constant('foo', 1);
20 $node = new Twig_Node_Print($expr, 1);
21
22 $this->assertEquals($expr, $node->getNode('expr'));
23 }
24
25 /**
26 * @covers Twig_Node_Print::compile
27 * @dataProvider getTests
28 */
29 public function testCompile($node, $source, $environment = null)
30 {
31 parent::testCompile($node, $source, $environment);
32 }
33
34 public function getTests()
35 {
36 $tests = array();
37 $tests[] = array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 1), 1), "// line 1\necho \"foo\";");
38
39 return $tests;
40 }
41}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SandboxTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SandboxTest.php
new file mode 100644
index 00000000..db9dbf95
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/SandboxTest.php
@@ -0,0 +1,56 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_SandboxTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Sandbox::__construct
16 */
17 public function testConstructor()
18 {
19 $body = new Twig_Node_Text('foo', 1);
20 $node = new Twig_Node_Sandbox($body, 1);
21
22 $this->assertEquals($body, $node->getNode('body'));
23 }
24
25 /**
26 * @covers Twig_Node_Sandbox::compile
27 * @dataProvider getTests
28 */
29 public function testCompile($node, $source, $environment = null)
30 {
31 parent::testCompile($node, $source, $environment);
32 }
33
34 public function getTests()
35 {
36 $tests = array();
37
38 $body = new Twig_Node_Text('foo', 1);
39 $node = new Twig_Node_Sandbox($body, 1);
40
41 $tests[] = array($node, <<<EOF
42// line 1
43\$sandbox = \$this->env->getExtension('sandbox');
44if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {
45 \$sandbox->enableSandbox();
46}
47echo "foo";
48if (!\$alreadySandboxed) {
49 \$sandbox->disableSandbox();
50}
51EOF
52 );
53
54 return $tests;
55 }
56}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php
new file mode 100644
index 00000000..217e3408
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php
@@ -0,0 +1,173 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_SandboxedModuleTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_SandboxedModule::__construct
16 */
17 public function testConstructor()
18 {
19 $body = new Twig_Node_Text('foo', 1);
20 $parent = new Twig_Node_Expression_Constant('layout.twig', 1);
21 $blocks = new Twig_Node();
22 $macros = new Twig_Node();
23 $traits = new Twig_Node();
24 $filename = 'foo.twig';
25 $node = new Twig_Node_Module($body, $parent, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
26 $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle'));
27
28 $this->assertEquals($body, $node->getNode('body'));
29 $this->assertEquals($blocks, $node->getNode('blocks'));
30 $this->assertEquals($macros, $node->getNode('macros'));
31 $this->assertEquals($parent, $node->getNode('parent'));
32 $this->assertEquals($filename, $node->getAttribute('filename'));
33 }
34
35 /**
36 * @covers Twig_Node_SandboxedModule::compile
37 * @covers Twig_Node_SandboxedModule::compileDisplayBody
38 * @covers Twig_Node_SandboxedModule::compileDisplayFooter
39 * @dataProvider getTests
40 */
41 public function testCompile($node, $source, $environment = null)
42 {
43 parent::testCompile($node, $source, $environment);
44 }
45
46 public function getTests()
47 {
48 $twig = new Twig_Environment(new Twig_Loader_String());
49
50 $tests = array();
51
52 $body = new Twig_Node_Text('foo', 1);
53 $extends = null;
54 $blocks = new Twig_Node();
55 $macros = new Twig_Node();
56 $traits = new Twig_Node();
57 $filename = 'foo.twig';
58
59 $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
60 $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle'));
61
62 $tests[] = array($node, <<<EOF
63<?php
64
65/* foo.twig */
66class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
67{
68 public function __construct(Twig_Environment \$env)
69 {
70 parent::__construct(\$env);
71
72 \$this->parent = false;
73
74 \$this->blocks = array(
75 );
76 }
77
78 protected function doDisplay(array \$context, array \$blocks = array())
79 {
80 \$this->checkSecurity();
81 // line 1
82 echo "foo";
83 }
84
85 protected function checkSecurity()
86 {
87 \$this->env->getExtension('sandbox')->checkSecurity(
88 array('upper'),
89 array('for'),
90 array('cycle')
91 );
92 }
93
94 public function getTemplateName()
95 {
96 return "foo.twig";
97 }
98
99 public function getDebugInfo()
100 {
101 return array ( 20 => 1,);
102 }
103}
104EOF
105 , $twig);
106
107 $body = new Twig_Node();
108 $extends = new Twig_Node_Expression_Constant('layout.twig', 1);
109 $blocks = new Twig_Node();
110 $macros = new Twig_Node();
111 $traits = new Twig_Node();
112 $filename = 'foo.twig';
113
114 $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
115 $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle'));
116
117 $tests[] = array($node, <<<EOF
118<?php
119
120/* foo.twig */
121class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
122{
123 public function __construct(Twig_Environment \$env)
124 {
125 parent::__construct(\$env);
126
127 \$this->parent = \$this->env->loadTemplate("layout.twig");
128
129 \$this->blocks = array(
130 );
131 }
132
133 protected function doGetParent(array \$context)
134 {
135 return "layout.twig";
136 }
137
138 protected function doDisplay(array \$context, array \$blocks = array())
139 {
140 \$this->checkSecurity();
141 \$this->parent->display(\$context, array_merge(\$this->blocks, \$blocks));
142 }
143
144 protected function checkSecurity()
145 {
146 \$this->env->getExtension('sandbox')->checkSecurity(
147 array('upper'),
148 array('for'),
149 array('cycle')
150 );
151 }
152
153 public function getTemplateName()
154 {
155 return "foo.twig";
156 }
157
158 public function isTraitable()
159 {
160 return false;
161 }
162
163 public function getDebugInfo()
164 {
165 return array ();
166 }
167}
168EOF
169 , $twig);
170
171 return $tests;
172 }
173}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SandboxedPrintTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SandboxedPrintTest.php
new file mode 100644
index 00000000..058e02bc
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/SandboxedPrintTest.php
@@ -0,0 +1,45 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_SandboxedPrintTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_SandboxedPrint::__construct
16 */
17 public function testConstructor()
18 {
19 $node = new Twig_Node_SandboxedPrint($expr = new Twig_Node_Expression_Constant('foo', 1), 1);
20
21 $this->assertEquals($expr, $node->getNode('expr'));
22 }
23
24 /**
25 * @covers Twig_Node_SandboxedPrint::compile
26 * @dataProvider getTests
27 */
28 public function testCompile($node, $source, $environment = null)
29 {
30 parent::testCompile($node, $source, $environment);
31 }
32
33 public function getTests()
34 {
35 $tests = array();
36
37 $tests[] = array(new Twig_Node_SandboxedPrint(new Twig_Node_Expression_Constant('foo', 1), 1), <<<EOF
38// line 1
39echo \$this->env->getExtension('sandbox')->ensureToStringAllowed("foo");
40EOF
41 );
42
43 return $tests;
44 }
45}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SetTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SetTest.php
new file mode 100644
index 00000000..d64d671a
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/SetTest.php
@@ -0,0 +1,81 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_SetTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Set::__construct
16 */
17 public function testConstructor()
18 {
19 $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
20 $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1)), array(), 1);
21 $node = new Twig_Node_Set(false, $names, $values, 1);
22
23 $this->assertEquals($names, $node->getNode('names'));
24 $this->assertEquals($values, $node->getNode('values'));
25 $this->assertEquals(false, $node->getAttribute('capture'));
26 }
27
28 /**
29 * @covers Twig_Node_Set::compile
30 * @dataProvider getTests
31 */
32 public function testCompile($node, $source, $environment = null)
33 {
34 parent::testCompile($node, $source, $environment);
35 }
36
37 public function getTests()
38 {
39 $tests = array();
40
41 $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
42 $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1)), array(), 1);
43 $node = new Twig_Node_Set(false, $names, $values, 1);
44 $tests[] = array($node, <<<EOF
45// line 1
46\$context["foo"] = "foo";
47EOF
48 );
49
50 $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
51 $values = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 1), 1)), array(), 1);
52 $node = new Twig_Node_Set(true, $names, $values, 1);
53 $tests[] = array($node, <<<EOF
54// line 1
55ob_start();
56echo "foo";
57\$context["foo"] = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());
58EOF
59 );
60
61 $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
62 $values = new Twig_Node_Text('foo', 1);
63 $node = new Twig_Node_Set(true, $names, $values, 1);
64 $tests[] = array($node, <<<EOF
65// line 1
66\$context["foo"] = ('' === \$tmp = "foo") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());
67EOF
68 );
69
70 $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1), new Twig_Node_Expression_AssignName('bar', 1)), array(), 1);
71 $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Name('bar', 1)), array(), 1);
72 $node = new Twig_Node_Set(false, $names, $values, 1);
73 $tests[] = array($node, <<<EOF
74// line 1
75list(\$context["foo"], \$context["bar"]) = array("foo", {$this->getVariableGetter('bar')});
76EOF
77 );
78
79 return $tests;
80 }
81}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SpacelessTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SpacelessTest.php
new file mode 100644
index 00000000..6735dc31
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/SpacelessTest.php
@@ -0,0 +1,49 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_SpacelessTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Spaceless::__construct
16 */
17 public function testConstructor()
18 {
19 $body = new Twig_Node(array(new Twig_Node_Text('<div> <div> foo </div> </div>', 1)));
20 $node = new Twig_Node_Spaceless($body, 1);
21
22 $this->assertEquals($body, $node->getNode('body'));
23 }
24
25 /**
26 * @covers Twig_Node_Spaceless::compile
27 * @dataProvider getTests
28 */
29 public function testCompile($node, $source, $environment = null)
30 {
31 parent::testCompile($node, $source, $environment);
32 }
33
34 public function getTests()
35 {
36 $body = new Twig_Node(array(new Twig_Node_Text('<div> <div> foo </div> </div>', 1)));
37 $node = new Twig_Node_Spaceless($body, 1);
38
39 return array(
40 array($node, <<<EOF
41// line 1
42ob_start();
43echo "<div> <div> foo </div> </div>";
44echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));
45EOF
46 ),
47 );
48 }
49}
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/TextTest.php b/vendor/twig/twig/test/Twig/Tests/Node/TextTest.php
new file mode 100644
index 00000000..6f85576e
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/Node/TextTest.php
@@ -0,0 +1,40 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_Node_TextTest extends Twig_Test_NodeTestCase
13{
14 /**
15 * @covers Twig_Node_Text::__construct
16 */
17 public function testConstructor()
18 {
19 $node = new Twig_Node_Text('foo', 1);
20
21 $this->assertEquals('foo', $node->getAttribute('data'));
22 }
23
24 /**
25 * @covers Twig_Node_Text::compile
26 * @dataProvider getTests
27 */
28 public function testCompile($node, $source, $environment = null)
29 {
30 parent::testCompile($node, $source, $environment);
31 }
32
33 public function getTests()
34 {
35 $tests = array();
36 $tests[] = array(new Twig_Node_Text('foo', 1), "// line 1\necho \"foo\";");
37
38 return $tests;
39 }
40}
diff --git a/vendor/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php b/vendor/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php
new file mode 100644
index 00000000..d35740d5
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php
@@ -0,0 +1,114 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
12{
13 public function testRenderBlockOptimizer()
14 {
15 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
16
17 $stream = $env->parse($env->tokenize('{{ block("foo") }}', 'index'));
18
19 $node = $stream->getNode('body')->getNode(0);
20
21 $this->assertEquals('Twig_Node_Expression_BlockReference', get_class($node));
22 $this->assertTrue($node->getAttribute('output'));
23 }
24
25 public function testRenderParentBlockOptimizer()
26 {
27 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
28
29 $stream = $env->parse($env->tokenize('{% extends "foo" %}{% block content %}{{ parent() }}{% endblock %}', 'index'));
30
31 $node = $stream->getNode('blocks')->getNode('content')->getNode(0)->getNode('body');
32
33 $this->assertEquals('Twig_Node_Expression_Parent', get_class($node));
34 $this->assertTrue($node->getAttribute('output'));
35 }
36
37 public function testRenderVariableBlockOptimizer()
38 {
39 if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
40 return;
41 }
42
43 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
44 $stream = $env->parse($env->tokenize('{{ block(name|lower) }}', 'index'));
45
46 $node = $stream->getNode('body')->getNode(0)->getNode(1);
47
48 $this->assertEquals('Twig_Node_Expression_BlockReference', get_class($node));
49 $this->assertTrue($node->getAttribute('output'));
50 }
51
52 /**
53 * @dataProvider getTestsForForOptimizer
54 */
55 public function testForOptimizer($template, $expected)
56 {
57 $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false));
58
59 $stream = $env->parse($env->tokenize($template, 'index'));
60
61 foreach ($expected as $target => $withLoop) {
62 $this->assertTrue($this->checkForConfiguration($stream, $target, $withLoop), sprintf('variable %s is %soptimized', $target, $withLoop ? 'not ' : ''));
63 }
64 }
65
66 public function getTestsForForOptimizer()
67 {
68 return array(
69 array('{% for i in foo %}{% endfor %}', array('i' => false)),
70
71 array('{% for i in foo %}{{ loop.index }}{% endfor %}', array('i' => true)),
72
73 array('{% for i in foo %}{% for j in foo %}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
74
75 array('{% for i in foo %}{% include "foo" %}{% endfor %}', array('i' => true)),
76
77 array('{% for i in foo %}{% include "foo" only %}{% endfor %}', array('i' => false)),
78
79 array('{% for i in foo %}{% include "foo" with { "foo": "bar" } only %}{% endfor %}', array('i' => false)),
80
81 array('{% for i in foo %}{% include "foo" with { "foo": loop.index } only %}{% endfor %}', array('i' => true)),
82
83 array('{% for i in foo %}{% for j in foo %}{{ loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => true)),
84
85 array('{% for i in foo %}{% for j in foo %}{{ loop.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
86
87 array('{% for i in foo %}{% set l = loop %}{% for j in foo %}{{ l.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => false)),
88
89 array('{% for i in foo %}{% for j in foo %}{{ foo.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
90
91 array('{% for i in foo %}{% for j in foo %}{{ loop["parent"].loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
92 );
93 }
94
95 public function checkForConfiguration(Twig_NodeInterface $node = null, $target, $withLoop)
96 {
97 if (null === $node) {
98 return;
99 }
100
101 foreach ($node as $n) {
102 if ($n instanceof Twig_Node_For) {
103 if ($target === $n->getNode('value_target')->getAttribute('name')) {
104 return $withLoop == $n->getAttribute('with_loop');
105 }
106 }
107
108 $ret = $this->checkForConfiguration($n, $target, $withLoop);
109 if (null !== $ret) {
110 return $ret;
111 }
112 }
113 }
114}
diff --git a/vendor/twig/twig/test/Twig/Tests/ParserTest.php b/vendor/twig/twig/test/Twig/Tests/ParserTest.php
new file mode 100644
index 00000000..55eb7fb4
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/ParserTest.php
@@ -0,0 +1,180 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Tests_ParserTest extends PHPUnit_Framework_TestCase
12{
13 /**
14 * @expectedException Twig_Error_Syntax
15 */
16 public function testSetMacroThrowsExceptionOnReservedMethods()
17 {
18 $parser = $this->getParser();
19 $parser->setMacro('display', $this->getMock('Twig_Node_Macro', array(), array(), '', null));
20 }
21
22 /**
23 * @expectedException Twig_Error_Syntax
24 * @expectedExceptionMessage Unknown tag name "foo". Did you mean "for" at line 1
25 */
26 public function testUnknownTag()
27 {
28 $stream = new Twig_TokenStream(array(
29 new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
30 new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 1),
31 new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
32 new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
33 ));
34 $parser = new Twig_Parser(new Twig_Environment());
35 $parser->parse($stream);
36 }
37
38 /**
39 * @dataProvider getFilterBodyNodesData
40 */
41 public function testFilterBodyNodes($input, $expected)
42 {
43 $parser = $this->getParser();
44
45 $this->assertEquals($expected, $parser->filterBodyNodes($input));
46 }
47
48 public function getFilterBodyNodesData()
49 {
50 return array(
51 array(
52 new Twig_Node(array(new Twig_Node_Text(' ', 1))),
53 new Twig_Node(array()),
54 ),
55 array(
56 $input = new Twig_Node(array(new Twig_Node_Set(false, new Twig_Node(), new Twig_Node(), 1))),
57 $input,
58 ),
59 array(
60 $input = new Twig_Node(array(new Twig_Node_Set(true, new Twig_Node(), new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 1))))), 1))),
61 $input,
62 ),
63 );
64 }
65
66 /**
67 * @dataProvider getFilterBodyNodesDataThrowsException
68 * @expectedException Twig_Error_Syntax
69 */
70 public function testFilterBodyNodesThrowsException($input)
71 {
72 $parser = $this->getParser();
73
74 $parser->filterBodyNodes($input);
75 }
76
77 public function getFilterBodyNodesDataThrowsException()
78 {
79 return array(
80 array(new Twig_Node_Text('foo', 1)),
81 array(new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 1)))))),
82 );
83 }
84
85 /**
86 * @expectedException Twig_Error_Syntax
87 * @expectedExceptionMessage A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed at line 1.
88 */
89 public function testFilterBodyNodesWithBOM()
90 {
91 $parser = $this->getParser();
92 $parser->filterBodyNodes(new Twig_Node_Text(chr(0xEF).chr(0xBB).chr(0xBF), 1));
93 }
94
95 public function testParseIsReentrant()
96 {
97 $twig = new Twig_Environment(null, array(
98 'autoescape' => false,
99 'optimizations' => 0,
100 ));
101 $twig->addTokenParser(new TestTokenParser());
102
103 $parser = new Twig_Parser($twig);
104
105 $parser->parse(new Twig_TokenStream(array(
106 new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
107 new Twig_Token(Twig_Token::NAME_TYPE, 'test', 1),
108 new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
109 new Twig_Token(Twig_Token::VAR_START_TYPE, '', 1),
110 new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 1),
111 new Twig_Token(Twig_Token::VAR_END_TYPE, '', 1),
112 new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
113 )));
114
115 $this->assertEquals(null, $parser->getParent());
116 }
117
118 // The getVarName() must not depend on the template loaders,
119 // If this test does not throw any exception, that's good.
120 // see https://github.com/symfony/symfony/issues/4218
121 public function testGetVarName()
122 {
123 $twig = new Twig_Environment(null, array(
124 'autoescape' => false,
125 'optimizations' => 0,
126 ));
127
128 $twig->parse($twig->tokenize(<<<EOF
129{% from _self import foo %}
130
131{% macro foo() %}
132 {{ foo }}
133{% endmacro %}
134EOF
135 ));
136 }
137
138 protected function getParser()
139 {
140 $parser = new TestParser(new Twig_Environment());
141 $parser->setParent(new Twig_Node());
142 $parser->stream = $this->getMockBuilder('Twig_TokenStream')->disableOriginalConstructor()->getMock();
143
144 return $parser;
145 }
146}
147
148class TestParser extends Twig_Parser
149{
150 public $stream;
151
152 public function filterBodyNodes(Twig_NodeInterface $node)
153 {
154 return parent::filterBodyNodes($node);
155 }
156}
157
158class TestTokenParser extends Twig_TokenParser
159{
160 public function parse(Twig_Token $token)
161 {
162 // simulate the parsing of another template right in the middle of the parsing of the current template
163 $this->parser->parse(new Twig_TokenStream(array(
164 new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
165 new Twig_Token(Twig_Token::NAME_TYPE, 'extends', 1),
166 new Twig_Token(Twig_Token::STRING_TYPE, 'base', 1),
167 new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
168 new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
169 )));
170
171 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
172
173 return new Twig_Node(array());
174 }
175
176 public function getTag()
177 {
178 return 'test';
179 }
180}
diff --git a/vendor/twig/twig/test/Twig/Tests/TemplateTest.php b/vendor/twig/twig/test/Twig/Tests/TemplateTest.php
new file mode 100644
index 00000000..823a9ce9
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/TemplateTest.php
@@ -0,0 +1,626 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
12{
13 /**
14 * @dataProvider getAttributeExceptions
15 */
16 public function testGetAttributeExceptions($template, $message, $useExt)
17 {
18 $name = 'index_'.($useExt ? 1 : 0);
19 $templates = array(
20 $name => $template.$useExt, // appending $useExt makes the template content unique
21 );
22
23 $env = new Twig_Environment(new Twig_Loader_Array($templates), array('strict_variables' => true));
24 if (!$useExt) {
25 $env->addNodeVisitor(new CExtDisablingNodeVisitor());
26 }
27 $template = $env->loadTemplate($name);
28
29 $context = array(
30 'string' => 'foo',
31 'array' => array('foo' => 'foo'),
32 'array_access' => new Twig_TemplateArrayAccessObject(),
33 'magic_exception' => new Twig_TemplateMagicPropertyObjectWithException(),
34 );
35
36 try {
37 $template->render($context);
38 $this->fail('Accessing an invalid attribute should throw an exception.');
39 } catch (Twig_Error_Runtime $e) {
40 $this->assertSame(sprintf($message, $name), $e->getMessage());
41 }
42 }
43
44 public function getAttributeExceptions()
45 {
46 $tests = array(
47 array('{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1', false),
48 array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false),
49 array('{{ array_access["a"] }}', 'Key "a" in object (with ArrayAccess) of type "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
50 array('{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1', false),
51 array('{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1', false),
52 array('{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false),
53 array('{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1', false),
54 array('{{ array_access.a }}', 'Method "a" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
55 array('{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ _self.foo(array_access) }}', 'Method "missing_method" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
56 array('{{ magic_exception.test }}', 'An exception has been thrown during the rendering of a template ("Hey! Don\'t try to isset me!") in "%s" at line 1.', false),
57 );
58
59 if (function_exists('twig_template_get_attributes')) {
60 foreach (array_slice($tests, 0) as $test) {
61 $test[2] = true;
62 $tests[] = $test;
63 }
64 }
65
66 return $tests;
67 }
68
69 /**
70 * @dataProvider getGetAttributeWithSandbox
71 */
72 public function testGetAttributeWithSandbox($object, $item, $allowed, $useExt)
73 {
74 $twig = new Twig_Environment();
75 $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(/*method*/), array(/*prop*/), array());
76 $twig->addExtension(new Twig_Extension_Sandbox($policy, !$allowed));
77 $template = new Twig_TemplateTest($twig, $useExt);
78
79 try {
80 $template->getAttribute($object, $item, array(), 'any');
81
82 if (!$allowed) {
83 $this->fail();
84 }
85 } catch (Twig_Sandbox_SecurityError $e) {
86 if ($allowed) {
87 $this->fail();
88 }
89
90 $this->assertContains('is not allowed', $e->getMessage());
91 }
92 }
93
94 public function getGetAttributeWithSandbox()
95 {
96 $tests = array(
97 array(new Twig_TemplatePropertyObject(), 'defined', false, false),
98 array(new Twig_TemplatePropertyObject(), 'defined', true, false),
99 array(new Twig_TemplateMethodObject(), 'defined', false, false),
100 array(new Twig_TemplateMethodObject(), 'defined', true, false),
101 );
102
103 if (function_exists('twig_template_get_attributes')) {
104 foreach (array_slice($tests, 0) as $test) {
105 $test[3] = true;
106 $tests[] = $test;
107 }
108 }
109
110 return $tests;
111 }
112
113 /**
114 * @dataProvider getGetAttributeWithTemplateAsObject
115 */
116 public function testGetAttributeWithTemplateAsObject($useExt)
117 {
118 $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
119 $template1 = new Twig_TemplateTest(new Twig_Environment(), false);
120
121 $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'string'));
122 $this->assertEquals('some_string', $template->getAttribute($template1, 'string'));
123
124 $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'true'));
125 $this->assertEquals('1', $template->getAttribute($template1, 'true'));
126
127 $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'zero'));
128 $this->assertEquals('0', $template->getAttribute($template1, 'zero'));
129
130 $this->assertNotInstanceof('Twig_Markup', $template->getAttribute($template1, 'empty'));
131 $this->assertSame('', $template->getAttribute($template1, 'empty'));
132 }
133
134 public function getGetAttributeWithTemplateAsObject()
135 {
136 $bools = array(
137 array(false),
138 );
139
140 if (function_exists('twig_template_get_attributes')) {
141 $bools[] = array(true);
142 }
143
144 return $bools;
145 }
146
147 /**
148 * @dataProvider getTestsDependingOnExtensionAvailability
149 */
150 public function testGetAttributeOnArrayWithConfusableKey($useExt = false)
151 {
152 $template = new Twig_TemplateTest(
153 new Twig_Environment(),
154 $useExt
155 );
156
157 $array = array('Zero', 'One', -1 => 'MinusOne', '' => 'EmptyString', '1.5' => 'FloatButString', '01' => 'IntegerButStringWithLeadingZeros');
158
159 $this->assertSame('Zero', $array[false]);
160 $this->assertSame('One', $array[true]);
161 $this->assertSame('One', $array[1.5]);
162 $this->assertSame('One', $array['1']);
163 $this->assertSame('MinusOne', $array[-1.5]);
164 $this->assertSame('FloatButString', $array['1.5']);
165 $this->assertSame('IntegerButStringWithLeadingZeros', $array['01']);
166 $this->assertSame('EmptyString', $array[null]);
167
168 $this->assertSame('Zero', $template->getAttribute($array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)');
169 $this->assertSame('One', $template->getAttribute($array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)');
170 $this->assertSame('One', $template->getAttribute($array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)');
171 $this->assertSame('One', $template->getAttribute($array, '1'), '"1" is treated as integer 1 when accessing an array (equals PHP behavior)');
172 $this->assertSame('MinusOne', $template->getAttribute($array, -1.5), 'negative float is casted to int when accessing an array (equals PHP behavior)');
173 $this->assertSame('FloatButString', $template->getAttribute($array, '1.5'), '"1.5" is treated as-is when accessing an array (equals PHP behavior)');
174 $this->assertSame('IntegerButStringWithLeadingZeros', $template->getAttribute($array, '01'), '"01" is treated as-is when accessing an array (equals PHP behavior)');
175 $this->assertSame('EmptyString', $template->getAttribute($array, null), 'null is treated as "" when accessing an array (equals PHP behavior)');
176 }
177
178 public function getTestsDependingOnExtensionAvailability()
179 {
180 if (function_exists('twig_template_get_attributes')) {
181 return array(array(false), array(true));
182 }
183
184 return array(array(false));
185 }
186
187 /**
188 * @dataProvider getGetAttributeTests
189 */
190 public function testGetAttribute($defined, $value, $object, $item, $arguments, $type, $useExt = false)
191 {
192 $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
193
194 $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
195 }
196
197 /**
198 * @dataProvider getGetAttributeTests
199 */
200 public function testGetAttributeStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false, $exceptionMessage = null)
201 {
202 $template = new Twig_TemplateTest(new Twig_Environment(null, array('strict_variables' => true)), $useExt);
203
204 if ($defined) {
205 $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
206 } else {
207 try {
208 $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
209
210 throw new Exception('Expected Twig_Error_Runtime exception.');
211 } catch (Twig_Error_Runtime $e) {
212 if (null !== $exceptionMessage) {
213 $this->assertSame($exceptionMessage, $e->getMessage());
214 }
215 }
216 }
217 }
218
219 /**
220 * @dataProvider getGetAttributeTests
221 */
222 public function testGetAttributeDefined($defined, $value, $object, $item, $arguments, $type, $useExt = false)
223 {
224 $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
225
226 $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true));
227 }
228
229 /**
230 * @dataProvider getGetAttributeTests
231 */
232 public function testGetAttributeDefinedStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false)
233 {
234 $template = new Twig_TemplateTest(new Twig_Environment(null, array('strict_variables' => true)), $useExt);
235
236 $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true));
237 }
238
239 public function getGetAttributeTests()
240 {
241 $array = array(
242 'defined' => 'defined',
243 'zero' => 0,
244 'null' => null,
245 '1' => 1,
246 'bar' => true,
247 '09' => '09',
248 '+4' => '+4',
249 );
250
251 $objectArray = new Twig_TemplateArrayAccessObject();
252 $stdObject = (object) $array;
253 $magicPropertyObject = new Twig_TemplateMagicPropertyObject();
254 $propertyObject = new Twig_TemplatePropertyObject();
255 $propertyObject1 = new Twig_TemplatePropertyObjectAndIterator();
256 $propertyObject2 = new Twig_TemplatePropertyObjectAndArrayAccess();
257 $methodObject = new Twig_TemplateMethodObject();
258 $magicMethodObject = new Twig_TemplateMagicMethodObject();
259
260 $anyType = Twig_TemplateInterface::ANY_CALL;
261 $methodType = Twig_TemplateInterface::METHOD_CALL;
262 $arrayType = Twig_TemplateInterface::ARRAY_CALL;
263
264 $basicTests = array(
265 // array(defined, value, property to fetch)
266 array(true, 'defined', 'defined'),
267 array(false, null, 'undefined'),
268 array(false, null, 'protected'),
269 array(true, 0, 'zero'),
270 array(true, 1, 1),
271 array(true, 1, 1.0),
272 array(true, null, 'null'),
273 array(true, true, 'bar'),
274 array(true, '09', '09'),
275 array(true, '+4', '+4'),
276 );
277 $testObjects = array(
278 // array(object, type of fetch)
279 array($array, $arrayType),
280 array($objectArray, $arrayType),
281 array($stdObject, $anyType),
282 array($magicPropertyObject, $anyType),
283 array($methodObject, $methodType),
284 array($methodObject, $anyType),
285 array($propertyObject, $anyType),
286 array($propertyObject1, $anyType),
287 array($propertyObject2, $anyType),
288 );
289
290 $tests = array();
291 foreach ($testObjects as $testObject) {
292 foreach ($basicTests as $test) {
293 // properties cannot be numbers
294 if (($testObject[0] instanceof stdClass || $testObject[0] instanceof Twig_TemplatePropertyObject) && is_numeric($test[2])) {
295 continue;
296 }
297
298 if ('+4' === $test[2] && $methodObject === $testObject[0]) {
299 continue;
300 }
301
302 $tests[] = array($test[0], $test[1], $testObject[0], $test[2], array(), $testObject[1]);
303 }
304 }
305
306 // additional method tests
307 $tests = array_merge($tests, array(
308 array(true, 'defined', $methodObject, 'defined', array(), $methodType),
309 array(true, 'defined', $methodObject, 'DEFINED', array(), $methodType),
310 array(true, 'defined', $methodObject, 'getDefined', array(), $methodType),
311 array(true, 'defined', $methodObject, 'GETDEFINED', array(), $methodType),
312 array(true, 'static', $methodObject, 'static', array(), $methodType),
313 array(true, 'static', $methodObject, 'getStatic', array(), $methodType),
314
315 array(true, '__call_undefined', $magicMethodObject, 'undefined', array(), $methodType),
316 array(true, '__call_UNDEFINED', $magicMethodObject, 'UNDEFINED', array(), $methodType),
317 ));
318
319 // add the same tests for the any type
320 foreach ($tests as $test) {
321 if ($anyType !== $test[5]) {
322 $test[5] = $anyType;
323 $tests[] = $test;
324 }
325 }
326
327 $methodAndPropObject = new Twig_TemplateMethodAndPropObject;
328
329 // additional method tests
330 $tests = array_merge($tests, array(
331 array(true, 'a', $methodAndPropObject, 'a', array(), $anyType),
332 array(true, 'a', $methodAndPropObject, 'a', array(), $methodType),
333 array(false, null, $methodAndPropObject, 'a', array(), $arrayType),
334
335 array(true, 'b_prop', $methodAndPropObject, 'b', array(), $anyType),
336 array(true, 'b', $methodAndPropObject, 'B', array(), $anyType),
337 array(true, 'b', $methodAndPropObject, 'b', array(), $methodType),
338 array(true, 'b', $methodAndPropObject, 'B', array(), $methodType),
339 array(false, null, $methodAndPropObject, 'b', array(), $arrayType),
340
341 array(false, null, $methodAndPropObject, 'c', array(), $anyType),
342 array(false, null, $methodAndPropObject, 'c', array(), $methodType),
343 array(false, null, $methodAndPropObject, 'c', array(), $arrayType),
344
345 ));
346
347 // tests when input is not an array or object
348 $tests = array_merge($tests, array(
349 array(false, null, 42, 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a integer variable ("42")'),
350 array(false, null, "string", 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a string variable ("string")'),
351 array(false, null, array(), 'a', array(), $anyType, false, 'Key "a" for array with keys "" does not exist'),
352 ));
353
354 // add twig_template_get_attributes tests
355
356 if (function_exists('twig_template_get_attributes')) {
357 foreach (array_slice($tests, 0) as $test) {
358 $test = array_pad($test, 7, null);
359 $test[6] = true;
360 $tests[] = $test;
361 }
362 }
363
364 return $tests;
365 }
366}
367
368class Twig_TemplateTest extends Twig_Template
369{
370 protected $useExtGetAttribute = false;
371
372 public function __construct(Twig_Environment $env, $useExtGetAttribute = false)
373 {
374 parent::__construct($env);
375 $this->useExtGetAttribute = $useExtGetAttribute;
376 Twig_Template::clearCache();
377 }
378
379 public function getZero()
380 {
381 return 0;
382 }
383
384 public function getEmpty()
385 {
386 return '';
387 }
388
389 public function getString()
390 {
391 return 'some_string';
392 }
393
394 public function getTrue()
395 {
396 return true;
397 }
398
399 public function getTemplateName()
400 {
401 }
402
403 public function getDebugInfo()
404 {
405 return array();
406 }
407
408 protected function doGetParent(array $context)
409 {
410 }
411
412 protected function doDisplay(array $context, array $blocks = array())
413 {
414 }
415
416 public function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
417 {
418 if ($this->useExtGetAttribute) {
419 return twig_template_get_attributes($this, $object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
420 } else {
421 return parent::getAttribute($object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
422 }
423 }
424}
425
426class Twig_TemplateArrayAccessObject implements ArrayAccess
427{
428 protected $protected = 'protected';
429
430 public $attributes = array(
431 'defined' => 'defined',
432 'zero' => 0,
433 'null' => null,
434 '1' => 1,
435 'bar' => true,
436 '09' => '09',
437 '+4' => '+4',
438 );
439
440 public function offsetExists($name)
441 {
442 return array_key_exists($name, $this->attributes);
443 }
444
445 public function offsetGet($name)
446 {
447 return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
448 }
449
450 public function offsetSet($name, $value)
451 {
452 }
453
454 public function offsetUnset($name)
455 {
456 }
457}
458
459class Twig_TemplateMagicPropertyObject
460{
461 public $defined = 'defined';
462
463 public $attributes = array(
464 'zero' => 0,
465 'null' => null,
466 '1' => 1,
467 'bar' => true,
468 '09' => '09',
469 '+4' => '+4',
470 );
471
472 protected $protected = 'protected';
473
474 public function __isset($name)
475 {
476 return array_key_exists($name, $this->attributes);
477 }
478
479 public function __get($name)
480 {
481 return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
482 }
483}
484
485class Twig_TemplateMagicPropertyObjectWithException
486{
487 public function __isset($key)
488 {
489 throw new Exception("Hey! Don't try to isset me!");
490 }
491}
492
493class Twig_TemplatePropertyObject
494{
495 public $defined = 'defined';
496 public $zero = 0;
497 public $null = null;
498 public $bar = true;
499
500 protected $protected = 'protected';
501}
502
503class Twig_TemplatePropertyObjectAndIterator extends Twig_TemplatePropertyObject implements IteratorAggregate
504{
505 public function getIterator()
506 {
507 return new ArrayIterator(array('foo', 'bar'));
508 }
509}
510
511class Twig_TemplatePropertyObjectAndArrayAccess extends Twig_TemplatePropertyObject implements ArrayAccess
512{
513 private $data = array();
514
515 public function offsetExists($offset)
516 {
517 return array_key_exists($offset, $this->data);
518 }
519
520 public function offsetGet($offset)
521 {
522 return $this->offsetExists($offset) ? $this->data[$offset] : 'n/a';
523 }
524
525 public function offsetSet($offset, $value)
526 {
527 }
528
529 public function offsetUnset($offset)
530 {
531 }
532}
533
534class Twig_TemplateMethodObject
535{
536 public function getDefined()
537 {
538 return 'defined';
539 }
540
541 public function get1()
542 {
543 return 1;
544 }
545
546 public function get09()
547 {
548 return '09';
549 }
550
551 public function getZero()
552 {
553 return 0;
554 }
555
556 public function getNull()
557 {
558 return null;
559 }
560
561 public function isBar()
562 {
563 return true;
564 }
565
566 protected function getProtected()
567 {
568 return 'protected';
569 }
570
571 public static function getStatic()
572 {
573 return 'static';
574 }
575}
576
577class Twig_TemplateMethodAndPropObject
578{
579 private $a = 'a_prop';
580 public function getA()
581 {
582 return 'a';
583 }
584
585 public $b = 'b_prop';
586 public function getB()
587 {
588 return 'b';
589 }
590
591 private $c = 'c_prop';
592 private function getC()
593 {
594 return 'c';
595 }
596}
597
598class Twig_TemplateMagicMethodObject
599{
600 public function __call($method, $arguments)
601 {
602 return '__call_'.$method;
603 }
604}
605
606class CExtDisablingNodeVisitor implements Twig_NodeVisitorInterface
607{
608 public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
609 {
610 if ($node instanceof Twig_Node_Expression_GetAttr) {
611 $node->setAttribute('disable_c_ext', true);
612 }
613
614 return $node;
615 }
616
617 public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
618 {
619 return $node;
620 }
621
622 public function getPriority()
623 {
624 return 0;
625 }
626}
diff --git a/vendor/twig/twig/test/Twig/Tests/TokenStreamTest.php b/vendor/twig/twig/test/Twig/Tests/TokenStreamTest.php
new file mode 100644
index 00000000..fd4ec633
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/TokenStreamTest.php
@@ -0,0 +1,70 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12class Twig_Tests_TokenStreamTest extends PHPUnit_Framework_TestCase
13{
14 protected static $tokens;
15
16 public function setUp()
17 {
18 self::$tokens = array(
19 new Twig_Token(Twig_Token::TEXT_TYPE, 1, 1),
20 new Twig_Token(Twig_Token::TEXT_TYPE, 2, 1),
21 new Twig_Token(Twig_Token::TEXT_TYPE, 3, 1),
22 new Twig_Token(Twig_Token::TEXT_TYPE, 4, 1),
23 new Twig_Token(Twig_Token::TEXT_TYPE, 5, 1),
24 new Twig_Token(Twig_Token::TEXT_TYPE, 6, 1),
25 new Twig_Token(Twig_Token::TEXT_TYPE, 7, 1),
26 new Twig_Token(Twig_Token::EOF_TYPE, 0, 1),
27 );
28 }
29
30 public function testNext()
31 {
32 $stream = new Twig_TokenStream(self::$tokens);
33 $repr = array();
34 while (!$stream->isEOF()) {
35 $token = $stream->next();
36
37 $repr[] = $token->getValue();
38 }
39 $this->assertEquals('1, 2, 3, 4, 5, 6, 7', implode(', ', $repr), '->next() advances the pointer and returns the current token');
40 }
41
42 /**
43 * @expectedException Twig_Error_Syntax
44 * @expectedMessage Unexpected end of template
45 */
46 public function testEndOfTemplateNext()
47 {
48 $stream = new Twig_TokenStream(array(
49 new Twig_Token(Twig_Token::BLOCK_START_TYPE, 1, 1),
50 ));
51 while (!$stream->isEOF()) {
52 $stream->next();
53 }
54 }
55
56 /**
57 * @expectedException Twig_Error_Syntax
58 * @expectedMessage Unexpected end of template
59 */
60 public function testEndOfTemplateLook()
61 {
62 $stream = new Twig_TokenStream(array(
63 new Twig_Token(Twig_Token::BLOCK_START_TYPE, 1, 1),
64 ));
65 while (!$stream->isEOF()) {
66 $stream->look();
67 $stream->next();
68 }
69 }
70}
diff --git a/vendor/twig/twig/test/Twig/Tests/escapingTest.php b/vendor/twig/twig/test/Twig/Tests/escapingTest.php
new file mode 100644
index 00000000..b41b5f97
--- /dev/null
+++ b/vendor/twig/twig/test/Twig/Tests/escapingTest.php
@@ -0,0 +1,320 @@
1<?php
2
3/**
4 * This class is adapted from code coming from Zend Framework.
5 *
6 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10class Twig_Test_EscapingTest extends PHPUnit_Framework_TestCase
11{
12 /**
13 * All character encodings supported by htmlspecialchars()
14 */
15 protected $htmlSpecialChars = array(
16 '\'' => '&#039;',
17 '"' => '&quot;',
18 '<' => '&lt;',
19 '>' => '&gt;',
20 '&' => '&amp;'
21 );
22
23 protected $htmlAttrSpecialChars = array(
24 '\'' => '&#x27;',
25 /* Characters beyond ASCII value 255 to unicode escape */
26 'Ā' => '&#x0100;',
27 /* Immune chars excluded */
28 ',' => ',',
29 '.' => '.',
30 '-' => '-',
31 '_' => '_',
32 /* Basic alnums excluded */
33 'a' => 'a',
34 'A' => 'A',
35 'z' => 'z',
36 'Z' => 'Z',
37 '0' => '0',
38 '9' => '9',
39 /* Basic control characters and null */
40 "\r" => '&#x0D;',
41 "\n" => '&#x0A;',
42 "\t" => '&#x09;',
43 "\0" => '&#xFFFD;', // should use Unicode replacement char
44 /* Encode chars as named entities where possible */
45 '<' => '&lt;',
46 '>' => '&gt;',
47 '&' => '&amp;',
48 '"' => '&quot;',
49 /* Encode spaces for quoteless attribute protection */
50 ' ' => '&#x20;',
51 );
52
53 protected $jsSpecialChars = array(
54 /* HTML special chars - escape without exception to hex */
55 '<' => '\\x3C',
56 '>' => '\\x3E',
57 '\'' => '\\x27',
58 '"' => '\\x22',
59 '&' => '\\x26',
60 /* Characters beyond ASCII value 255 to unicode escape */
61 'Ā' => '\\u0100',
62 /* Immune chars excluded */
63 ',' => ',',
64 '.' => '.',
65 '_' => '_',
66 /* Basic alnums excluded */
67 'a' => 'a',
68 'A' => 'A',
69 'z' => 'z',
70 'Z' => 'Z',
71 '0' => '0',
72 '9' => '9',
73 /* Basic control characters and null */
74 "\r" => '\\x0D',
75 "\n" => '\\x0A',
76 "\t" => '\\x09',
77 "\0" => '\\x00',
78 /* Encode spaces for quoteless attribute protection */
79 ' ' => '\\x20',
80 );
81
82 protected $urlSpecialChars = array(
83 /* HTML special chars - escape without exception to percent encoding */
84 '<' => '%3C',
85 '>' => '%3E',
86 '\'' => '%27',
87 '"' => '%22',
88 '&' => '%26',
89 /* Characters beyond ASCII value 255 to hex sequence */
90 'Ā' => '%C4%80',
91 /* Punctuation and unreserved check */
92 ',' => '%2C',
93 '.' => '.',
94 '_' => '_',
95 '-' => '-',
96 ':' => '%3A',
97 ';' => '%3B',
98 '!' => '%21',
99 /* Basic alnums excluded */
100 'a' => 'a',
101 'A' => 'A',
102 'z' => 'z',
103 'Z' => 'Z',
104 '0' => '0',
105 '9' => '9',
106 /* Basic control characters and null */
107 "\r" => '%0D',
108 "\n" => '%0A',
109 "\t" => '%09',
110 "\0" => '%00',
111 /* PHP quirks from the past */
112 ' ' => '%20',
113 '~' => '~',
114 '+' => '%2B',
115 );
116
117 protected $cssSpecialChars = array(
118 /* HTML special chars - escape without exception to hex */
119 '<' => '\\3C ',
120 '>' => '\\3E ',
121 '\'' => '\\27 ',
122 '"' => '\\22 ',
123 '&' => '\\26 ',
124 /* Characters beyond ASCII value 255 to unicode escape */
125 'Ā' => '\\100 ',
126 /* Immune chars excluded */
127 ',' => '\\2C ',
128 '.' => '\\2E ',
129 '_' => '\\5F ',
130 /* Basic alnums excluded */
131 'a' => 'a',
132 'A' => 'A',
133 'z' => 'z',
134 'Z' => 'Z',
135 '0' => '0',
136 '9' => '9',
137 /* Basic control characters and null */
138 "\r" => '\\D ',
139 "\n" => '\\A ',
140 "\t" => '\\9 ',
141 "\0" => '\\0 ',
142 /* Encode spaces for quoteless attribute protection */
143 ' ' => '\\20 ',
144 );
145
146 protected $env;
147
148 public function setUp()
149 {
150 $this->env = new Twig_Environment();
151 }
152
153 public function testHtmlEscapingConvertsSpecialChars()
154 {
155 foreach ($this->htmlSpecialChars as $key => $value) {
156 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html'), 'Failed to escape: '.$key);
157 }
158 }
159
160 public function testHtmlAttributeEscapingConvertsSpecialChars()
161 {
162 foreach ($this->htmlAttrSpecialChars as $key => $value) {
163 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html_attr'), 'Failed to escape: '.$key);
164 }
165 }
166
167 public function testJavascriptEscapingConvertsSpecialChars()
168 {
169 foreach ($this->jsSpecialChars as $key => $value) {
170 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'js'), 'Failed to escape: '.$key);
171 }
172 }
173
174 public function testJavascriptEscapingReturnsStringIfZeroLength()
175 {
176 $this->assertEquals('', twig_escape_filter($this->env, '', 'js'));
177 }
178
179 public function testJavascriptEscapingReturnsStringIfContainsOnlyDigits()
180 {
181 $this->assertEquals('123', twig_escape_filter($this->env, '123', 'js'));
182 }
183
184 public function testCssEscapingConvertsSpecialChars()
185 {
186 foreach ($this->cssSpecialChars as $key => $value) {
187 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'css'), 'Failed to escape: '.$key);
188 }
189 }
190
191 public function testCssEscapingReturnsStringIfZeroLength()
192 {
193 $this->assertEquals('', twig_escape_filter($this->env, '', 'css'));
194 }
195
196 public function testCssEscapingReturnsStringIfContainsOnlyDigits()
197 {
198 $this->assertEquals('123', twig_escape_filter($this->env, '123', 'css'));
199 }
200
201 public function testUrlEscapingConvertsSpecialChars()
202 {
203 foreach ($this->urlSpecialChars as $key => $value) {
204 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'url'), 'Failed to escape: '.$key);
205 }
206 }
207
208 /**
209 * Range tests to confirm escaped range of characters is within OWASP recommendation
210 */
211
212 /**
213 * Only testing the first few 2 ranges on this prot. function as that's all these
214 * other range tests require
215 */
216 public function testUnicodeCodepointConversionToUtf8()
217 {
218 $expected = " ~ޙ";
219 $codepoints = array(0x20, 0x7e, 0x799);
220 $result = '';
221 foreach ($codepoints as $value) {
222 $result .= $this->codepointToUtf8($value);
223 }
224 $this->assertEquals($expected, $result);
225 }
226
227 /**
228 * Convert a Unicode Codepoint to a literal UTF-8 character.
229 *
230 * @param int Unicode codepoint in hex notation
231 * @return string UTF-8 literal string
232 */
233 protected function codepointToUtf8($codepoint)
234 {
235 if ($codepoint < 0x80) {
236 return chr($codepoint);
237 }
238 if ($codepoint < 0x800) {
239 return chr($codepoint >> 6 & 0x3f | 0xc0)
240 . chr($codepoint & 0x3f | 0x80);
241 }
242 if ($codepoint < 0x10000) {
243 return chr($codepoint >> 12 & 0x0f | 0xe0)
244 . chr($codepoint >> 6 & 0x3f | 0x80)
245 . chr($codepoint & 0x3f | 0x80);
246 }
247 if ($codepoint < 0x110000) {
248 return chr($codepoint >> 18 & 0x07 | 0xf0)
249 . chr($codepoint >> 12 & 0x3f | 0x80)
250 . chr($codepoint >> 6 & 0x3f | 0x80)
251 . chr($codepoint & 0x3f | 0x80);
252 }
253 throw new Exception('Codepoint requested outside of Unicode range');
254 }
255
256 public function testJavascriptEscapingEscapesOwaspRecommendedRanges()
257 {
258 $immune = array(',', '.', '_'); // Exceptions to escaping ranges
259 for ($chr=0; $chr < 0xFF; $chr++) {
260 if ($chr >= 0x30 && $chr <= 0x39
261 || $chr >= 0x41 && $chr <= 0x5A
262 || $chr >= 0x61 && $chr <= 0x7A) {
263 $literal = $this->codepointToUtf8($chr);
264 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js'));
265 } else {
266 $literal = $this->codepointToUtf8($chr);
267 if (in_array($literal, $immune)) {
268 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js'));
269 } else {
270 $this->assertNotEquals(
271 $literal,
272 twig_escape_filter($this->env, $literal, 'js'),
273 "$literal should be escaped!");
274 }
275 }
276 }
277 }
278
279 public function testHtmlAttributeEscapingEscapesOwaspRecommendedRanges()
280 {
281 $immune = array(',', '.', '-', '_'); // Exceptions to escaping ranges
282 for ($chr=0; $chr < 0xFF; $chr++) {
283 if ($chr >= 0x30 && $chr <= 0x39
284 || $chr >= 0x41 && $chr <= 0x5A
285 || $chr >= 0x61 && $chr <= 0x7A) {
286 $literal = $this->codepointToUtf8($chr);
287 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr'));
288 } else {
289 $literal = $this->codepointToUtf8($chr);
290 if (in_array($literal, $immune)) {
291 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr'));
292 } else {
293 $this->assertNotEquals(
294 $literal,
295 twig_escape_filter($this->env, $literal, 'html_attr'),
296 "$literal should be escaped!");
297 }
298 }
299 }
300 }
301
302 public function testCssEscapingEscapesOwaspRecommendedRanges()
303 {
304 $immune = array(); // CSS has no exceptions to escaping ranges
305 for ($chr=0; $chr < 0xFF; $chr++) {
306 if ($chr >= 0x30 && $chr <= 0x39
307 || $chr >= 0x41 && $chr <= 0x5A
308 || $chr >= 0x61 && $chr <= 0x7A) {
309 $literal = $this->codepointToUtf8($chr);
310 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'css'));
311 } else {
312 $literal = $this->codepointToUtf8($chr);
313 $this->assertNotEquals(
314 $literal,
315 twig_escape_filter($this->env, $literal, 'css'),
316 "$literal should be escaped!");
317 }
318 }
319 }
320}
diff --git a/vendor/twig/twig/test/bootstrap.php b/vendor/twig/twig/test/bootstrap.php
new file mode 100644
index 00000000..aecb976f
--- /dev/null
+++ b/vendor/twig/twig/test/bootstrap.php
@@ -0,0 +1,13 @@
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12require_once dirname(__FILE__).'/../lib/Twig/Autoloader.php';
13Twig_Autoloader::register(true);
diff --git a/vendor/umpirsky/twig-gettext-extractor/.gitignore b/vendor/umpirsky/twig-gettext-extractor/.gitignore
new file mode 100644
index 00000000..61381e45
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/.gitignore
@@ -0,0 +1,3 @@
1vendor
2phpunit.xml
3composer.lock
diff --git a/vendor/umpirsky/twig-gettext-extractor/.travis.yml b/vendor/umpirsky/twig-gettext-extractor/.travis.yml
new file mode 100644
index 00000000..0c9bce01
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/.travis.yml
@@ -0,0 +1,10 @@
1language: php
2
3before_script:
4 - curl -s http://getcomposer.org/installer | php
5 - php composer.phar install --dev
6
7php:
8 - 5.3
9 - 5.4
10
diff --git a/vendor/umpirsky/twig-gettext-extractor/LICENSE b/vendor/umpirsky/twig-gettext-extractor/LICENSE
new file mode 100644
index 00000000..df9dd107
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) Саша Стаменковић <umpirsky@gmail.com>
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. \ No newline at end of file
diff --git a/vendor/umpirsky/twig-gettext-extractor/README.md b/vendor/umpirsky/twig-gettext-extractor/README.md
new file mode 100644
index 00000000..34eff88c
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/README.md
@@ -0,0 +1,49 @@
1Twig Gettext Extractor [![Build Status](https://secure.travis-ci.org/umpirsky/Twig-Gettext-Extractor.png?branch=master)](http://travis-ci.org/umpirsky/Twig-Gettext-Extractor)
2======================
3
4The Twig Gettext Extractor is [Poedit](http://www.poedit.net/download.php)
5friendly tool which extracts translations from twig templates.
6
7## Installation
8
9The recommended way to install Twig Gettext Extractor is through
10[composer](http://getcomposer.org).
11
12```json
13{
14 "require": {
15 "umpirsky/twig-gettext-extractor": "1.1.*"
16 }
17}
18```
19
20## Setup
21
22By default, Poedit does not have the ability to parse Twig templates.
23This can be resolved by adding an additional parser (Edit > Preferences > Parsers)
24with the following options:
25
26- Language: `Twig`
27- List of extensions: `*.twig`
28- Invocation:
29 - Parser command: `<project>/vendor/bin/twig-gettext-extractor --sort-output --force-po -o %o %C %K -L PHP --files %F`
30 - An item in keyword list: `-k%k`
31 - An item in input file list: `%f`
32 - Source code charset: `--from-code=%c`
33
34<img src="http://i.imgur.com/f9px2.png" />
35
36Now you can update your catalog and Poedit will synchronize it with your twig
37templates.
38
39## Tests
40
41To run the test suite, you need [composer](http://getcomposer.org) and
42[PHPUnit](https://github.com/sebastianbergmann/phpunit).
43
44 $ composer install --dev
45 $ phpunit
46
47## License
48
49Twig Gettext Extractor is licensed under the MIT license.
diff --git a/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Extractor.php b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Extractor.php
new file mode 100644
index 00000000..e7fa1af2
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Extractor.php
@@ -0,0 +1,95 @@
1<?php
2
3/**
4 * This file is part of the Twig Gettext utility.
5 *
6 * (c) Саша Стаменковић <umpirsky@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Twig\Gettext;
13
14use Symfony\Component\Filesystem\Filesystem;
15
16/**
17 * Extracts translations from twig templates.
18 *
19 * @author Саша Стаменковић <umpirsky@gmail.com>
20 */
21class Extractor
22{
23 /**
24 * @var \Twig_Environment
25 */
26 protected $environment;
27
28 /**
29 * Template cached file names.
30 *
31 * @var string[]
32 */
33 protected $templates;
34
35 /**
36 * Gettext parameters.
37 *
38 * @var string[]
39 */
40 protected $parameters;
41
42 public function __construct(\Twig_Environment $environment)
43 {
44 $this->environment = $environment;
45 $this->reset();
46 }
47
48 protected function reset()
49 {
50 $this->templates = array();
51 $this->parameters = array();
52 }
53
54 public function addTemplate($path)
55 {
56 $this->environment->loadTemplate($path);
57 $this->templates[] = $this->environment->getCacheFilename($path);
58 }
59
60 public function addGettextParameter($parameter)
61 {
62 $this->parameters[] = $parameter;
63 }
64
65 public function setGettextParameters(array $parameters)
66 {
67 $this->parameters = $parameters;
68 }
69
70 public function extract()
71 {
72 $command = 'xgettext';
73 $command .= ' '.join(' ', $this->parameters);
74 $command .= ' '.join(' ', $this->templates);
75
76 $error = 0;
77 $output = system($command, $error);
78 if (0 !== $error) {
79 throw new \RuntimeException(sprintf(
80 'Gettext command "%s" failed with error code %s and output: %s',
81 $command,
82 $error,
83 $output
84 ));
85 }
86
87 $this->reset();
88 }
89
90 public function __destruct()
91 {
92 $filesystem = new Filesystem();
93 $filesystem->remove($this->environment->getCache());
94 }
95}
diff --git a/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Loader/Filesystem.php b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Loader/Filesystem.php
new file mode 100644
index 00000000..b011b032
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Loader/Filesystem.php
@@ -0,0 +1,58 @@
1<?php
2
3/**
4 * This file is part of the Twig Gettext utility.
5 *
6 * (c) Саша Стаменковић <umpirsky@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Twig\Gettext\Loader;
13
14/**
15 * Loads template from the filesystem.
16 *
17 * @author Саша Стаменковић <umpirsky@gmail.com>
18 */
19class Filesystem extends \Twig_Loader_Filesystem
20{
21 /**
22 * Hacked find template to allow loading templates by absolute path.
23 *
24 * @param string $name template name or absolute path
25 */
26 protected function findTemplate($name)
27 {
28 // normalize name
29 $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'));
30
31 if (isset($this->cache[$name])) {
32 return $this->cache[$name];
33 }
34
35 $this->validateName($name);
36
37 $namespace = '__main__';
38 if (isset($name[0]) && '@' == $name[0]) {
39 if (false === $pos = strpos($name, '/')) {
40 throw new \InvalidArgumentException(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
41 }
42
43 $namespace = substr($name, 1, $pos - 1);
44
45 $name = substr($name, $pos + 1);
46 }
47
48 if (!isset($this->paths[$namespace])) {
49 throw new \Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
50 }
51
52 if (is_file($name)) {
53 return $this->cache[$name] = $name;
54 }
55
56 return __DIR__.'/../Test/Fixtures/twig/empty.twig';
57 }
58}
diff --git a/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Routing/Generator/UrlGenerator.php b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Routing/Generator/UrlGenerator.php
new file mode 100644
index 00000000..9e3431bd
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Routing/Generator/UrlGenerator.php
@@ -0,0 +1,39 @@
1<?php
2
3/**
4 * This file is part of the Twig Gettext utility.
5 *
6 * (c) Саша Стаменковић <umpirsky@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Twig\Gettext\Routing\Generator;
13
14use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15use Symfony\Component\Routing\RequestContext;
16
17/**
18 * Dummy url generator.
19 *
20 * @author Саша Стаменковић <umpirsky@gmail.com>
21 */
22class UrlGenerator implements UrlGeneratorInterface
23{
24 protected $context;
25
26 public function generate($name, $parameters = array(), $absolute = false)
27 {
28 }
29
30 public function getContext()
31 {
32 return $this->context;
33 }
34
35 public function setContext(RequestContext $context)
36 {
37 $this->context = $context;
38 }
39}
diff --git a/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/ExtractorTest.php b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/ExtractorTest.php
new file mode 100644
index 00000000..d467835f
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/ExtractorTest.php
@@ -0,0 +1,123 @@
1<?php
2
3/**
4 * This file is part of the Twig Gettext utility.
5 *
6 * (c) Саша Стаменковић <umpirsky@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Twig\Gettext\Test;
13
14use Twig\Gettext\Extractor;
15use Twig\Gettext\Loader\Filesystem;
16use Symfony\Component\Translation\Loader\PoFileLoader;
17
18/**
19 * @author Саша Стаменковић <umpirsky@gmail.com>
20 */
21class ExtractorTest extends \PHPUnit_Framework_TestCase
22{
23 /**
24 * @var \Twig_Environment
25 */
26 protected $twig;
27
28 /**
29 * @var PoFileLoader
30 */
31 protected $loader;
32
33 protected function setUp()
34 {
35 $this->twig = new \Twig_Environment(new Filesystem('/'), array(
36 'cache' => '/tmp/cache/'.uniqid(),
37 'auto_reload' => true
38 ));
39 $this->twig->addExtension(new \Twig_Extensions_Extension_I18n());
40
41 $this->loader = new PoFileLoader();
42 }
43
44 /**
45 * @dataProvider testExtractDataProvider
46 */
47 public function testExtract(array $templates, array $parameters, array $messages)
48 {
49 $extractor = new Extractor($this->twig);
50
51 foreach ($templates as $template) {
52 $extractor->addTemplate($template);
53 }
54 foreach ($parameters as $parameter) {
55 $extractor->addGettextParameter($parameter);
56 }
57
58 $extractor->extract();
59
60 $catalog = $this->loader->load($this->getPotFile(), null);
61
62 foreach ($messages as $message) {
63 $this->assertTrue(
64 $catalog->has($message),
65 sprintf('Message "%s" not found in catalog.', $message)
66 );
67 }
68 }
69
70 public function testExtractDataProvider()
71 {
72 return array(
73 array(
74 array(
75 __DIR__.'/Fixtures/twig/singular.twig',
76 __DIR__.'/Fixtures/twig/plural.twig',
77 ),
78 $this->getGettextParameters(),
79 array(
80 'Hello %name%!',
81 'Hello World!',
82 'Hey %name%, I have one apple.',
83 'Hey %name%, I have %count% apples.',
84 ),
85 ),
86 );
87 }
88
89 public function testExtractNoTranslations()
90 {
91 $extractor = new Extractor($this->twig);
92
93 $extractor->addTemplate(__DIR__.'/Fixtures/twig/empty.twig');
94 $extractor->setGettextParameters($this->getGettextParameters());
95
96 $extractor->extract();
97
98 $catalog = $this->loader->load($this->getPotFile(), null);
99
100 $this->assertEmpty($catalog->all('messages'));
101 }
102
103 private function getPotFile()
104 {
105 return __DIR__.'/Fixtures/messages.pot';
106 }
107
108 private function getGettextParameters()
109 {
110 return array(
111 '--force-po',
112 '-o',
113 $this->getPotFile(),
114 );
115 }
116
117 protected function tearDown()
118 {
119 if (file_exists($this->getPotFile())) {
120 unlink($this->getPotFile());
121 }
122 }
123}
diff --git a/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/empty.twig b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/empty.twig
new file mode 100644
index 00000000..05f0d26a
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/empty.twig
@@ -0,0 +1 @@
Nothing to translate here.
diff --git a/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/plural.twig b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/plural.twig
new file mode 100644
index 00000000..f9754ff4
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/plural.twig
@@ -0,0 +1,5 @@
1{% trans %}
2 Hey {{ name }}, I have one apple.
3{% plural apple_count %}
4 Hey {{ name }}, I have {{ count }} apples.
5{% endtrans %}
diff --git a/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/singular.twig b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/singular.twig
new file mode 100644
index 00000000..d757cf90
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/Twig/Gettext/Test/Fixtures/twig/singular.twig
@@ -0,0 +1,9 @@
1{% trans "Hello World!" %}
2
3{% trans %}
4 Hello World!
5{% endtrans %}
6
7{% trans %}
8 Hello {{ name }}!
9{% endtrans %}
diff --git a/vendor/umpirsky/twig-gettext-extractor/composer.json b/vendor/umpirsky/twig-gettext-extractor/composer.json
new file mode 100644
index 00000000..7cda5f73
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/composer.json
@@ -0,0 +1,30 @@
1{
2 "name": "umpirsky/twig-gettext-extractor",
3 "type": "application",
4 "description": "The Twig Gettext Extractor is Poedit friendly tool which extracts translations from twig templates.",
5 "license": "MIT",
6 "authors": [
7 {
8 "name": "Саша Стаменковић",
9 "email": "umpirsky@gmail.com"
10 }
11 ],
12 "require": {
13 "php": ">=5.3.3",
14 "twig/twig": ">=1.2.0,<2.0-dev",
15 "twig/extensions": "1.0.*",
16 "symfony/twig-bridge": ">=2.0,<3.0",
17 "symfony/routing": ">=2.0,<3.0",
18 "symfony/filesystem": ">=2.0,<3.0",
19 "symfony/translation": ">=2.0,<3.0",
20 "symfony/form": ">=2.0,<3.0"
21 },
22 "require-dev": {
23 "symfony/config": "2.1.*"
24 },
25 "minimum-stability": "dev",
26 "autoload": {
27 "psr-0": { "Twig\\Gettext": "." }
28 },
29 "bin": ["twig-gettext-extractor"]
30} \ No newline at end of file
diff --git a/vendor/umpirsky/twig-gettext-extractor/phpunit.xml.dist b/vendor/umpirsky/twig-gettext-extractor/phpunit.xml.dist
new file mode 100644
index 00000000..56fdc6b0
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/phpunit.xml.dist
@@ -0,0 +1,14 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit colors="true"
4 convertErrorsToExceptions="true"
5 convertNoticesToExceptions="true"
6 convertWarningsToExceptions="true"
7 bootstrap="./vendor/autoload.php"
8>
9 <testsuites>
10 <testsuite name="Twig Gettext Extractor Test Suite">
11 <directory>./Twig/Gettext/Test/</directory>
12 </testsuite>
13 </testsuites>
14</phpunit>
diff --git a/vendor/umpirsky/twig-gettext-extractor/twig-gettext-extractor b/vendor/umpirsky/twig-gettext-extractor/twig-gettext-extractor
new file mode 100755
index 00000000..6cc97c1d
--- /dev/null
+++ b/vendor/umpirsky/twig-gettext-extractor/twig-gettext-extractor
@@ -0,0 +1,58 @@
1#!/usr/bin/env php
2<?php
3
4/**
5 * This file is part of the Twig Gettext utility.
6 *
7 * (c) Саша Стаменковић <umpirsky@gmail.com>
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13/**
14 * Extracts translations from twig templates.
15 *
16 * @author Саша Стаменковић <umpirsky@gmail.com>
17 */
18
19if (file_exists($a = __DIR__.'/../../autoload.php')) {
20 require_once $a;
21} else {
22 require_once __DIR__.'/vendor/autoload.php';
23}
24
25$twig = new Twig_Environment(new Twig\Gettext\Loader\Filesystem('/'), array(
26 'cache' => '/tmp/cache/'.uniqid(),
27 'auto_reload' => true
28));
29$twig->addExtension(new Symfony\Bridge\Twig\Extension\TranslationExtension(
30 new Symfony\Component\Translation\Translator(null)
31));
32$twig->addExtension(new Twig_Extensions_Extension_I18n());
33$twig->addExtension(new Symfony\Bridge\Twig\Extension\RoutingExtension(
34 new Twig\Gettext\Routing\Generator\UrlGenerator()
35));
36$twig->addExtension(new Symfony\Bridge\Twig\Extension\FormExtension(
37 new Symfony\Bridge\Twig\Form\TwigRenderer(
38 new Symfony\Bridge\Twig\Form\TwigRendererEngine()
39 )
40));
41// You can add more extensions here.
42
43array_shift($_SERVER['argv']);
44$addTemplate = false;
45
46$extractor = new Twig\Gettext\Extractor($twig);
47
48foreach ($_SERVER['argv'] as $arg) {
49 if ('--files' == $arg) {
50 $addTemplate = true;
51 } else if ($addTemplate) {
52 $extractor->addTemplate(getcwd().DIRECTORY_SEPARATOR.$arg);
53 } else {
54 $extractor->addGettextParameter($arg);
55 }
56}
57
58$extractor->extract();