Skip to content

Commit d708e4c

Browse files
committed
Merge remote-tracking branch 'origin/2026.1' into 2026.x
2 parents 1fea000 + a587ac7 commit d708e4c

10 files changed

Lines changed: 283 additions & 18 deletions

File tree

src/Grid/Column/Collector/DataObject/AdvancedColumnCollector.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ private function getDefaultFields(array $groupedDefinitions): array
166166
$simpleFields = $this->getSystemFields();
167167
foreach ($groupedDefinitions as $definition) {
168168
if ($definition instanceof Classificationstore) {
169+
$simpleFields[] = $this->buildClassificationStoreField($definition);
170+
169171
continue;
170172
}
171173

@@ -193,6 +195,18 @@ private function getDefaultFields(array $groupedDefinitions): array
193195
return $simpleFields;
194196
}
195197

198+
private function buildClassificationStoreField(Classificationstore $definition): SimpleField
199+
{
200+
return new SimpleField(
201+
name: $definition->getTitle(),
202+
key: $definition->getName(),
203+
config: [
204+
'classificationStore' => true,
205+
'storeId' => $definition->getStoreId(),
206+
],
207+
);
208+
}
209+
196210
private function getSystemFields(): array
197211
{
198212
$systemColumns = $this->systemColumnService->getSystemColumnsForDataObjects();

src/Grid/Column/Resolver/DataObject/AdvancedColumnResolver.php

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@
3939
use Pimcore\Model\DataObject\Concrete;
4040
use Pimcore\Model\Element\ElementInterface;
4141
use Pimcore\Model\UserInterface;
42+
use function array_filter;
4243
use function array_key_exists;
44+
use function array_values;
4345
use function is_array;
4446
use function is_object;
4547
use function is_scalar;
@@ -220,14 +222,22 @@ private function resolveField(
220222
$this->user
221223
);
222224

225+
$config = $column->getConfig();
226+
if ($resolverType === 'dataobject.classificationstore') {
227+
$config = [
228+
'groupId' => $fieldConfig->getGroupId(),
229+
'keyId' => $fieldConfig->getKeyId(),
230+
];
231+
}
232+
223233
$resolver = $this->gridService->getColumnResolvers()[$resolverType];
224234

225235
$subColumn = new Column(
226236
key: $fieldConfig->getField(),
227237
locale: $isLocalizable ? $column->getLocale() : null,
228238
type: $resolverType,
229239
group: $column->getGroup(),
230-
config: $column->getConfig(),
240+
config: $config,
231241
);
232242

233243
$data = null;
@@ -265,36 +275,42 @@ private function resolveRelationField(
265275
Concrete $element,
266276
bool $export = false
267277
): void {
278+
$relatedElements = $this->getRelatedElements($relationFieldConfig->getRelation(), $column, $element);
279+
foreach ($relatedElements as $relationElement) {
280+
$this->resolveField($relationFieldConfig, $column, $relationElement, $export);
281+
}
282+
}
283+
284+
/**
285+
* @return Concrete[]
286+
*
287+
* @throws Exception
288+
*/
289+
private function getRelatedElements(string $relationKey, Column $column, Concrete $element): array
290+
{
268291
$isRelationLocalizable = $this->resolverTypeGuesser->isLocalizable(
269-
$relationFieldConfig->getRelation(),
292+
$relationKey,
270293
$element->getClassId(),
271294
$this->user
272295
);
273296

274297
$relation = $this->getLocalizedValueFromKey(
275-
$relationFieldConfig->getRelation(),
298+
$relationKey,
276299
$isRelationLocalizable ? $column->getLocale() : null,
277300
$element
278301
);
279302

280303
if (is_array($relation)) {
281-
foreach ($relation as $relationElement) {
282-
if (!$relationElement instanceof Concrete) {
283-
continue;
284-
}
285-
286-
$this->resolveField($relationFieldConfig, $column, $relationElement, $export);
287-
288-
}
289-
290-
return;
304+
return array_values(
305+
array_filter($relation, static fn ($relationElement) => $relationElement instanceof Concrete)
306+
);
291307
}
292308

293309
if (!$relation instanceof Concrete) {
294-
return;
310+
return [];
295311
}
296312

297-
$this->resolveField($relationFieldConfig, $column, $relation, $export);
313+
return [$relation];
298314
}
299315

300316
/**

src/Grid/Schema/AdvancedColumnConfig/AdvancedColumnConfig.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function __construct(
7676
}
7777

7878
/**
79-
* @return RelationFieldConfig[]|SimpleFieldConfig[]|StaticTextConfig[]
79+
* @return array<RelationFieldConfig|SimpleFieldConfig|StaticTextConfig>
8080
*/
8181
public function getColumns(): array
8282
{

src/Grid/Schema/AdvancedColumnConfig/RelationFieldConfig.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ public function __construct(
3131
private string $relation,
3232
#[Property(description: 'Field getter', type: 'string', example: 'name')]
3333
private string $field,
34+
#[Property(description: 'Classification store group id', type: 'integer', example: 1, nullable: true)]
35+
private ?int $groupId = null,
36+
#[Property(description: 'Classification store key id', type: 'integer', example: 1, nullable: true)]
37+
private ?int $keyId = null,
3438
) {
3539
}
3640

@@ -43,4 +47,14 @@ public function getField(): string
4347
{
4448
return $this->field;
4549
}
50+
51+
public function getGroupId(): ?int
52+
{
53+
return $this->groupId;
54+
}
55+
56+
public function getKeyId(): ?int
57+
{
58+
return $this->keyId;
59+
}
4660
}

src/Grid/Schema/AdvancedColumnConfig/SimpleFieldConfig.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,25 @@
2929
public function __construct(
3030
#[Property(description: 'Field getter', type: 'string', example: 'name')]
3131
private string $field,
32+
#[Property(description: 'Classification store group id', type: 'integer', example: 1, nullable: true)]
33+
private ?int $groupId = null,
34+
#[Property(description: 'Classification store key id', type: 'integer', example: 1, nullable: true)]
35+
private ?int $keyId = null,
3236
) {
3337
}
3438

3539
public function getField(): string
3640
{
3741
return $this->field;
3842
}
43+
44+
public function getGroupId(): ?int
45+
{
46+
return $this->groupId;
47+
}
48+
49+
public function getKeyId(): ?int
50+
{
51+
return $this->keyId;
52+
}
3953
}

