Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 6 additions & 17 deletions src/CoreShop/Bundle/IndexBundle/Controller/IndexController.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use CoreShop\Bundle\StudioFormBundle\Form\Schema\RuleFormSchemaCollector;
use CoreShop\Component\Index\Interpreter\LocalizedInterpreterInterface;
use CoreShop\Component\Index\Interpreter\RelationInterpreterInterface;
use CoreShop\Component\Index\Model\IndexableInterface;
use CoreShop\Component\Index\Service\IndexableClassesProviderInterface;
use CoreShop\Component\Registry\ServiceRegistryInterface;
use Pimcore\Model\DataObject;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
Expand All @@ -49,6 +49,7 @@ public function getTypesAction(): Response

public function getConfigAction(
RuleFormSchemaCollector $schemaCollector,
IndexableClassesProviderInterface $indexableClassesProvider,
#[Autowire(service: 'coreshop.form_registry.index.getter')]
FormTypeRegistryInterface $getterFormTypeRegistry,
#[Autowire(service: 'coreshop.form_registry.index.interpreter')]
Expand Down Expand Up @@ -118,22 +119,10 @@ public function getConfigAction(
}
}

$classes = new DataObject\ClassDefinition\Listing();
$classes = $classes->load();
$availableClasses = [];

foreach ($classes as $class) {
if ($class instanceof DataObject\ClassDefinition) {
$pimcoreClass = 'Pimcore\Model\DataObject\\' . ucfirst($class->getName());
$implements = class_implements($pimcoreClass) ?: [];

if (in_array(IndexableInterface::class, $implements, true)) {
$availableClasses[] = [
'name' => $class->getName(),
];
}
}
}
$availableClasses = array_map(
static fn (string $name) => ['name' => $name],
$indexableClassesProvider->getIndexableClassNames(),
);

$workersResult = [];

Expand Down
3 changes: 1 addition & 2 deletions src/CoreShop/Bundle/IndexBundle/Form/Type/IndexType.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

use CoreShop\Bundle\ResourceBundle\Form\Registry\FormTypeRegistryInterface;
use CoreShop\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use CoreShop\Bundle\ResourceBundle\Form\Type\PimcoreClassChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
Expand All @@ -42,7 +41,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
$builder
->add('name', TextType::class)
->add('worker', IndexWorkerChoiceType::class)
->add('class', PimcoreClassChoiceType::class)
->add('class', IndexablePimcoreClassChoiceType::class)
->add('columns', IndexColumnCollectionType::class)
->add('indexLastVersion', CheckboxType::class)
;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

/*
* CoreShop
*
* This source file is available under the terms of the
* CoreShop Commercial License (CCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) CoreShop GmbH (https://www.coreshop.com)
* @license CoreShop Commercial License (CCL)
*
*/

namespace CoreShop\Bundle\IndexBundle\Form\Type;

use CoreShop\Component\Index\Service\IndexableClassesProviderInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class IndexablePimcoreClassChoiceType extends AbstractType
{
public function __construct(
private readonly IndexableClassesProviderInterface $indexableClassesProvider,
) {
}

public function configureOptions(OptionsResolver $resolver): void
{
$choices = [];

foreach ($this->indexableClassesProvider->getIndexableClassNames() as $name) {
$choices[$name] = $name;
}

$resolver->setDefaults([
'choices' => $choices,
]);
}

public function getParent(): string
{
return ChoiceType::class;
}

public function getBlockPrefix(): string
{
return 'coreshop_index_indexable_pimcore_class_choice';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class MysqlWorkerTableIndexType extends AbstractType
{
Expand All @@ -37,20 +37,14 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'required' => false,
])
->add('columns', CollectionType::class, [
'entry_type' => TextType::class,
'allow_delete' => true,
'allow_add' => true,
'required' => false,
])
;
}

public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefault('data_class', TableIndex::class);

parent::configureOptions($resolver);
}

