Implement a bulk processing worker
authorCyperghost <olaf_schmitz_1@t-online.de>
Tue, 23 Jan 2024 12:15:20 +0000 (13:15 +0100)
committerCyperghost <olaf_schmitz_1@t-online.de>
Tue, 23 Jan 2024 12:15:20 +0000 (13:15 +0100)
wcfsetup/install/files/acp/templates/bulkProcessing.tpl
wcfsetup/install/files/lib/acp/form/AbstractBulkProcessingForm.class.php
wcfsetup/install/files/lib/system/worker/BulkProcessingWorker.class.php [new file with mode: 0644]

index d4b944ab9b85817ed2168bd8de66b546b0712d47..f3d6556939a2fa4068e8ab5485040bfc8e7079a1 100644 (file)
                }
        });
 </script>
+{if $bulkProcessingID|isset}
+       <script data-relocate="true">
+         {jsphrase name='wcf.acp.worker.abort.confirmMessage'}
+               require(['WoltLabSuite/Core/Acp/Ui/Worker'], (AcpUiWorker) => {
+               new AcpUiWorker({
+                       dialogId: 'bulkProcessing',
+                       dialogTitle: '{jslang}{$pageTitle}{/jslang}',
+                       className: 'wcf\\system\\worker\\BulkProcessingWorker',
+                       parameters: {
+                       bulkProcessingID: {@$bulkProcessingID},
+                       },
+               });
+      });
+       </script>
+{/if}
 
 <header class="contentHeader">
        <h1 class="contentTitle">{lang}{$objectType->getProcessor()->getLanguageItemPrefix()}{/lang}</h1>
index 6560e30cfb1928f6f0507a45ff5c24275b9b2539..3187a3cda31d380cfbb2446316cdddabedf8b980 100644 (file)
@@ -7,6 +7,7 @@ use wcf\data\object\type\ObjectTypeCache;
 use wcf\form\AbstractForm;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\UserInputException;
+use wcf\system\request\LinkHandler;
 use wcf\system\WCF;
 
 /**
@@ -134,6 +135,13 @@ abstract class AbstractBulkProcessingForm extends AbstractForm
         }
 
         parent::readData();
+
+        if (empty($_POST)) {
+            if (isset($_REQUEST['success']) && isset($_REQUEST['count'])) {
+                $this->affectedObjectCount = \intval($_REQUEST['count']);
+                WCF::getTPL()->assign('success', true);
+            }
+        }
     }
 
     /**
@@ -173,31 +181,28 @@ abstract class AbstractBulkProcessingForm extends AbstractForm
             }
         }
 
-        // Set a limit to avoid the 'Prepared statement contains too many placeholders' error
-        $this->objectList->sqlLimit = 65000;
+        $this->objectList->readObjectIDs();
 
-        $this->objectList->readObjects();
-
-        // execute action
-        if (\count($this->objectList)) {
-            $this->actions[$this->action]->getProcessor()->executeAction($this->objectList);
+        $this->affectedObjectCount = \count($this->objectList->getObjectIDs());
+        // save config in session
+        $bulkProcessingData = WCF::getSession()->getVar('bulkProcessingData');
+        if ($bulkProcessingData === null) {
+            $bulkProcessingData = [];
         }
-
-        $this->affectedObjectCount = \count($this->objectList);
+        $bulkProcessingData[$this->affectedObjectCount] = [
+            'action' => $this->actions[$this->action]->getProcessor(),
+            'objectIDs' => $this->objectList->getObjectIDs(),
+            'form' => LinkHandler::getInstance()->getControllerLink(get_called_class(), [
+                'isACP' => true,
+                'success' => true,
+                'count' => $this->affectedObjectCount,
+            ]),
+        ];
+        WCF::getSession()->register('bulkProcessingData', $bulkProcessingData);
 
         $this->saved();
 
-        // reset fields
-        $this->actions[$this->action]->getProcessor()->reset();
-
-        foreach ($this->conditions as $groupedObjectTypes) {
-            foreach ($groupedObjectTypes as $objectType) {
-                $objectType->getProcessor()->reset();
-            }
-        }
-        $this->action = '';
-
-        WCF::getTPL()->assign('success', true);
+        WCF::getTPL()->assign('bulkProcessingID', $this->affectedObjectCount);
     }
 
     /**
diff --git a/wcfsetup/install/files/lib/system/worker/BulkProcessingWorker.class.php b/wcfsetup/install/files/lib/system/worker/BulkProcessingWorker.class.php
new file mode 100644 (file)
index 0000000..abe1caf
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+
+namespace wcf\system\worker;
+
+use wcf\system\bulk\processing\IBulkProcessingAction;
+use wcf\system\exception\SystemException;
+use wcf\system\WCF;
+
+/**
+ * @author  Olaf Braun
+ * @copyright   2001-2024 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+final class BulkProcessingWorker extends AbstractWorker
+{
+    /**
+     * @inheritDoc
+     */
+    protected $limit = 100;
+    protected array $bulkProcessingData;
+    protected IBulkProcessingAction $action;
+
+    #[\Override]
+    public function validate()
+    {
+        if (!isset($this->parameters['bulkProcessingID'])) {
+            throw new SystemException("bulkProcessingID missing");
+        }
+
+        $bulkProcessingData = WCF::getSession()->getVar('bulkProcessingData');
+        if (!isset($bulkProcessingData[$this->parameters['bulkProcessingID']])) {
+            throw new SystemException("bulkProcessingID '" . $this->parameters['bulkProcessingID'] . "' is invalid");
+        }
+
+        $this->bulkProcessingData = $bulkProcessingData[$this->parameters['bulkProcessingID']];
+        $this->action = $this->bulkProcessingData['action'];
+    }
+
+    #[\Override]
+    public function countObjects()
+    {
+        return \count($this->bulkProcessingData['objectIDs']);
+    }
+
+    #[\Override]
+    public function getProgress()
+    {
+        $progress = parent::getProgress();
+
+        if ($progress == 100) {
+            // clear session
+            $bulkProcessingData = WCF::getSession()->getVar('bulkProcessingData');
+            unset($bulkProcessingData[$this->parameters['bulkProcessingID']]);
+            WCF::getSession()->register('bulkProcessingData', $bulkProcessingData);
+        }
+
+        return $progress;
+    }
+
+    #[\Override]
+    public function execute()
+    {
+        $objectList = $this->action->getObjectList();
+        $objectList->setObjectIDs(
+            \array_slice($this->bulkProcessingData['objectIDs'], $this->limit * $this->loopCount, $this->limit)
+        );
+        $objectList->readObjects();
+
+        $this->action->executeAction($objectList);
+    }
+
+    #[\Override]
+    public function getProceedURL()
+    {
+        return $this->bulkProcessingData['form'];
+    }
+}