private function updateOrInsertTableRow(TableRow $data, $forceInsert = false, Statement $insertStmt = null) { $id = false; $pk = null; if ($data->description()->hasIdentifier()) { $pk = $data::toDbColumnName($data->description()->identifierName()); $id = $data->property($data->description()->identifierName())->value(); } $dbTypes = $this->getDbTypesForProperties($data); $itemType = $data->prototype()->of(); $data = $this->convertToDbData($data); //In try update mode we try to delete the table row first and then insert it again if (!$forceInsert) { $query = $this->connection->createQueryBuilder(); //Due to Sqlite error when using an alias we don't assign one here, so delete queries are limit to one table //However, a action event listener can rebuild the query and use a platform specific delete with joins if required $query->delete($this->table); if ($id) { $query->where($query->expr()->eq($pk, ':identifier')); $query->setParameter('identifier', $id, $dbTypes[$pk]); } elseif ($this->triggerActions) { $actionEvent = $this->actions->getNewActionEvent('delete_table_row', $this, ['query' => $query, 'item_type' => $itemType, 'item_db_data' => $data, 'item_db_types' => $dbTypes, 'skip_row' => false]); $this->actions->dispatch($actionEvent); if ($actionEvent->getParam('skip_row')) { return $insertStmt; } $query = $actionEvent->getParam('query'); if ($query && empty($query->getQueryPart('where'))) { $query = null; } } else { $query = null; } //We only perform the delete query if it has at least one condition set. if ($query) { $query->execute(); } } return $this->performInsert($data, $dbTypes, $insertStmt); }