public function getBlockPrefix(): string
{
return 'coreshop_index_worker_mysql';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,26 @@ export const ColumnsPanel: React.FC<ColumnsPanelProps> = ({
return
}

// Create new column with defaults
const newColumn: IndexColumn = {
// `field.dataType` is the Pimcore ClassDefinition fieldtype (e.g. 'input', 'numeric'),
// not a valid index column type. Open the edit modal with the draft column and let the
// user pick a valid index column type (STRING, INTEGER, …). The column is only appended
// once the user clicks Apply (see handleSaveField with editingIndex === null).
const draftColumn: IndexColumn = {
name: field.name || field.objectKey || '',
objectKey: field.objectKey || '',
objectType: field.objectType,
dataType: field.dataType,
columnType: field.dataType || 'TEXT',
columnType: undefined,
getter: field.getter,
getterConfig: field.configuration,
interpreter: field.interpreter,
interpreterConfig: undefined,
configuration: field.configuration
}

onChange({
...index,
columns: [...columns, newColumn]
})
setEditingColumn(draftColumn)
setEditingIndex(null)
setDialogVisible(true)
}

const handleDrop = (info: DragAndDropInfo) => {
Expand All @@ -102,14 +104,21 @@ export const ColumnsPanel: React.FC<ColumnsPanelProps> = ({
}

const handleSaveField = (updatedColumn: IndexColumn) => {
if (editingIndex !== null) {
const newColumns = [...columns]
newColumns[editingIndex] = updatedColumn
if (editingIndex === null) {
// New field — append
onChange({
...index,
columns: newColumns
columns: [...columns, updatedColumn]
})
return
}

const newColumns = [...columns]
newColumns[editingIndex] = updatedColumn
onChange({
...index,
columns: newColumns
})
}

const handleCloseModal = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const FieldEditModal: React.FC<FieldEditModalProps> = ({
name: field.name || '',
getter: field.getter || undefined,
interpreter: field.interpreter || undefined,
columnType: field.columnType || 'INTEGER'
columnType: field.columnType || undefined
})
setSelectedGetter(field.getter)
setSelectedInterpreter(field.interpreter)
Expand Down
4 changes: 4 additions & 0 deletions src/CoreShop/Bundle/IndexBundle/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ services:
- '@coreshop.repository.index'
- '@coreshop.registry.index.worker'

# Indexable Classes Provider
CoreShop\Component\Index\Service\IndexableClassesProviderInterface: '@CoreShop\Bundle\IndexBundle\Service\IndexableClassesProvider'
CoreShop\Bundle\IndexBundle\Service\IndexableClassesProvider: ~

CoreShop\Component\Index\Extension\DecimalIndexColumnTypeConfigExtension:
tags:
- { name: coreshop.index.extension }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ services:
- { name: form.type }
- { name: coreshop.studio_form }

CoreShop\Bundle\IndexBundle\Form\Type\IndexablePimcoreClassChoiceType:
arguments:
- '@CoreShop\Component\Index\Service\IndexableClassesProviderInterface'
tags:
- { name: form.type }

CoreShop\Bundle\IndexBundle\Form\Schema\IndexSchemaEnricher:
tags:
- { name: coreshop_studio_form.enricher }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

/*
* CoreShop
*
* This source file is available under the terms of the
* CoreShop Commercial License (CCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) CoreShop GmbH (https://www.coreshop.com)
* @license CoreShop Commercial License (CCL)
*
*/

namespace CoreShop\Bundle\IndexBundle\Service;

use CoreShop\Component\Index\Model\IndexableInterface;
use CoreShop\Component\Index\Service\IndexableClassesProviderInterface;
use Pimcore\Model\DataObject\ClassDefinition;

final class IndexableClassesProvider implements IndexableClassesProviderInterface
{
public function getIndexableClassNames(): array
{
$listing = new ClassDefinition\Listing();
$result = [];

foreach ($listing->load() as $class) {
if (!$class instanceof ClassDefinition) {
continue;
}

$name = $class->getName();

if (null === $name || '' === $name) {
continue;
}

$pimcoreClass = 'Pimcore\\Model\\DataObject\\' . ucfirst($name);

if (!class_exists($pimcoreClass)) {
continue;
}

if (in_array(IndexableInterface::class, class_implements($pimcoreClass) ?: [], true)) {
$result[] = $name;
}
}

return $result;
}
}
61 changes: 49 additions & 12 deletions src/CoreShop/Bundle/IndexBundle/Worker/MysqlWorker.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,17 @@
}

if (array_key_exists('indexes', $index->getConfiguration())) {
/**
* @var TableIndex $tableIndex
*/
foreach ($index->getConfiguration()['indexes'] as $tableIndex) {
if ($tableIndex->getType() === TableIndex::TABLE_INDEX_TYPE_UNIQUE) {
$table->addUniqueIndex($tableIndex->getColumns());
$normalized = $this->normalizeTableIndex($tableIndex);

if (null === $normalized) {
continue;
}

if ($normalized['type'] === TableIndex::TABLE_INDEX_TYPE_UNIQUE) {
$table->addUniqueIndex($normalized['columns']);
} else {
$table->addIndex($tableIndex->getColumns());
$table->addIndex($normalized['columns']);
}
}
}
Expand Down Expand Up @@ -269,21 +272,55 @@
}

if (array_key_exists('localizedIndexes', $index->getConfiguration())) {
/**
* @var TableIndex $tableIndex
*/
foreach ($index->getConfiguration()['localizedIndexes'] as $tableIndex) {
if ($tableIndex->getType() === TableIndex::TABLE_INDEX_TYPE_UNIQUE) {
$table->addUniqueIndex($tableIndex->getColumns());
$normalized = $this->normalizeTableIndex($tableIndex);

if (null === $normalized) {
continue;
}

if ($normalized['type'] === TableIndex::TABLE_INDEX_TYPE_UNIQUE) {
$table->addUniqueIndex($normalized['columns']);
} else {
$table->addIndex($tableIndex->getColumns());
$table->addIndex($normalized['columns']);
}
}
}

return $tableSchema;
}

/**
* Accept both {@see TableIndex} objects (legacy programmatic setup) and plain arrays
* (the form + JSON-stored configuration format). Returns null for empty/invalid entries.
*
* @return array{type: string|null, columns: array<int, string>}|null
*/
private function normalizeTableIndex(mixed $tableIndex): ?array

Check warning on line 299 in src/CoreShop/Bundle/IndexBundle/Worker/MysqlWorker.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This method has 4 returns, which is more than the 3 allowed.

See more on https://sonarcloud.io/project/issues?id=coreshop_CoreShop&issues=AZ246WScUpWIFo_VH9M-&open=AZ246WScUpWIFo_VH9M-&pullRequest=3022
{
if ($tableIndex instanceof TableIndex) {
$columns = $tableIndex->getColumns();

if (empty($columns)) {
return null;
}

return [
'type' => $tableIndex->getType(),
'columns' => array_values($columns),
];
}

if (is_array($tableIndex) && !empty($tableIndex['columns']) && is_array($tableIndex['columns'])) {
return [
'type' => $tableIndex['type'] ?? null,
'columns' => array_values($tableIndex['columns']),
];
}

return null;
}

protected function createRelationalTableSchema(IndexInterface $index, Schema $tableSchema)
{
$table = $tableSchema->createTable($this->getRelationTablename($index->getName()));
Expand Down
Loading
Loading