From 0c5388292de533ee5eada081ad5a36472a7fb535 Mon Sep 17 00:00:00 2001 From: Daniel Lovegrove Date: Thu, 27 Aug 2026 14:41:33 -0500 Subject: [PATCH 1/4] Reduce save() calls on QubitEvent objects --- lib/model/QubitActor.php | 53 +++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/lib/model/QubitActor.php b/lib/model/QubitActor.php index cf4141d0bd..9d83986765 100644 --- a/lib/model/QubitActor.php +++ b/lib/model/QubitActor.php @@ -136,30 +136,29 @@ public function save($connection = null) parent::save($connection); - $creationIoIds = $otherIoIds = []; $context = sfContext::getInstance(); $env = $context->getConfiguration()->getEnvironment(); // Save related event objects - foreach ($this->events as $event) { - $event->indexOnSave = false; - - // Update search index for related info object, update them - // in QubitEvent synchronously in CLI tasks and jobs - if (in_array($env, ['cli', 'worker'])) { + if (in_array($env, ['cli', 'worker'])) { + // In CLI/worker environments, all events are saved with indexing enabled + // so related information objects are updated synchronously in QubitEvent. + foreach ($this->events as $event) { $event->indexOnSave = true; - } elseif (isset($event->objectId)) { - // Otherwise, do not update in QubitEvent, - // but save ids to update asynchronously - if (isset($event->typeId) && QubitTerm::CREATION_ID == $event->typeId) { - $creationIoIds[] = $event->objectId; - } else { - $otherIoIds[] = $event->objectId; + $event->actor = $this; + $event->save(); + } + } elseif (isset($this->refFkValues['events'])) { + // Only iterate the events collection if it has been initialized + // (i.e. events were accessed or added). This avoids a lazy-load of + // all events from the database when no events have been touched. + foreach ($this->refFkValues['events'] as $event) { + if (isset($event->new) && $event->new) { + $event->indexOnSave = false; + $event->actor = $this; + $event->save(); } } - - $event->actor = $this; - $event->save(); } // Save related contact information objects @@ -169,6 +168,26 @@ public function save($connection = null) } if ($this->indexOnSave) { + // Find creation-type events + $sql = sprintf(' + SELECT DISTINCT object_id + FROM %s + WHERE actor_id = ? AND type_id = ? AND object_id IS NOT NULL; + ', QubitEvent::TABLE_NAME + ); + $params = [$this->id, QubitTerm::CREATION_ID]; + $creationIoIds = QubitPdo::fetchAll($sql, $params, ['fetchMode' => PDO::FETCH_COLUMN]); + + // Find other non-creation-type events + $sql = sprintf(' + SELECT DISTINCT object_id + FROM %s + WHERE actor_id = ? AND (type_id != ? OR type_id IS NULL) AND object_id IS NOT NULL; + ', QubitEvent::TABLE_NAME + ); + $params = [$this->id, QubitTerm::CREATION_ID]; + $otherIoIds = QubitPdo::fetchAll($sql, $params, ['fetchMode' => PDO::FETCH_COLUMN]); + // Update asynchronously the saved IOs ids, two jobs may // be launched in here as creation events require updating // the descendants but other events don't. From e4ac774d0767aa9d8e9fce090797ca925bfbc09a Mon Sep 17 00:00:00 2001 From: Daniel Lovegrove Date: Thu, 27 Aug 2026 14:58:54 -0500 Subject: [PATCH 2/4] Use SQL style used elsewhere in codebase --- lib/model/QubitActor.php | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/lib/model/QubitActor.php b/lib/model/QubitActor.php index 9d83986765..329a0c073d 100644 --- a/lib/model/QubitActor.php +++ b/lib/model/QubitActor.php @@ -154,6 +154,7 @@ public function save($connection = null) // all events from the database when no events have been touched. foreach ($this->refFkValues['events'] as $event) { if (isset($event->new) && $event->new) { + // We don't index on save because we index below in arUpdateEsIoDocumentsJob $event->indexOnSave = false; $event->actor = $this; $event->save(); @@ -169,24 +170,18 @@ public function save($connection = null) if ($this->indexOnSave) { // Find creation-type events - $sql = sprintf(' - SELECT DISTINCT object_id - FROM %s - WHERE actor_id = ? AND type_id = ? AND object_id IS NOT NULL; - ', QubitEvent::TABLE_NAME - ); - $params = [$this->id, QubitTerm::CREATION_ID]; - $creationIoIds = QubitPdo::fetchAll($sql, $params, ['fetchMode' => PDO::FETCH_COLUMN]); + $sql = 'SELECT DISTINCT object_id FROM ' + .QubitEvent::TABLE_NAME + .' WHERE actor_id = ? AND type_id = ? AND object_id IS NOT NULL'; + + $creationIoIds = QubitPdo::fetchAll($sql, [$this->id, QubitTerm::CREATION_ID], ['fetchMode' => PDO::FETCH_COLUMN]); // Find other non-creation-type events - $sql = sprintf(' - SELECT DISTINCT object_id - FROM %s - WHERE actor_id = ? AND (type_id != ? OR type_id IS NULL) AND object_id IS NOT NULL; - ', QubitEvent::TABLE_NAME - ); - $params = [$this->id, QubitTerm::CREATION_ID]; - $otherIoIds = QubitPdo::fetchAll($sql, $params, ['fetchMode' => PDO::FETCH_COLUMN]); + $sql = 'SELECT DISTINCT object_id FROM ' + .QubitEvent::TABLE_NAME + .' WHERE actor_id = ? AND (type_id = ? OR type_id IS NULL) AND object_id IS NOT NULL'; + + $otherIoIds = QubitPdo::fetchAll($sql, [$this->id, QubitTerm::CREATION_ID], ['fetchMode' => PDO::FETCH_COLUMN]); // Update asynchronously the saved IOs ids, two jobs may // be launched in here as creation events require updating From dabefa22ec35c64b461c3b00f409843c74c04a82 Mon Sep 17 00:00:00 2001 From: Daniel Lovegrove Date: Thu, 27 Aug 2026 15:04:15 -0500 Subject: [PATCH 3/4] Fix bug in SQL --- lib/model/QubitActor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/model/QubitActor.php b/lib/model/QubitActor.php index 329a0c073d..403072a7a5 100644 --- a/lib/model/QubitActor.php +++ b/lib/model/QubitActor.php @@ -179,7 +179,7 @@ public function save($connection = null) // Find other non-creation-type events $sql = 'SELECT DISTINCT object_id FROM ' .QubitEvent::TABLE_NAME - .' WHERE actor_id = ? AND (type_id = ? OR type_id IS NULL) AND object_id IS NOT NULL'; + .' WHERE actor_id = ? AND (type_id != ? OR type_id IS NULL) AND object_id IS NOT NULL'; $otherIoIds = QubitPdo::fetchAll($sql, [$this->id, QubitTerm::CREATION_ID], ['fetchMode' => PDO::FETCH_COLUMN]); From 2f35e7db57b6288121c9cf700e236cd7b8e5bb21 Mon Sep 17 00:00:00 2001 From: Daniel Lovegrove Date: Thu, 27 Aug 2026 15:56:26 -0500 Subject: [PATCH 4/4] Use transient instead of refFkValues --- lib/model/QubitActor.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/model/QubitActor.php b/lib/model/QubitActor.php index 403072a7a5..f19c403317 100644 --- a/lib/model/QubitActor.php +++ b/lib/model/QubitActor.php @@ -148,11 +148,11 @@ public function save($connection = null) $event->actor = $this; $event->save(); } - } elseif (isset($this->refFkValues['events'])) { - // Only iterate the events collection if it has been initialized - // (i.e. events were accessed or added). This avoids a lazy-load of - // all events from the database when no events have been touched. - foreach ($this->refFkValues['events'] as $event) { + } else { + // Only iterate over newly created but not saved events (i.e., transient events). This + // avoids looping over all existing events, which are already saved in the event edit + // component + foreach ($this->events->transient as $event) { if (isset($event->new) && $event->new) { // We don't index on save because we index below in arUpdateEsIoDocumentsJob $event->indexOnSave = false;