mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-01-13 05:39:33 +00:00
* Erweiterungstätigkeiten zur IPN-Vorschlagsliste anhand von Präfixen aus den Kategorien * Umstellung Migrationen bzgl. Multi-Plattform-Support. Zunächst MySQL, SQLite Statements integrieren. * Postgre Statements integrieren * SQL-Formatierung in Migration verbessern * Erweitere IPN-Suggest um Bauteilbeschreibung. Die Implementierung berücksichtigt nun zusätzlich die Bauteilbeschreibung zu maximal 150 Zeichen Länge für die Generierung von IPN-Vorschlägen und Inkrementen. * Anpassungen aus Analyse vornehmen * IPN-Validierung für Parts überarbeiten * IPN-Vorschlagslogik um Konfiguration erweitert * Anpassungen aus phpstan Analyse * IPN-Vorschlagslogik erweitert und Bauteil-IPN vereindeutigt Die IPN-Logik wurde um eine Konfiguration zur automatischen Suffix-Anfügung und die Berücksichtigung von doppelten Beschreibungen bei Bedarf ergänzt. Zudem wurde das Datenmodell angepasst, um eine eindeutige Speicherung der IPN zu gewährleisten. * Regex-Konfigurationsmöglichkeit für IPN-Vorschläge einführen Die Einstellungen für die IPN-Vorschlagslogik wurden um eine Regex-Validierung und eine Hilfetext-Konfiguration erweitert. Tests und Änderungen an den Formularoptionen wurden implementiert. * Match range assert and form limits in suggestPartDigits * Keep existing behavior with autoAppend suffix by default * Show the regex hint in the browser validation notice. * Improved translations * Removed unnecessary service definition * Removed german comments --------- Co-authored-by: Marcel Diegelmann <marcel.diegelmann@gmail.com> Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
97 lines
3.3 KiB
PHP
97 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\EventSubscriber\UserSystem;
|
|
|
|
use App\Entity\Parts\Part;
|
|
use App\Settings\MiscSettings\IpnSuggestSettings;
|
|
use Doctrine\Common\EventSubscriber;
|
|
use Doctrine\ORM\Events;
|
|
use Doctrine\ORM\Event\OnFlushEventArgs;
|
|
|
|
class PartUniqueIpnSubscriber implements EventSubscriber
|
|
{
|
|
public function __construct(
|
|
private IpnSuggestSettings $ipnSuggestSettings
|
|
) {
|
|
}
|
|
|
|
public function getSubscribedEvents(): array
|
|
{
|
|
return [
|
|
Events::onFlush,
|
|
];
|
|
}
|
|
|
|
public function onFlush(OnFlushEventArgs $args): void
|
|
{
|
|
if (!$this->ipnSuggestSettings->autoAppendSuffix) {
|
|
return;
|
|
}
|
|
|
|
$em = $args->getObjectManager();
|
|
$uow = $em->getUnitOfWork();
|
|
$meta = $em->getClassMetadata(Part::class);
|
|
|
|
// Collect all IPNs already reserved in the current flush (so new entities do not collide with each other)
|
|
$reservedIpns = [];
|
|
|
|
// Helper to assign a collision-free IPN for a Part entity
|
|
$ensureUnique = function (Part $part) use ($em, $uow, $meta, &$reservedIpns) {
|
|
$ipn = $part->getIpn();
|
|
if ($ipn === null || $ipn === '') {
|
|
return;
|
|
}
|
|
|
|
// Check against IPNs already reserved in the current flush (except itself)
|
|
$originalIpn = $ipn;
|
|
$candidate = $originalIpn;
|
|
$increment = 1;
|
|
|
|
$conflicts = function (string $candidate) use ($em, $part, $reservedIpns) {
|
|
// Collision within the current flush session?
|
|
if (isset($reservedIpns[$candidate]) && $reservedIpns[$candidate] !== $part) {
|
|
return true;
|
|
}
|
|
// Collision with an existing DB row?
|
|
$existing = $em->getRepository(Part::class)->findOneBy(['ipn' => $candidate]);
|
|
return $existing !== null && $existing->getId() !== $part->getId();
|
|
};
|
|
|
|
while ($conflicts($candidate)) {
|
|
$candidate = $originalIpn . '_' . $increment;
|
|
$increment++;
|
|
}
|
|
|
|
if ($candidate !== $ipn) {
|
|
$before = $part->getIpn();
|
|
$part->setIpn($candidate);
|
|
|
|
// Recompute the change set so Doctrine writes the change
|
|
$uow->recomputeSingleEntityChangeSet($meta, $part);
|
|
$reservedIpns[$candidate] = $part;
|
|
|
|
// If the old IPN was reserved already, clean it up
|
|
if ($before !== null && isset($reservedIpns[$before]) && $reservedIpns[$before] === $part) {
|
|
unset($reservedIpns[$before]);
|
|
}
|
|
} else {
|
|
// Candidate unchanged, but reserve it so subsequent entities see it
|
|
$reservedIpns[$candidate] = $part;
|
|
}
|
|
};
|
|
|
|
// 1) Iterate over new entities
|
|
foreach ($uow->getScheduledEntityInsertions() as $entity) {
|
|
if ($entity instanceof Part) {
|
|
$ensureUnique($entity);
|
|
}
|
|
}
|
|
|
|
// 2) Iterate over updates (if IPN changed, ensure uniqueness again)
|
|
foreach ($uow->getScheduledEntityUpdates() as $entity) {
|
|
if ($entity instanceof Part) {
|
|
$ensureUnique($entity);
|
|
}
|
|
}
|
|
}
|
|
}
|