From d9c83a79cfeb98ce66742adf96134ef5de009220 Mon Sep 17 00:00:00 2001
From: Roland Golla <rolandgolla@gmail.com>
Date: Sun, 19 Mar 2017 15:42:39 +0100
Subject: [PATCH] [FEATURE] URL validator for Extbase

Add a new Extbase validator to check if a value is a valid URL.

Change-Id: Ic4ce6ee0f8a38f082e869c094ae6013493d7fb96
Resolves: #80342
Releases: master
Reviewed-on: https://review.typo3.org/52092
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: Andreas Fernandez <typo3@scripting-base.de>
---
 .../Feature-80342-ExtbaseValidatorForURLs.rst |  20 +++
 .../Validation/Validator/UrlValidator.php     |  45 +++++++
 .../Resources/Private/Language/locallang.xlf  |   3 +
 .../Validation/Validator/UrlValidatorTest.php | 126 ++++++++++++++++++
 4 files changed, 194 insertions(+)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-80342-ExtbaseValidatorForURLs.rst
 create mode 100644 typo3/sysext/extbase/Classes/Validation/Validator/UrlValidator.php
 create mode 100644 typo3/sysext/extbase/Tests/Unit/Validation/Validator/UrlValidatorTest.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-80342-ExtbaseValidatorForURLs.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-80342-ExtbaseValidatorForURLs.rst
new file mode 100644
index 000000000000..a83d9fba971c
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-80342-ExtbaseValidatorForURLs.rst
@@ -0,0 +1,20 @@
+.. include:: ../../Includes.txt
+
+============================================
+Feature: #80342 - Extbase validator for URLs
+============================================
+
+See :issue:`80342`
+
+Description
+===========
+
+It is now possible to validate URLs in an Extbase model.
+
+
+Impact
+======
+
+Validation may be used by adding the annotation :php`@validate Url`.
+
+.. index:: PHP-API, NotScanned
diff --git a/typo3/sysext/extbase/Classes/Validation/Validator/UrlValidator.php b/typo3/sysext/extbase/Classes/Validation/Validator/UrlValidator.php
new file mode 100644
index 000000000000..04f2c3f843d9
--- /dev/null
+++ b/typo3/sysext/extbase/Classes/Validation/Validator/UrlValidator.php
@@ -0,0 +1,45 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Extbase\Validation\Validator;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Validator for url.
+ *
+ * @api
+ */
+class UrlValidator extends AbstractValidator
+{
+    /**
+     * Checks if the given value is a string.
+     *
+     * @param mixed $value The value that should be validated
+     * @api
+     */
+    public function isValid($value)
+    {
+        if (!is_string($value) || !GeneralUtility::isValidUrl($value)) {
+            $this->addError(
+                $this->translateErrorMessage(
+                    'validator.url.notvalid',
+                    'extbase'
+                ),
+                1238108078
+            );
+        }
+    }
+}
diff --git a/typo3/sysext/extbase/Resources/Private/Language/locallang.xlf b/typo3/sysext/extbase/Resources/Private/Language/locallang.xlf
index 731f2062791d..a2b9a809bec1 100644
--- a/typo3/sysext/extbase/Resources/Private/Language/locallang.xlf
+++ b/typo3/sysext/extbase/Resources/Private/Language/locallang.xlf
@@ -69,6 +69,9 @@
 			<trans-unit id="validator.boolean.notfalse">
 				<source>The given subject was not false.</source>
 			</trans-unit>
+			<trans-unit id="validator.url.notvalid">
+				<source>The given subject is no valid URL.</source>
+			</trans-unit>
 		</body>
 	</file>
 </xliff>
diff --git a/typo3/sysext/extbase/Tests/Unit/Validation/Validator/UrlValidatorTest.php b/typo3/sysext/extbase/Tests/Unit/Validation/Validator/UrlValidatorTest.php
new file mode 100644
index 000000000000..a21a826393f8
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Unit/Validation/Validator/UrlValidatorTest.php
@@ -0,0 +1,126 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Extbase\Tests\Unit\Validation\Validator;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Test case
+ */
+class UrlValidatorTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
+{
+    /**
+     * @var string
+     */
+    protected $validatorClassName = \TYPO3\CMS\Extbase\Validation\Validator\UrlValidator::class;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Validation\Validator\UrlValidator
+     */
+    protected $validator;
+
+    protected function setUp()
+    {
+        $this->validator = $this->getMockBuilder($this->validatorClassName)
+            ->setMethods(['translateErrorMessage'])
+            ->getMock();
+    }
+
+    /**
+     * @return array
+     */
+    public function urlDataProvider(): array
+    {
+        return [
+            'Regular URL' => [
+                'value' => 'https://typo3.org/',
+                'isValid' => true,
+            ],
+            'Regular URL with subdomain' => [
+                'value' => 'https://testify.typo3.org/',
+                'isValid' => true,
+            ],
+            'Valid URL with trailing slash and path segment' => [
+                'value' => 'https://testify.typo3.org/testify/',
+                'isValid' => true,
+            ],
+            'Valid URL without trailing slash and path segment' => [
+                'value' => 'https://testify.typo3.org/testify',
+                'isValid' => true,
+            ],
+            'mailto' => [
+                'value' => 'mailto:foobar@example.com',
+                'isValid' => true,
+            ],
+            'mailto with subject' => [
+                'value' => 'mailto:foobar@example.com?subject=Unit+test+results',
+                'isValid' => true,
+            ],
+            'ftp' => [
+                'value' => 'ftp://remotestorage.org',
+                'isValid' => true,
+            ],
+            'tel' => [
+                'value' => 'tel:01189998819991197253',
+                'isValid' => true,
+            ],
+            'Some scheme that most likely does not exist' => [
+                'value' => 'monk://convert.wololo',
+                'isValid' => true,
+            ],
+            'Umlauts in domain' => [
+                'value' => 'https://bürgerkarte.at',
+                'isValid' => true,
+            ],
+            'Domain without protocol' => [
+                'value' => 'typo3.org',
+                'isValid' => false,
+            ],
+            'Empty value' => [
+                'value' => '',
+                'isValid' => true,
+            ],
+            'Null value' => [
+                'value' => null,
+                'isValid' => true,
+            ],
+            'Invalid value is only a string' => [
+                'value' => 'testify',
+                'isValid' => false,
+            ],
+            'Invalid value is integer' => [
+                'value' => 1,
+                'isValid' => false,
+            ],
+            'Invalid value is object' => [
+                'value' => new \stdClass,
+                'isValid' => false,
+            ],
+            'Invalid value is closure' => [
+                'value' => function () {
+                },
+                'isValid' => false,
+            ],
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider urlDataProvider
+     */
+    public function urlValidatorDetectsUrlsCorrectly($value, $expected)
+    {
+        $this->assertSame($expected, !$this->validator->validate($value)->hasErrors());
+    }
+}
-- 
GitLab