Skip to content

Commit

Permalink
Merge pull request #70 from systopia/null-instead-of-empty-string
Browse files Browse the repository at this point in the history
Use `NULL` instead of empty string if property is allowed to be `NULL`
  • Loading branch information
dontub authored Aug 16, 2024
2 parents 69a3797 + 5a13bb9 commit b8f4067
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/Form/Control/Callbacks/EmailValidateCallback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* Copyright (C) 2024 SYSTOPIA GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

declare(strict_types=1);

namespace Drupal\json_forms\Form\Control\Callbacks;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\Email;

final class EmailValidateCallback {

/**
* @param array<int|string, mixed> $element
* @param \Drupal\Core\Form\FormStateInterface $formState
* @param array<int|string, mixed> $completeForm
*/
public static function validate(array &$element, FormStateInterface $formState, array $completeForm): void {
// @phpstan-ignore argument.type
$value = $formState->getValue($element['#parents']);

// Prevent Email::validateEmail() from setting an empty string when the
// current value is NULL and allowed to be NULL.
if (NULL !== $value || TRUE !== $element['#_nullable']) {
Email::validateEmail($element, $formState, $completeForm);
}
}

}
59 changes: 59 additions & 0 deletions src/Form/Control/Callbacks/StringValueCallback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/*
* Copyright (C) 2022 SYSTOPIA GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

declare(strict_types=1);

namespace Drupal\json_forms\Form\Control\Callbacks;

use Drupal\Core\Form\FormStateInterface;

final class StringValueCallback {

/**
* @param array<int|string, mixed> $element
* @param mixed $input
* @param \Drupal\Core\Form\FormStateInterface $formState
*
* @return mixed
*/
public static function convert(array $element, $input, FormStateInterface $formState) {
$value = $input;
if (FALSE === $value) {
$value = $element['#default_value'] ?? '';
}

if ('' === $value) {
if (TRUE === $element['#_nullable']) {
$value = NULL;
}
}

if (NULL === $value) {
// Prevent empty string as value. Drupal sets an empty string in this
// case if no value is set in the form state.
$formState->setValueForElement($element, NULL);
}
elseif ('textfield' === $element['#type'] && is_string($value)) {
$value = str_replace(["\r", "\n"], '', $value);
}

return $value;
}

}
45 changes: 45 additions & 0 deletions src/Form/Control/Callbacks/UrlValidateCallback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* Copyright (C) 2024 SYSTOPIA GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

declare(strict_types=1);

namespace Drupal\json_forms\Form\Control\Callbacks;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\Url;

final class UrlValidateCallback {

/**
* @param array<int|string, mixed> $element
* @param \Drupal\Core\Form\FormStateInterface $formState
* @param array<int|string, mixed> $completeForm
*/
public static function validate(array &$element, FormStateInterface $formState, array $completeForm): void {
// @phpstan-ignore argument.type
$value = $formState->getValue($element['#parents']);

// Prevent Url::validateUrl() from setting an empty string when the current
// value is NULL and allowed to be NULL.
if (NULL !== $value || TRUE !== $element['#_nullable']) {
Url::validateUrl($element, $formState, $completeForm);
}
}

}
2 changes: 2 additions & 0 deletions src/Form/Control/EmailArrayFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
namespace Drupal\json_forms\Form\Control;

use Drupal\Core\Form\FormStateInterface;
use Drupal\json_forms\Form\Control\Callbacks\EmailValidateCallback;
use Drupal\json_forms\Form\FormArrayFactoryInterface;
use Drupal\json_forms\JsonForms\Definition\Control\ControlDefinition;
use Drupal\json_forms\JsonForms\Definition\DefinitionInterface;
Expand All @@ -42,6 +43,7 @@ public function createFormArray(
): array {
return [
'#type' => 'email',
'#element_validate' => [EmailValidateCallback::class . '::validate'],
] + parent::createFormArray($definition, $formState, $formArrayFactory);
}

Expand Down
2 changes: 2 additions & 0 deletions src/Form/Control/StringArrayFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Assert\Assertion;
use Drupal\Core\Form\FormStateInterface;
use Drupal\json_forms\Form\AbstractConcreteFormArrayFactory;
use Drupal\json_forms\Form\Control\Callbacks\StringValueCallback;
use Drupal\json_forms\Form\Control\Util\BasicFormPropertiesFactory;
use Drupal\json_forms\Form\FormArrayFactoryInterface;
use Drupal\json_forms\JsonForms\Definition\Control\ControlDefinition;
Expand All @@ -47,6 +48,7 @@ public function createFormArray(

$form = [
'#type' => TRUE === $definition->getOptionsValue('multi', FALSE) ? 'textarea' : 'textfield',
'#value_callback' => StringValueCallback::class . '::convert',
] + BasicFormPropertiesFactory::createFieldProperties($definition, $formState);

if (NULL !== $definition->getMaxLength()) {
Expand Down
2 changes: 2 additions & 0 deletions src/Form/Control/UrlArrayFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
namespace Drupal\json_forms\Form\Control;

use Drupal\Core\Form\FormStateInterface;
use Drupal\json_forms\Form\Control\Callbacks\UrlValidateCallback;
use Drupal\json_forms\Form\FormArrayFactoryInterface;
use Drupal\json_forms\JsonForms\Definition\Control\ControlDefinition;
use Drupal\json_forms\JsonForms\Definition\DefinitionInterface;
Expand All @@ -42,6 +43,7 @@ public function createFormArray(
): array {
return [
'#type' => 'url',
'#element_validate' => [UrlValidateCallback::class . '::validate'],
] + parent::createFormArray($definition, $formState, $formArrayFactory);
}

Expand Down
1 change: 1 addition & 0 deletions src/Form/Control/Util/BasicFormPropertiesFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public static function createFieldProperties(ControlDefinition $definition, Form
'#disabled' => $definition->isReadOnly(),
'#required' => $definition->isRequired(),
'#limit_validation_errors' => [],
'#_nullable' => $definition->isNullable(),
];

if ((!$formState->isCached() || $definition->isReadOnly())
Expand Down
4 changes: 4 additions & 0 deletions src/JsonForms/Definition/Control/ControlDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ public function getType(): string {
return $this->propertySchema->type;
}

public function isNullable(): bool {
return in_array('null', (array) $this->propertySchema->type, TRUE);
}

public function isReadOnly(): bool {
return $this->controlSchema->options->readonly ?? $this->propertySchema->readOnly
?? (property_exists($this->propertySchema, '$calculate') || $this->parentUiReadonly);
Expand Down

0 comments on commit b8f4067

Please sign in to comment.