Skip to content

Commit 24ec92c

Browse files
authored
Merge pull request #16629 from craftcms/bugfix/16588-expanded-export-custom-date-fields
Expanded element export & custom date fields
2 parents c2ebc39 + b05ad00 commit 24ec92c

File tree

9 files changed

+119
-6
lines changed

9 files changed

+119
-6
lines changed

CHANGELOG-WIP.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
### Extensibility
77
- Global nav items and breadcrumbs can now have `aria-label` attributes via an `ariaLabel` property.
8+
- Added `craft\base\ElementInterface::getSerializedFieldValuesForDb()`.
9+
- Added `craft\base\FieldInterface::serializeValueForDb()`.
810

911
### System
1012
- The `changedattributes` and `changedfields` tables are now cleaned up during garbage collection. ([#16531](https://github.com/craftcms/cms/pull/16531))
1113
- The `resourcepaths` table is now truncated when clearing control panel resources, via the Caches utility or the `clear-caches/cp-resources` command. ([#16514](https://github.com/craftcms/cms/issues/16514))
14+
- Date values for custom fields are now represented as ISO-8601 date strings (with time zones) within element exports. ([#16629](https://github.com/craftcms/cms/pull/16629))

src/base/Element.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
use craft\validators\SlugValidator;
7575
use craft\validators\StringValidator;
7676
use craft\web\UploadedFile;
77+
use DateTime;
7778
use Illuminate\Support\Collection;
7879
use Throwable;
7980
use Traversable;
@@ -2538,7 +2539,7 @@ public function afterValidate(): void
25382539

25392540
if ($field::hasContentColumn()) {
25402541
$columnType = $field->getContentColumnType();
2541-
$value = $field->serializeValue($this->getFieldValue($field->handle), $this);
2542+
$value = $field->serializeValueForDb($this->getFieldValue($field->handle), $this);
25422543

25432544
if (is_array($columnType)) {
25442545
foreach ($columnType as $key => $type) {
@@ -4189,6 +4190,23 @@ public function getSerializedFieldValues(?array $fieldHandles = null): array
41894190
return $serializedValues;
41904191
}
41914192

4193+
/**
4194+
* @inheritdoc
4195+
*/
4196+
public function getSerializedFieldValuesForDb(?array $fieldHandles = null): array
4197+
{
4198+
$serializedValues = [];
4199+
4200+
foreach ($this->fieldLayoutFields() as $field) {
4201+
if ($fieldHandles === null || in_array($field->handle, $fieldHandles, true)) {
4202+
$value = $this->getFieldValue($field->handle);
4203+
$serializedValues[$field->handle] = $field->serializeValueForDb($value, $this);
4204+
}
4205+
}
4206+
4207+
return $serializedValues;
4208+
}
4209+
41924210
/**
41934211
* @inheritdoc
41944212
*/

src/base/ElementInterface.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,18 @@ public function getFieldValues(?array $fieldHandles = null): array;
13791379
*/
13801380
public function getSerializedFieldValues(?array $fieldHandles = null): array;
13811381

1382+
/**
1383+
* Returns an array of the element’s serialized custom field values, indexed by their handles,
1384+
* for database storage.
1385+
*
1386+
* @param string[]|null $fieldHandles The list of field handles whose values
1387+
* need to be returned. Defaults to null, meaning all fields’ values will be
1388+
* returned. If it is an array, only the fields in the array will be returned.
1389+
* @return array
1390+
* @since 4.15.0
1391+
*/
1392+
public function getSerializedFieldValuesForDb(?array $fieldHandles = null): array;
1393+
13821394
/**
13831395
* Sets the element’s custom field values.
13841396
*

src/base/Field.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,12 +643,25 @@ public function serializeValue(mixed $value, ?ElementInterface $element = null):
643643

644644
// Only DateTime objects and ISO-8601 strings should automatically be detected as dates
645645
if ($value instanceof DateTime || DateTimeHelper::isIso8601($value)) {
646-
return Db::prepareDateForDb($value);
646+
return DateTimeHelper::toIso8601($value);
647647
}
648648

649649
return $value;
650650
}
651651

652+
/**
653+
* @inheritdoc
654+
*/
655+
public function serializeValueForDb(mixed $value, ?ElementInterface $element = null): mixed
656+
{
657+
// Dates should be stored in UTC w/o the time zone
658+
if ($value instanceof DateTime || DateTimeHelper::isIso8601($value)) {
659+
return Db::prepareDateForDb($value);
660+
}
661+
662+
return $this->serializeValue($value, $element);
663+
}
664+
652665
/**
653666
* @inheritdoc
654667
*/

src/base/FieldInterface.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,9 +393,8 @@ public function normalizeValue(mixed $value, ?ElementInterface $element = null):
393393
public function normalizeValueFromRequest(mixed $value, ?ElementInterface $element = null): mixed;
394394

395395
/**
396-
* Prepares the field’s value to be stored somewhere, like the content table.
396+
* Serializes the field’s value into a transportable format (either a scalar value or array of scalar values).
397397
*
398-
* Data types that are JSON-encodable are safe (arrays, integers, strings, booleans, etc).
399398
* Whatever this returns should be something [[normalizeValue()]] can handle.
400399
*
401400
* @param mixed $value The raw field value
@@ -404,6 +403,19 @@ public function normalizeValueFromRequest(mixed $value, ?ElementInterface $eleme
404403
*/
405404
public function serializeValue(mixed $value, ?ElementInterface $element = null): mixed;
406405

406+
/**
407+
* Serializes the field’s value into a transportable format (either a scalar value or array of scalar values),
408+
* for database storage.
409+
*
410+
* Whatever this returns should be something [[normalizeValue()]] can handle.
411+
*
412+
* @param mixed $value
413+
* @param ElementInterface|null $element
414+
* @return mixed
415+
* @since 4.15.0
416+
*/
417+
public function serializeValueForDb(mixed $value, ?ElementInterface $element = null): mixed;
418+
407419
/**
408420
* Copies the field’s value from one element to another.
409421
*

src/fields/Date.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ public function normalizeValue(mixed $value, ?ElementInterface $element = null):
394394
/**
395395
* @inheritdoc
396396
*/
397-
public function serializeValue(mixed $value, ?ElementInterface $element = null): mixed
397+
public function serializeValueForDb(mixed $value, ?ElementInterface $element = null): mixed
398398
{
399399
if (!$value) {
400400
return null;

src/fields/Matrix.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,28 @@ public function serializeValue(mixed $value, ?ElementInterface $element = null):
582582
return $serialized;
583583
}
584584

585+
/**
586+
* @inheritdoc
587+
*/
588+
public function serializeValueForDb(mixed $value, ?ElementInterface $element = null): mixed
589+
{
590+
/** @var MatrixBlockQuery|Collection $value */
591+
$serialized = [];
592+
$new = 0;
593+
594+
foreach ($value->all() as $block) {
595+
$blockId = $block->id ?? 'new' . ++$new;
596+
$serialized[$blockId] = [
597+
'type' => $block->getType()->handle,
598+
'enabled' => $block->enabled,
599+
'collapsed' => $block->collapsed,
600+
'fields' => $block->getSerializedFieldValuesForDb(),
601+
];
602+
}
603+
604+
return $serialized;
605+
}
606+
585607
/**
586608
* @inheritdoc
587609
*/

src/fields/Table.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,39 @@ public function serializeValue(mixed $value, ?ElementInterface $element = null):
532532
return $serialized;
533533
}
534534

535+
/**
536+
* @inheritdoc
537+
*/
538+
public function serializeValueForDb(mixed $value, ?ElementInterface $element = null): mixed
539+
{
540+
if (!is_array($value) || empty($this->columns)) {
541+
return null;
542+
}
543+
544+
$serialized = [];
545+
$supportsMb4 = Craft::$app->getDb()->getSupportsMb4();
546+
547+
foreach ($value as $row) {
548+
$serializedRow = [];
549+
foreach ($this->columns as $colId => $column) {
550+
if ($column['type'] === 'heading') {
551+
continue;
552+
}
553+
554+
$value = $row[$colId];
555+
556+
if (is_string($value) && !$supportsMb4) {
557+
$value = StringHelper::emojiToShortcodes(StringHelper::escapeShortcodes($value));
558+
}
559+
560+
$serializedRow[$colId] = parent::serializeValueForDb($value ?? null);
561+
}
562+
$serialized[] = $serializedRow;
563+
}
564+
565+
return $serialized;
566+
}
567+
535568
/**
536569
* @inheritdoc
537570
*/

src/services/Content.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public function saveContent(ElementInterface $element): bool
9393
(!$element->contentId || $element->isFieldDirty($field->handle)) &&
9494
$field::hasContentColumn()
9595
) {
96-
$serializedFieldValues[$field->uid] = $field->serializeValue($element->getFieldValue($field->handle), $element);
96+
$serializedFieldValues[$field->uid] = $field->serializeValueForDb($element->getFieldValue($field->handle), $element);
9797
$fields[$field->uid] = $field;
9898
}
9999
}

0 commit comments

Comments
 (0)