mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-12-10 21:19:30 +00:00
Added feature for part IPN suggest with category prefixes (#1054)
* 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>
This commit is contained in:
parent
14a4f1f437
commit
771857e014
34 changed files with 2791 additions and 115 deletions
97
src/EventSubscriber/UserSystem/PartUniqueIpnSubscriber.php
Normal file
97
src/EventSubscriber/UserSystem/PartUniqueIpnSubscriber.php
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<?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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue