Skip to content

Commit 87cc6df

Browse files
committed
fix: Ensure object properties can have a different title
1 parent 290bbe6 commit 87cc6df

5 files changed

Lines changed: 65 additions & 9 deletions

File tree

‎src/Contracts/JsonSchema.php‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,9 @@ public function version(SchemaVersion $schemaVersion): static;
9898
* Get the JSON Schema version for this schema.
9999
*/
100100
public function getVersion(): SchemaVersion;
101+
102+
/**
103+
* Get the initial title.
104+
*/
105+
public function getInitialTitle(): ?string;
101106
}

‎src/Types/AbstractSchema.php‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Cortex\JsonSchema\Types\Concerns\HasDefinitions;
2020
use Cortex\JsonSchema\Types\Concerns\HasDescription;
2121
use Cortex\JsonSchema\Types\Concerns\HasConditionals;
22+
use Cortex\JsonSchema\Types\Concerns\HasInitialTitle;
2223
use Cortex\JsonSchema\Types\Concerns\ValidatesVersionFeatures;
2324

2425
abstract class AbstractSchema implements JsonSchema
@@ -33,8 +34,9 @@ abstract class AbstractSchema implements JsonSchema
3334
use HasReadWrite;
3435
use HasValidation;
3536
use HasDescription;
36-
use HasConditionals;
3737
use HasDefinitions;
38+
use HasConditionals;
39+
use HasInitialTitle;
3840
use ValidatesVersionFeatures;
3941

4042
protected SchemaVersion $schemaVersion = SchemaVersion::Draft_2020_12;
@@ -47,6 +49,7 @@ public function __construct(
4749
?string $title = null,
4850
?SchemaVersion $schemaVersion = null,
4951
) {
52+
$this->initialTitle = $title;
5053
$this->title = $title;
5154
$this->schemaVersion = $schemaVersion ?? SchemaVersion::default();
5255
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cortex\JsonSchema\Types\Concerns;
6+
7+
/** @mixin \Cortex\JsonSchema\Contracts\JsonSchema */
8+
trait HasInitialTitle
9+
{
10+
protected ?string $initialTitle = null;
11+
12+
/**
13+
* Get the initial title.
14+
*
15+
* @internal
16+
*/
17+
public function getInitialTitle(): ?string
18+
{
19+
return $this->initialTitle;
20+
}
21+
}

‎src/Types/Concerns/HasProperties.php‎

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ trait HasProperties
5555
public function properties(JsonSchema ...$properties): static
5656
{
5757
foreach ($properties as $property) {
58-
$title = $property->getTitle();
58+
$title = $this->resolvePropertyTitle($property);
5959

6060
if ($title === null) {
6161
throw new SchemaException('Property must have a title');
@@ -253,12 +253,8 @@ public function hasRequiredProperties(): bool
253253
*/
254254
public function requireAll(): static
255255
{
256-
foreach ($this->properties as $property) {
257-
$title = $property->getTitle();
258-
259-
if ($title !== null) {
260-
$this->requiredProperties[] = $title;
261-
}
256+
foreach ($this->properties as $name => $property) {
257+
$this->requiredProperties[] = $name;
262258
}
263259

264260
return $this;
@@ -277,7 +273,15 @@ protected function addPropertiesToSchema(array $schema): array
277273
$schema['properties'] = [];
278274

279275
foreach ($this->properties as $name => $prop) {
280-
$schema['properties'][$name] = $prop->toArray(includeSchemaRef: false, includeTitle: false);
276+
$propertySchema = $prop->toArray(includeSchemaRef: false, includeTitle: true);
277+
278+
// If the property schema has a title and it matches the name,
279+
// then we don't need to include it in the schema
280+
if (array_key_exists('title', $propertySchema) && $propertySchema['title'] === $name) {
281+
unset($propertySchema['title']);
282+
}
283+
284+
$schema['properties'][$name] = $propertySchema;
281285
}
282286
}
283287

@@ -331,6 +335,14 @@ protected function addPropertiesToSchema(array $schema): array
331335
return $schema;
332336
}
333337

338+
/**
339+
* Resolve the property title from a schema instance.
340+
*/
341+
protected function resolvePropertyTitle(JsonSchema $property): ?string
342+
{
343+
return $property->getInitialTitle() ?? $property->getTitle();
344+
}
345+
334346
/**
335347
* Get unevaluated properties features used by this schema.
336348
*

‎tests/Unit/Types/ObjectSchemaTest.php‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,21 @@
113113
}
114114
})->throws(SchemaException::class);
115115

116+
it('can set set the property title separately from the property key', function (): void {
117+
$objectSchema = Schema::object()
118+
->properties(
119+
Schema::string('foo')->title('Foo'),
120+
Schema::string('bar'),
121+
);
122+
123+
$schemaArray = $objectSchema->toArray();
124+
125+
expect($schemaArray)->toHaveKey('properties.foo.type', 'string');
126+
expect($schemaArray)->toHaveKey('properties.foo.title', 'Foo');
127+
expect($schemaArray)->toHaveKey('properties.bar.type', 'string');
128+
expect($schemaArray['properties']['bar'])->not->toHaveKey('title');
129+
});
130+
116131
it('can create an object schema with additional properties control', function (): void {
117132
$objectSchema = Schema::object('config')
118133
->description('Configuration object')

0 commit comments

Comments
 (0)