I want to create a custom filter in the admin panel, in the order overview. Therefore I added a filter to the filter list:
Shopware.Component.override('sw-order-list', {
...
// Custom Filter hinzufügen
filterOptions['supplier-filter'] = {
property: 'customFields.supplier',
type: 'multi-select-filter',
label: this.$tc('swedi-order.filters.customFilter.label'),
placeholder: this.$tc('swedi-order.filters.customFilter.placeholder'),
valueProperty: 'id',
labelProperty: 'name',
options: this.suppliers,
loading: this.isSupplierLoading,
schema: {
entity: 'supplier',
referenceField: 'id',
},
custom: true, // Mark as custom for your logic
};
And a subscriber:
public static function getSubscribedEvents(): array
{
return [
EntitySearchedEvent::class => 'onOrderSearchCriteria',
'order.written' => 'onOrderWritten',
'order.loaded' => 'onOrderLoaded',
// Add more events as needed
];
}
public function onOrderSearchCriteria($event): void
{
$msgEvent = '[OrderFilterSubscriber] Event: ' . get_class($event);
$msgContext = '[OrderFilterSubscriber] Context: ' . print_r($event->getContext(), true);
$msgCriteria = '[OrderFilterSubscriber] Criteria: ' . print_r($event->getCriteria()->getFilters(), true);
$this->logger->info($msgEvent);
$this->logger->info($msgContext);
$this->logger->info($msgCriteria);
error_log($msgEvent);
error_log($msgContext);
error_log($msgCriteria);
}
when I open the order overview in admin panel, it fires the entity loaded event, but no search event, so I cannot modify the search criteria.
Anyone can help? Thanks! :)
I solved it!
The solution was to create a decorator, since there is no suitable event to listen to. So to create a custom order filter in the admin I did the following:
UI override:
Shopware.Component.override('sw-order-list', {
data() {
return {
suppliers: [],
isSupplierLoading: false,
};
},
created() {
if (!this.defaultFilters.includes('supplier-filter')) {
this.defaultFilters.push('supplier-filter');
}
this.loadSuppliers();
},
computed: {
/**
* Erweiterung der bestehenden Filteroptionen
*/
listFilterOptions() {
const filterOptions = this.$super('listFilterOptions');
// Custom Filter hinzufügen
filterOptions['supplier-filter'] = {
property: 'customFields.supplier',
type: 'multi-select-filter',
label: this.$tc('swedi-order.filters.customFilter.label'),
placeholder: this.$tc('swedi-order.filters.customFilter.placeholder'),
valueProperty: 'id',
labelProperty: 'name',
options: this.suppliers,
loading: this.isSupplierLoading,
};
return filterOptions;
},
},
And for the backend, the decorator:
<?php declare(strict_types=1);
namespace SwediPlugin\Decorator;
use Doctrine\DBAL\Connection;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
use Shopware\Core\Framework\Uuid\Uuid;
use Psr\Log\LoggerInterface;
use Shopware\Core\Checkout\Order\OrderCollection;
use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
class OrderRepositoryDecorator extends EntityRepository
{
private EntityRepository $inner;
private Connection $connection;
private LoggerInterface $logger;
public function __construct(EntityRepository $inner, LoggerInterface $logger)
{
$this->inner = $inner;
$this->connection = \Shopware\Core\Kernel::getConnection();
$this->logger = $logger;
}
public function getDefinition(): EntityDefinition
{
return $this->inner->getDefinition();
}
public function search(Criteria $criteria, Context $context): EntitySearchResult
{
try {
$supplierIds = [];
$newFilters = [];
// 1. Filter durchlaufen und "customFields.supplier" herausfiltern
foreach ($criteria->getFilters() as $filter) {
if (
$filter instanceof \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter
&& $filter->getField() === 'order.customFields.supplier'
) {
$supplierIds = $filter->getValue();
} else {
$newFilters[] = $filter;
}
}
// 2. Filter zurücksetzen und neu setzen
$criteria->resetFilters();
foreach ($newFilters as $filter) {
$criteria->addFilter($filter);
}
// 3. Standard-Suche ausführen, wenn keine Supplier-IDs vorhanden sind
if (empty($supplierIds)) {
return $this->inner->search($criteria, $context);
}
// 4. DBAL-Abfrage ausführen
$orderIds = $this->fetchOrderIdsBySupplierIds($supplierIds);
if (empty($orderIds)) {
return new EntitySearchResult(
'order', // <- Muss ein String sein, kein OrderDefinition-Objekt
0,
new OrderCollection(),
null,
$criteria,
$context
);
}
// 5. Criteria auf die gefundenen Order-IDs beschränken
$criteria->setIds($orderIds);
// 6. Originale Suche ausführen
$searchResult = $this->inner->search($criteria, $context);
// 7. EntitySearchResult erstellen und zurückgeben
return new EntitySearchResult(
'order',
$searchResult->getTotal(),
$searchResult->getEntities(),
$searchResult->getAggregations(),
$criteria,
$context
);
} catch (\Throwable $e) {
$this->logger->error('Fehler im OrderRepositoryDecorator: ' . $e->getMessage());
$this->logger->error('Stack Trace: ' . $e->getTraceAsString());
throw new \Exception('Ein Fehler ist im OrderRepositoryDecorator aufgetreten. Siehe Log für Details.');
}
}
/**
* Führt eine DBAL-Abfrage aus, um die Order-IDs anhand der Supplier-IDs zu ermitteln.
*/
private function fetchOrderIdsBySupplierIds(array $supplierIds): array
{
// UUIDs in Binärformat umwandeln
$binarySupplierIds = array_map(fn($id) => Uuid::fromHexToBytes($id), $supplierIds);
$query = '
SELECT DISTINCT LOWER(HEX(o.id)) AS order_id
FROM `order` o
INNER JOIN `order_line_item` line_items ON o.id = line_items.order_id
LEFT JOIN `pickware_erp_product_supplier_configuration` config ON line_items.product_id = config.product_id
LEFT JOIN `pickware_erp_supplier` supplier ON config.supplier_id = supplier.id
WHERE supplier.id IN (:supplierIds)
';
try {
$results = $this->connection->fetchFirstColumn($query, [
'supplierIds' => $binarySupplierIds, // Binärwerte verwenden
], [
'supplierIds' => Connection::PARAM_STR_ARRAY,
]);
return $results;
} catch (\Throwable $e) {
$this->logger->error('OrderRepositoryDecorator DBAL Fehler: ' . $e->getMessage());
throw $e;
}
}
}