Sets and lists
Target group: Integrators, Developers
Table of Contents
Introduction
Any property in Schema.org can have multiple values, which are provided in JSON-LD as an array of values. These multiple values are technically treated as an unordered set by default. But there are cases where the order of the values matters, for example, steps in a recipe, or items in a list. Most parsers assume source order, but it is not explicit.
Unordered set
An unordered set of values can be achieved in the TYPO3 in the following ways.
Usage in PHP
Use the ->addProperty($value) method of the type to add multiple values to a property:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Controller;
use Brotkrueml\Schema\Type\TypeFactory;
final class MyController
{
public function __construct(
private readonly TypeFactory $typeFactory,
) {}
public function doSomething(): void
{
// ...
$person = $this->typeFactory->create('Person');
$person->setProperty('name', 'John Smith');
$person->addProperty('sameAs', 'https://mastodon.example.com/@john-smith');
$person->addProperty('sameAs', 'https://peertube.example.com/john-smith');
// ...
}
}
This results in the following output:
{
"@context": "https://schema.org/",
"@type": "Person",
"name": "John Smith",
"sameAs": [
"https://mastodon.example.com/@john-smith",
"https://peertube.example.com/john-smith"
]
}
The order of the values in the same property does not matter in this
example.
Usage in Fluid
Use the <schema:property> view helper to add multiple values to a property:
<schema:type.person name="John Smith">
<schema:property -as="sameAs" value="https://mastodon.example.com/@john-smith"/>
<schema:property -as="sameAs" value="https://peertube.example.com/john-smith"/>
</schema:type.person>
This results in the following output:
{
"@context": "https://schema.org/",
"@type": "Person",
"name": "John Smith",
"sameAs": [
"https://mastodon.example.com/@john-smith",
"https://peertube.example.com/john-smith"
]
}
The order of the values in the same property does not matter in this
example.
Ordered list
You can provide an ordered list as value for a property via the following API.
With ItemList
Usage in PHP
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Controller;
use Brotkrueml\Schema\Type\TypeFactory;
final class MyController
{
public function __construct(
private readonly TypeFactory $typeFactory,
) {}
public function doSomething(): void
{
// ...
$positiveNotes = [
'Tougher and water resistant design.',
'Cheery bright colours and solid feel.',
'Excellent amplification.',
];
$review = $this->typeFactory->create('Review');
$review->setProperty('name', 'Megaphone 11 review');
$itemList = $this->typeFactory->create('ItemList');
foreach ($positiveNotes as $index => $note) {
$item = $this->typeFactory->create('ListItem');
$item->setProperties([
'position' => $index + 1,
'name' => $note,
]);
$itemList->addProperty('itemListElement', $item);
}
$review->setProperty('positiveNotes', $itemList);
// ...
}
}
This results in the following output:
{
"@context": "https://schema.org",
"@type": "Review",
"name": "Megaphone 11 review",
"positiveNotes": {
"@type": "ItemList",
"itemListElement": [
{
"@type": "ListItem",
"name": "Tougher and water resistant design.",
"position": "1"
},
{
"@type": "ListItem",
"name": "Cheery bright colours and solid feel.",
"position": "2"
},
{
"@type": "ListItem",
"name": "Excellent amplification.",
"position": "3"
}
]
}
}
Usage in Fluid
<f:variable name="positiveNotes" value="{
0: 'Tougher and water resistant design.',
1: 'Cheery bright colours and solid feel.',
2: 'Excellent amplification.',
}"/>
<schema:type.review name="Megaphone 11 review">
<schema:type.itemList -as="positiveNotes">
<f:for each="{positiveNotes}" as="note" iteration="i">
<schema:type.listItem
-as="itemListElement"
position="{i.cycle}"
name="{note}"
/>
</f:for>
</schema:type.itemList>
</schema:type.review>
This results in the following output:
{
"@context": "https://schema.org",
"@type": "Review",
"name": "Megaphone 11 review",
"positiveNotes": {
"@type": "ItemList",
"itemListElement": [
{
"@type": "ListItem",
"name": "Tougher and water resistant design.",
"position": "1"
},
{
"@type": "ListItem",
"name": "Cheery bright colours and solid feel.",
"position": "2"
},
{
"@type": "ListItem",
"name": "Excellent amplification.",
"position": "3"
}
]
}
}
With @list
New in version 4.4.0
A property providing an ordered list of values via @list is displayed in the
admin panel via the LIST annotation:
Ordered list in the admin panel
Usage in PHP
Use the
Ordered class and pass the
items on instantiation:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Controller;
use Brotkrueml\Schema\Core\Model\OrderedList;
use Brotkrueml\Schema\Type\TypeFactory;
final class MyController
{
public function __construct(
private readonly TypeFactory $typeFactory,
) {}
public function doSomething(): void
{
// ...
$positiveNotes = [
'Tougher and water resistant design.',
'Cheery bright colours and solid feel.',
'Excellent amplification.',
];
$review = $this->typeFactory->create('Review');
$review->setProperty('name', 'Megaphone 11 review');
$review->setProperty('positiveNotes', new OrderedList(...$positiveNotes));
// ...
}
}
This results in the following output:
{
"@context": "https://schema.org",
"@type": "Review",
"name": "Megaphone 11 review",
"positiveNotes": {
"@list": [
"Tougher and water resistant design.",
"Cheery bright colours and solid feel.",
"Excellent amplification."
]
}
}
If you need to pass a type as list value, create the type and assign an @id
to it, then pass the @id as value (for example, via the
blank node identifier):
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Controller;
use Brotkrueml\Schema\Core\Model\BlankNodeIdentifier;
use Brotkrueml\Schema\Core\Model\OrderedList;
use Brotkrueml\Schema\Manager\SchemaManager;
use Brotkrueml\Schema\Type\TypeFactory;
final class MyController
{
public function __construct(
private readonly SchemaManager $schemaManager,
private readonly TypeFactory $typeFactory,
) {}
public function doSomething(): void
{
// ...
$positiveNotes = [
'Tougher and water resistant design.',
'Cheery bright colours and solid feel.',
'Excellent amplification.',
];
$review = $this->typeFactory->create('Review');
$review->setProperty('name', 'Megaphone 11 review');
$itemIds = [];
for ($i = 0; $i < \count($positiveNotes); $i++) {
$itemIds[$i] = new BlankNodeIdentifier();
$item = $this->typeFactory->create('ListItem');
$item->setId($itemIds[$i]->getId());
$item->setProperty('name', $positiveNotes[$i]);
$this->schemaManager->addType($item);
}
$review->setProperty('positiveNotes', new OrderedList(...$itemIds));
// ...
}
}
This results in the following output:
{
"@context": "https://schema.org/",
"@graph": [
{
"@type": "ListItem",
"@id": "_:b0",
"name": "Tougher and water resistant design."
},
{
"@type": "ListItem",
"@id": "_:b1",
"name": "Cheery bright colours and solid feel."
},
{
"@type": "ListItem",
"@id": "_:b2",
"name": "Excellent amplification."
},
{
"@type": "Review",
"name": "Megaphone 11 review",
"positiveNotes": {
"@list": [
{
"@id": "_:b0"
},
{
"@id": "_:b1"
},
{
"@id": "_:b2"
}
]
}
}
]
}
Usage in Fluid
Use the <schema:orderedList> view helper:
<f:variable name="positiveNotes" value="{
0: 'Tougher and water resistant design.',
1: 'Cheery bright colours and solid feel.',
2: 'Excellent amplification.',
}"/>
<schema:type.review name="Megaphone 11 review">
<schema:orderedList -as="positiveNotes" items="{positiveNotes}"/>
</schema:type.review>
This results in the following output:
{
"@context": "https://schema.org",
"@type": "Review",
"name": "Megaphone 11 review",
"positiveNotes": {
"@list": [
"Tougher and water resistant design.",
"Cheery bright colours and solid feel.",
"Excellent amplification."
]
}
}
If you need to pass a type as list value, create the type and assign an @id
to it, then pass the @id as value (for example, via the
blank node identifier):
<f:variable name="positiveNotes" value="{
0: 'Tougher and water resistant design.',
1: 'Cheery bright colours and solid feel.',
2: 'Excellent amplification.',
}"/>
<f:variable name="orderedList" value="{null}"/>
<f:for each="{positiveNotes}" as="note" reverse="1">
<f:variable name="id"><schema:blankNodeIdentifier/></f:variable>
<f:variable name="orderedList"><f:merge array="{0: '{id}'}" with="{orderedList}"/></f:variable>
<schema:type.listItem -id="{id}" name="{note}"/>
</f:for>
<schema:type.review name="Megaphone 11 review">
<schema:orderedList -as="positiveNotes" items="{orderedList}"/>
</schema:type.review>
Note
the
reverse="1"
attribute is necessary in this case, as
<f: adds the new item to the beginning of the array.
This results in the following output:
{
"@context": "https://schema.org/",
"@graph": [
{
"@type": "ListItem",
"@id": "_:b0",
"name": "Excellent amplification."
},
{
"@type": "ListItem",
"@id": "_:b1",
"name": "Cheery bright colours and solid feel."
},
{
"@type": "ListItem",
"@id": "_:b2",
"name": "Tougher and water resistant design."
},
{
"@type": "Review",
"name": "Megaphone 11 review",
"positiveNotes": {
"@list": [
{
"@id": "_:b2"
},
{
"@id": "_:b1"
},
{
"@id": "_:b0"
}
]
}
}
]
}