Skip to content

Commit 3d26622

Browse files
\Stringable always has precedence over \JsonSerializable
1 parent 64df6f7 commit 3d26622

File tree

5 files changed

+85
-1
lines changed

5 files changed

+85
-1
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
### Fixed
1212
- JSON update requests correctly handle `Stringable` object set as field value
1313

14+
### Changed
15+
- JSON update requests give precedence to `Stringable` over `JsonSerializable` for object set as field value to keep behaviour consistent across request formats
16+
1417

1518
## [6.3.5]
1619
### Added

docs/documents.md

+8
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,14 @@ Solarium issues JSON formatted update requests by default. If you change this to
238238
[SOLR-16183](https://issues.apache.org/jira/browse/SOLR-16183). Any child document you index this way will end up as an anonymous nested child.
239239
- Atomic updates of child documents aren't fully supported because of [SOLR-12677](https://issues.apache.org/jira/browse/SOLR-12677).
240240

241+
If you set a field value to an object that is both `Stringable` and `JsonSerializable`, it will always be cast to a `string` when building the
242+
request to keep the behaviour consistent between request formats. You can override this by calling `jsonSerialize()` explicitly. Even if an object
243+
isn't `Stringable`, depending on `jsonSerialize()` being called implicitly is discouraged as it will only work for JSON formatted update requests.
244+
245+
```php
246+
$doc->reaction = $reaction->jsonSerialize();
247+
```
248+
241249
### Atomic updates
242250

243251
You can create atomic updates by using the `setFieldModifier` method. Set a modifier on the field you want to update. The supported modifiers are:

src/QueryType/Update/Query/Document.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ public function jsonSerialize()
498498
foreach ($fields as $key => &$value) {
499499
if ($value instanceof \DateTimeInterface) {
500500
$value = $this->getHelper()->formatDate($value);
501-
} elseif ($value instanceof \Stringable && !($value instanceof \JsonSerializable)) {
501+
} elseif ($value instanceof \Stringable) {
502502
$value = (string) $value;
503503
} elseif (\is_array($value) && is_numeric(array_key_first($value))) {
504504
// ensure consecutive indices so it doesn't serialize to an object

tests/QueryType/Update/RequestBuilder/JsonTest.php

+44
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,10 @@ public function __toString(): string
773773
);
774774
}
775775

776+
/**
777+
* Test that \Stringable takes precedence over \JsonSerializable for
778+
* consistency across request format.
779+
*/
776780
public function testBuildAddJsonWithJsonSerializableAndStringableObject()
777781
{
778782
$value = new class() implements \JsonSerializable, \Stringable {
@@ -795,6 +799,46 @@ public function __toString(): string
795799

796800
$this->builder->buildAddJson($command, $json);
797801

802+
$this->assertCount(1, $json);
803+
$this->assertJsonStringEqualsJsonString(
804+
'{
805+
"add": {
806+
"doc": {
807+
"id": 1,
808+
"my_field": "My string value"
809+
}
810+
}
811+
}',
812+
'{'.$json[0].'}'
813+
);
814+
}
815+
816+
/**
817+
* Test that the \Stringable precedence on an also \JsonSerializable object
818+
* can be overridden by explicitly calling jsonSerialize().
819+
*/
820+
public function testBuildAddJsonWithJsonSerializableAndStringableObjectWithExplicitJsonSerialize()
821+
{
822+
$value = new class() implements \JsonSerializable, \Stringable {
823+
public function jsonSerialize(): mixed
824+
{
825+
return 'My JSON value';
826+
}
827+
828+
public function __toString(): string
829+
{
830+
return 'My string value';
831+
}
832+
};
833+
834+
$command = new AddCommand();
835+
$command->addDocument(
836+
new Document(['id' => 1, 'my_field' => $value->jsonSerialize()])
837+
);
838+
$json = [];
839+
840+
$this->builder->buildAddJson($command, $json);
841+
798842
$this->assertCount(1, $json);
799843
$this->assertJsonStringEqualsJsonString(
800844
'{

tests/QueryType/Update/RequestBuilder/XmlTest.php

+29
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,35 @@ public function __toString(): string
542542
);
543543
}
544544

545+
/**
546+
* Test that \Stringable takes precedence over \JsonSerializable for
547+
* consistency across request format.
548+
*/
549+
public function testBuildAddXmlWithJsonSerializableAndStringableObject()
550+
{
551+
$value = new class() implements \JsonSerializable, \Stringable {
552+
public function jsonSerialize(): mixed
553+
{
554+
return 'My JSON value';
555+
}
556+
557+
public function __toString(): string
558+
{
559+
return 'My string value';
560+
}
561+
};
562+
563+
$command = new AddCommand();
564+
$command->addDocument(
565+
new Document(['id' => 1, 'my_field' => $value])
566+
);
567+
568+
$this->assertSame(
569+
'<add><doc><field name="id">1</field><field name="my_field">My string value</field></doc></add>',
570+
$this->builder->buildAddXml($command)
571+
);
572+
}
573+
545574
public function testBuildAddXmlWithFieldModifierAndNullValue()
546575
{
547576
$doc = new Document();

0 commit comments

Comments
 (0)