Implement (un)serialize of bulk processing additional parameters
authorCyperghost <olaf_schmitz_1@t-online.de>
Tue, 23 Jan 2024 13:29:05 +0000 (14:29 +0100)
committerCyperghost <olaf_schmitz_1@t-online.de>
Tue, 23 Jan 2024 13:29:05 +0000 (14:29 +0100)
wcfsetup/install/files/lib/acp/form/AbstractBulkProcessingForm.class.php
wcfsetup/install/files/lib/system/bulk/processing/AbstractBulkProcessingAction.class.php
wcfsetup/install/files/lib/system/bulk/processing/IBulkProcessingAction.class.php
wcfsetup/install/files/lib/system/bulk/processing/user/AbstractUserGroupsUserBulkProcessingAction.class.php
wcfsetup/install/files/lib/system/worker/BulkProcessingWorker.class.php

index 3187a3cda31d380cfbb2446316cdddabedf8b980..43fdb223d28764e41f4e82aecccba85b588c9dfc 100644 (file)
@@ -2,9 +2,11 @@
 
 namespace wcf\acp\form;
 
+use wcf\data\object\type\AbstractObjectTypeProcessor;
 use wcf\data\object\type\ObjectType;
 use wcf\data\object\type\ObjectTypeCache;
 use wcf\form\AbstractForm;
+use wcf\system\bulk\processing\IBulkProcessingAction;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\UserInputException;
 use wcf\system\request\LinkHandler;
@@ -181,28 +183,61 @@ abstract class AbstractBulkProcessingForm extends AbstractForm
             }
         }
 
-        $this->objectList->readObjectIDs();
+        $action = $this->actions[$this->action]->getProcessor();
+        /** @var IBulkProcessingAction&AbstractObjectTypeProcessor $action */
+        if ($action->canRunInWorker()) {
+            $this->objectList->readObjectIDs();
 
-        $this->affectedObjectCount = \count($this->objectList->getObjectIDs());
-        // save config in session
-        $bulkProcessingData = WCF::getSession()->getVar('bulkProcessingData');
-        if ($bulkProcessingData === null) {
-            $bulkProcessingData = [];
+            $this->affectedObjectCount = \count($this->objectList->getObjectIDs());
+            // save config in session
+            $bulkProcessingData = WCF::getSession()->getVar('bulkProcessingData');
+            if ($bulkProcessingData === null) {
+                $bulkProcessingData = [];
+            }
+            $bulkProcessingID = \count($bulkProcessingData) + 1;
+
+            $bulkProcessingData[$bulkProcessingID] = [
+                'objectTypeID' => $action->objectTypeID,
+                'additionalParameters' => $action->getAdditionalParameters(),
+                '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();
+
+            WCF::getTPL()->assign('bulkProcessingID', $bulkProcessingID);
+        } else {
+            // Set a limit to avoid the 'Prepared statement contains too many placeholders' error
+            $this->objectList->sqlLimit = 65000;
+
+            $this->objectList->readObjects();
+
+            // execute action
+            if (\count($this->objectList)) {
+                $this->actions[$this->action]->getProcessor()->executeAction($this->objectList);
+            }
+
+            $this->affectedObjectCount = \count($this->objectList);
+
+            $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);
         }
-        $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();
-
-        WCF::getTPL()->assign('bulkProcessingID', $this->affectedObjectCount);
     }
 
     /**
index 4e82d60a8fe715f1f3ec09b3413b8a4c3fa71558..591a3bcf8a640ac8dd57af8b046ce384738fe91d 100644 (file)
@@ -53,4 +53,22 @@ abstract class AbstractBulkProcessingAction extends AbstractObjectTypeProcessor
     {
         // does nothing
     }
+
+    #[\Override]
+    public function canRunInWorker(): bool
+    {
+        return false;
+    }
+
+    #[\Override]
+    public function getAdditionalParameters(): array
+    {
+        return [];
+    }
+
+    #[\Override]
+    public function loadAdditionalParameters(array $data): void
+    {
+        // does nothing by default
+    }
 }
index dda0baaa1b18244a5816aab752d47e770ec4fd22..6ef7c970083cb1acee26e1243bbfae9dc0349ac2 100644 (file)
@@ -59,4 +59,25 @@ interface IBulkProcessingAction
      * Validates the additional action parameters.
      */
     public function validate();
+
+    /**
+     * Returns true if the action can be executed in a worker.
+     *
+     * @return  bool
+     */
+    public function canRunInWorker(): bool;
+
+    /**
+     * Returns the additional action parameters that should be serialized.
+     *
+     * @return  array
+     */
+    public function getAdditionalParameters(): array;
+
+    /**
+     * Loads the additional action parameters from the given data.
+     *
+     * @param array $data
+     */
+    public function loadAdditionalParameters(array $data): void;
 }
index 184b0f25f036085c6e1edca01151a1c2e1b9963f..6ddb521158648ddfca877598f2a932cc8587249c 100644 (file)
@@ -138,4 +138,10 @@ abstract class AbstractUserGroupsUserBulkProcessingAction extends AbstractUserBu
             }
         }
     }
+
+    #[\Override]
+    public function canRunInWorker(): bool
+    {
+        return true;
+    }
 }
index abe1caff376b9c787eab6ca351cc7893b82c203f..06b0786b496b51170f54f3df90c7a02847feb90e 100644 (file)
@@ -2,7 +2,9 @@
 
 namespace wcf\system\worker;
 
+use wcf\data\object\type\ObjectTypeCache;
 use wcf\system\bulk\processing\IBulkProcessingAction;
+use wcf\system\exception\PermissionDeniedException;
 use wcf\system\exception\SystemException;
 use wcf\system\WCF;
 
@@ -33,7 +35,17 @@ final class BulkProcessingWorker extends AbstractWorker
         }
 
         $this->bulkProcessingData = $bulkProcessingData[$this->parameters['bulkProcessingID']];
-        $this->action = $this->bulkProcessingData['action'];
+        $objectType = ObjectTypeCache::getInstance()->getObjectType($this->bulkProcessingData['objectTypeID']);
+        if (!$objectType->validateOptions() || !$objectType->validatePermissions()) {
+            throw new PermissionDeniedException();
+        }
+
+        $this->action = $objectType->getProcessor();
+        if (!$this->action->canRunInWorker()) {
+            throw new SystemException("action '" . $this->bulkProcessingData['action'] . "' cannot run in worker");
+        }
+
+        $this->action->unserializeData($this->bulkProcessingData['additionalParameters']);
     }
 
     #[\Override]