src/Grid/Schema/Column.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ public function getAdvancedColumnConfig(): AdvancedColumnConfig
101101
$configs[] = new RelationFieldConfig(
102102
relation: $advancedColumn['config']['relation'],
103103
field: $advancedColumn['config']['field'],
104+
groupId: $advancedColumn['config']['groupId'] ?? null,
105+
keyId: $advancedColumn['config']['keyId'] ?? null,
104106
);
105107

106108
continue;
@@ -109,6 +111,8 @@ public function getAdvancedColumnConfig(): AdvancedColumnConfig
109111
if ($advancedColumn['key'] === 'simpleField') {
110112
$configs[] = new SimpleFieldConfig(
111113
field: $advancedColumn['config']['field'],
114+
groupId: $advancedColumn['config']['groupId'] ?? null,
115+
keyId: $advancedColumn['config']['keyId'] ?? null,
112116
);
113117

114118
continue;

src/Grid/Util/SimpleField.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
*/
1919
readonly class SimpleField
2020
{
21-
public function __construct(private string $name, private string $key)
22-
{
21+
public function __construct(
22+
private string $name,
23+
private string $key,
24+
private array $config = [],
25+
) {
2326
}
2427

2528
public function getName(): string
@@ -31,4 +34,12 @@ public function getKey(): string
3134
{
3235
return $this->key;
3336
}
37+
38+
/**
39+
* @return array<string, mixed>
40+
*/
41+
public function getConfig(): array
42+
{
43+
return $this->config;
44+
}
3445
}

tests/Unit/Grid/Column/Collector/DataObject/AdvancedColumnCollectorTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Pimcore\Bundle\StudioBackendBundle\Grid\Service\TransformerLoaderInterface;
2424
use Pimcore\Bundle\StudioBackendBundle\Grid\Util\SimpleField;
2525
use Pimcore\Bundle\StudioBackendBundle\ObjectBrick\Service\ObjectBrickServiceInterface;
26+
use Pimcore\Model\DataObject\ClassDefinition\Data\Classificationstore;
2627
use Pimcore\Model\DataObject\ClassDefinition\Data\Input;
2728
use Pimcore\Model\DataObject\ClassDefinition\Data\ManyToManyObjectRelation;
2829
use Pimcore\Model\DataObject\ClassDefinition\Layout;
@@ -62,6 +63,41 @@ public function testGetColumnConfigurationsExcludesInvisibleRelationFields(): vo
6263
$this->assertSame([], $config->getConfig()['relationField']);
6364
}
6465

66+
public function testGetColumnConfigurationsExposesClassificationStoreFieldAsMarkedSimpleField(): void
67+
{
68+
$simpleField = $this->createInput('name', 'Name', false);
69+
70+
$classificationStore = new Classificationstore();
71+
$classificationStore->setName('csstore');
72+
$classificationStore->setTitle('Classification Store');
73+
$classificationStore->setStoreId(2);
74+
75+
$collector = $this->createCollector([$simpleField, $classificationStore]);
76+
77+
$config = $this->getAdvancedConfig($collector);
78+
79+
// Classification store is offered as part of the simple fields, flagged with a marker
80+
$this->assertArrayNotHasKey('classificationStoreField', $config->getConfig());
81+
82+
$simpleFields = $config->getConfig()['simpleField'];
83+
$this->assertContains('csstore', $this->extractFieldKeys($simpleFields));
84+
85+
$classificationStoreField = null;
86+
foreach ($simpleFields as $field) {
87+
if ($field->getKey() === 'csstore') {
88+
$classificationStoreField = $field;
89+
90+
break;
91+
}
92+
}
93+
94+
$this->assertInstanceOf(SimpleField::class, $classificationStoreField);
95+
$this->assertSame(
96+
['classificationStore' => true, 'storeId' => 2],
97+
$classificationStoreField->getConfig()
98+
);
99+
}
100+
65101
private function createInput(string $name, string $title, bool $invisible): Input
66102
{
67103
$field = new Input();
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/**
5+
* This source file is available under the terms of the
6+
* Pimcore Open Core License (POCL)
7+
* Full copyright and license information is available in
8+
* LICENSE.md which is distributed with this source code.
9+
*
10+
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
11+
* @license Pimcore Open Core License (POCL)
12+
*/
13+
14+
namespace Pimcore\Bundle\StudioBackendBundle\Tests\Unit\Grid\Column\Resolver\DataObject;
15+
16+
use Codeception\Test\Unit;
17+
use Pimcore\Bundle\StaticResolverBundle\Lib\ToolResolverInterface;
18+
use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\LocalizedFieldResolverInterface;
19+
use Pimcore\Bundle\StudioBackendBundle\Grid\Column\CoreElementColumnResolverInterface;
20+
use Pimcore\Bundle\StudioBackendBundle\Grid\Column\Resolver\DataObject\AdvancedColumnResolver;
21+
use Pimcore\Bundle\StudioBackendBundle\Grid\Column\Resolver\ResolverTypeGuesserInterface;
22+
use Pimcore\Bundle\StudioBackendBundle\Grid\Schema\Column;
23+
use Pimcore\Bundle\StudioBackendBundle\Grid\Schema\ColumnData;
24+
use Pimcore\Bundle\StudioBackendBundle\Grid\Service\GridServiceInterface;
25+
use Pimcore\Bundle\StudioBackendBundle\Grid\Service\TransformerLoaderInterface;
26+
use Pimcore\Bundle\StudioBackendBundle\Grid\Util\AdvancedValue;
27+
use Pimcore\Model\DataObject\Concrete;
28+
29+
/**
30+
* @internal
31+
*/
32+
final class AdvancedColumnResolverTest extends Unit
33+
{
34+
public function testResolveForCoreElementResolvesClassificationStoreField(): void
35+
{
36+
$classificationStoreResolver = $this->makeEmpty(CoreElementColumnResolverInterface::class, [
37+
'resolveForCoreElement' => static function (Column $column): ColumnData {
38+
// The advanced resolver must forward the picked group/key as the sub column config
39+
self::assertSame('dataobject.classificationstore', $column->getType());
40+
self::assertSame('csstore', $column->getKey());
41+
self::assertSame(['groupId' => 5, 'keyId' => 7], $column->getConfig());
42+
43+
return new ColumnData(
44+
key: 'csstore.size',
45+
locale: null,
46+
value: 'XL',
47+
fieldType: 'input',
48+
);
49+
},
50+
]);
51+
52+
$resolver = new AdvancedColumnResolver(
53+
$this->makeEmpty(TransformerLoaderInterface::class, ['loadTransformers' => []]),
54+
$this->makeEmpty(GridServiceInterface::class, [
55+
'getColumnResolvers' => ['dataobject.classificationstore' => $classificationStoreResolver],
56+
]),
57+
$this->makeEmpty(ResolverTypeGuesserInterface::class, [
58+
'guessType' => 'dataobject.classificationstore',
59+
'isLocalizable' => false,
60+
]),
61+
$this->makeEmpty(ToolResolverInterface::class),
62+
$this->makeEmpty(LocalizedFieldResolverInterface::class),
63+
);
64+
65+
$column = new Column(
66+
key: 'advanced',
67+
locale: null,
68+
type: 'dataobject.advanced',
69+
group: ['advanced'],
70+
config: [
71+
'advancedColumns' => [
72+
[
73+
'key' => 'simpleField',
74+
'config' => ['field' => 'csstore', 'groupId' => 5, 'keyId' => 7],
75+
],
76+
],
77+
'transformers' => [],
78+
],
79+
);
80+
81+
$element = $this->makeEmpty(Concrete::class, ['getClassId' => 'CAR']);
82+
83+
$result = $resolver->resolveForCoreElement($column, $element);
84+
85+
$values = $result->getValue();
86+
$this->assertIsArray($values);
87+
$this->assertCount(1, $values);
88+
$this->assertInstanceOf(AdvancedValue::class, $values[0]);
89+
$this->assertSame('XL', $values[0]->getValue());
90+
$this->assertSame('input', $values[0]->getType());
91+
$this->assertSame('csstore', $values[0]->getFieldName());
92+
$this->assertNull($values[0]->getRelation());
93+
}
94+
}

0 commit comments

Comments
 (0)