Skip to content

Commit af85b2a

Browse files
committed
Type: added mergeMode() [WIP]
TODO: Type should not support the array at all
1 parent 793adc6 commit af85b2a

File tree

3 files changed

+68
-4
lines changed

3 files changed

+68
-4
lines changed

src/Schema/Elements/Type.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Nette\Schema\Context;
1313
use Nette\Schema\DynamicParameter;
1414
use Nette\Schema\Helpers;
15+
use Nette\Schema\MergeMode;
1516
use Nette\Schema\Schema;
1617

1718

@@ -27,6 +28,7 @@ final class Type implements Schema
2728
private array $range = [null, null];
2829
private ?string $pattern = null;
2930
private bool $merge = false;
31+
private ?MergeMode $mergeMode = null;
3032

3133

3234
public function __construct(string $type)
@@ -55,6 +57,13 @@ public function mergeDefaults(bool $state = true): self
5557
}
5658

5759

60+
public function mergeMode(MergeMode $mode): self
61+
{
62+
$this->mergeMode = $mode;
63+
return $this;
64+
}
65+
66+
5867
public function dynamic(): self
5968
{
6069
$this->type = DynamicParameter::class . '|' . $this->type;
@@ -134,19 +143,19 @@ public function normalize(mixed $value, Context $context): mixed
134143

135144
public function merge(mixed $value, mixed $base): mixed
136145
{
137-
if (is_array($value) && isset($value[Helpers::PreventMerging])) {
146+
if ($this->mergeMode === MergeMode::Replace || (is_array($value) && isset($value[Helpers::PreventMerging]))) {
138147
unset($value[Helpers::PreventMerging]);
139148
return $value;
140149
}
141150

142-
if (is_array($value) && is_array($base) && $this->itemsValue) {
143-
$index = 0;
151+
if (is_array($value) && is_array($base) && ($this->itemsValue || $this->mergeMode)) {
152+
$index = $this->mergeMode === MergeMode::OverwriteKeys ? null : 0;
144153
foreach ($value as $key => $val) {
145154
if ($key === $index) {
146155
$base[] = $val;
147156
$index++;
148157
} else {
149-
$base[$key] = array_key_exists($key, $base)
158+
$base[$key] = array_key_exists($key, $base) && $this->itemsValue
150159
? $this->itemsValue->merge($val, $base[$key])
151160
: $val;
152161
}

src/Schema/MergeMode.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Nette Framework (https://nette.org)
5+
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Nette\Schema;
11+
12+
13+
enum MergeMode: int
14+
{
15+
/** Replaces all items with the last one. */
16+
case Replace = 0;
17+
18+
/** Overwrites existing keys. */
19+
case OverwriteKeys = 1;
20+
21+
/** Overwrites existing keys and appends new indexed elements. */
22+
case AppendKeys = 2;
23+
}

tests/Schema/Expect.array.phpt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ declare(strict_types=1);
44

55
use Nette\Schema\Expect;
66
use Nette\Schema\Helpers;
7+
use Nette\Schema\MergeMode;
78
use Nette\Schema\Processor;
89
use Tester\Assert;
910

@@ -343,3 +344,34 @@ test('array shape', function () {
343344
(new Processor)->process($schema, []),
344345
);
345346
});
347+
348+
349+
test('merge modes', function () {
350+
$schema = Expect::structure([
351+
'foo1' => Expect::array()->mergeMode(MergeMode::Replace),
352+
'foo2' => Expect::array()->mergeMode(MergeMode::OverwriteKeys),
353+
'foo3' => Expect::array()->mergeMode(MergeMode::AppendKeys),
354+
]);
355+
356+
$processor = new Processor;
357+
358+
Assert::equal(
359+
(object) [
360+
'foo1' => ['key' => 'new'],
361+
'foo2' => ['new', 'key' => 'new'],
362+
'foo3' => ['old', 'new', 'key' => 'new'],
363+
],
364+
$processor->processMultiple($schema, [
365+
[
366+
'foo1' => ['old', 'key' => '1'],
367+
'foo2' => ['old', 'key' => '1'],
368+
'foo3' => ['old', 'key' => '1'],
369+
],
370+
[
371+
'foo1' => ['key' => 'new'],
372+
'foo2' => ['new', 'key' => 'new'],
373+
'foo3' => ['new', 'key' => 'new'],
374+
],
375+
]),
376+
);
377+
});

0 commit comments

Comments
 (0)