From 2e4bc9515730b5fc95d163e21682f2cb0082e92e Mon Sep 17 00:00:00 2001
From: Steve Boyd <emteknetnz@gmail.com>
Date: Fri, 2 Feb 2024 13:43:26 +1300
Subject: [PATCH] NEW Add UrlField

---
 src/Forms/UrlField.php           | 32 +++++++++++
 tests/php/Forms/UrlFieldTest.php | 93 ++++++++++++++++++++++++++++++++
 2 files changed, 125 insertions(+)
 create mode 100644 src/Forms/UrlField.php
 create mode 100644 tests/php/Forms/UrlFieldTest.php

diff --git a/src/Forms/UrlField.php b/src/Forms/UrlField.php
new file mode 100644
index 00000000000..a8332d87a7e
--- /dev/null
+++ b/src/Forms/UrlField.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace SilverStripe\Forms;
+
+use SilverStripe\Core\Validation\ConstraintValidator;
+use Symfony\Component\Validator\Constraints\Url;
+
+/**
+ * Text input field with validation for a url
+ * Url must include a scheme, either http:// or https://
+ */
+class UrlField extends TextField
+{
+    public function Type()
+    {
+        return 'text url';
+    }
+
+    public function validate($validator)
+    {
+        $result = true;
+        if ($this->value && !ConstraintValidator::validate($this->value, new Url())->isValid()) {
+            $validator->validationError(
+                $this->name,
+                _t(__CLASS__ . '.INVALID', 'Please enter a valid URL'),
+                'validation'
+            );
+            $result = false;
+        }
+        return $this->extendValidationResult($result, $validator);
+    }
+}
diff --git a/tests/php/Forms/UrlFieldTest.php b/tests/php/Forms/UrlFieldTest.php
new file mode 100644
index 00000000000..72cd2efb4d1
--- /dev/null
+++ b/tests/php/Forms/UrlFieldTest.php
@@ -0,0 +1,93 @@
+<?php
+
+namespace SilverStripe\Forms\Tests;
+
+use SilverStripe\Dev\SapphireTest;
+use SilverStripe\Forms\UrlField;
+use SilverStripe\Forms\RequiredFields;
+
+class UrlFieldTest extends SapphireTest
+{
+    public function provideValidate(): array
+    {
+        return [
+            [
+                'url' => '',
+                'valid' => true,
+            ],
+            [
+                'url' => '',
+                'valid' => true,
+            ],
+            [
+                'url' => 'http://example-123.com',
+                'valid' => true,
+            ],
+            [
+                'url' => 'https://example-123.com',
+                'valid' => true,
+            ],
+            [
+                'url' => 'ftp://example-123.com',
+                'valid' => false,
+            ],
+            [
+                'url' => 'http://example-123.com:8080',
+                'valid' => true,
+            ],
+            [
+                'url' => 'http://example_with_underscore_in_host.com',
+                'valid' => true,
+            ],
+            [
+                'url' => 'http://subdomain.example-123.com',
+                'valid' => true,
+            ],
+            [
+                'url' => 'http://subdomain_with_underscores.example-123.com',
+                'valid' => true,
+            ],
+            [
+                'url' => 'http://subdomain-with-dashes.example-123.com',
+                'valid' => true,
+            ],
+            [
+                'url' => 'http://example-123.com:8080/path_with_underscores_(and)_parens-and-dashes',
+                'valid' => true,
+            ],
+            [
+                'url' => 'http://example-123.com:8080/path/?query=string&some=1#fragment',
+                'valid' => true,
+            ],
+            [
+                'url' => 'http://a/b/c/g;x?y#s',
+                'valid' => true,
+            ],
+            [
+                'url' => 'http://a:123/b/c/g;x?y#s',
+                'valid' => true,
+            ],
+            [
+                'url' => 'example-123.com',
+                'valid' => false,
+            ],
+            [
+                'url' => 'nope',
+                'valid' => false,
+            ],
+        ];
+    }
+
+    /**
+     * @dataProvider provideValidate
+     */
+    public function testValidate(string $email, bool $valid)
+    {
+        $field = new UrlField('MyUrl');
+        $field->setValue($email);
+        $validator = new RequiredFields();
+        $field->validate($validator);
+        $expectedCount = $valid ? 0 : 1;
+        $this->assertEquals($expectedCount, count($validator->getErrors()));
+    }
+}