[TikiWiki-commits] [Git][tikiwiki/tiki][30.x] [BP][FIX] Tracker/ItemLink: Cascade duplication of child items when duplicateCascade is enabled
"luci \(@luciash\) via TikiWiki-cvs" <[email protected]> Fri, 17 Jul 2026 15:20:54 +0000
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <6a5a4856dfdba_3819cfa8738f8@gitlab-sidekiq-low-urgency-cpu-bound-v2-7456c65c79-dtttt.mail> |
luci pushed to branch 30.x at Tiki Wiki CMS Groupware / Tiki
Commits:
ae48e56b by Landry Bitege at 2026-07-17T15:12:54+00:00
[BP][FIX] Tracker/ItemLink: Cascade duplication of child items when duplicateCascade is enabled
---
* [FIX] Tracker/ItemLink: Cascade duplication of child items when duplicateCascade is enabled
---
* [FIX] Tracker/ItemLink: Cascade duplication of child items when duplicateCascade is enabled
See merge request tikiwiki/tiki!10257
(cherry picked from commit ee79bf9599c5952fb176fc510d53623c76b563ee)
See merge request tikiwiki/tiki!10738
- - - - -
6 changed files:
- + installer/schema/20260519_itemlink_duplicate_cascade_tiki.php
- lib/core/Services/Tracker/Controller.php
- lib/core/Services/Tracker/Utilities.php
- lib/core/Tracker/Field/ItemLink.php
- templates/tracker/edit_field.tpl
- templates/tracker/insert_item.tpl
Changes:
=====================================
installer/schema/20260519_itemlink_duplicate_cascade_tiki.php
=====================================
@@ -0,0 +1,34 @@
+<?php
+
+// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
+//
+// All Rights Reserved. See copyright.txt for details and a complete list of authors.
+// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
+
+use Tiki\Installer\Installer;
+
+function upgrade_20260519_itemlink_duplicate_cascade_tiki(Installer $installer): void
+{
+ $fields = $installer->fetchAll(
+ "SELECT fieldId, options FROM tiki_tracker_fields WHERE type = 'r'"
+ );
+
+ foreach ($fields as $field) {
+ $options = @json_decode($field['options'], true);
+
+ if (! is_array($options)) {
+ continue;
+ }
+
+ $updated = Tracker_Field_ItemLink::syncDuplicateCascadeDefaultForUpgrade($options);
+
+ if ($updated === $options) {
+ continue;
+ }
+
+ $installer->query(
+ "UPDATE tiki_tracker_fields SET options = ? WHERE fieldId = ?",
+ [json_encode($updated), $field['fieldId']]
+ );
+ }
+}
=====================================
lib/core/Services/Tracker/Controller.php
=====================================
@@ -1078,6 +1078,9 @@ class Services_Tracker_Controller
);
if ($itemId) {
+ if ($cloneFrom) {
+ $this->utilities->cascadeChildItems($cloneFrom, $itemId);
+ }
TikiLib::lib('unifiedsearch')->processUpdateQueue();
TikiLib::events()->trigger('tiki.process.redirect'); // wait for indexing to complete before loading of next request to ensure updated info shown
@@ -1188,6 +1191,7 @@ class Services_Tracker_Controller
'skipRefresh' => $input->skipRefresh->bool(),
'refreshMeta' => $input->refreshMeta->raw(),
'refreshObject' => $input->refreshObject->raw(),
+ 'cloneFrom' => $cloneFrom,
];
}
=====================================
lib/core/Services/Tracker/Utilities.php
=====================================
@@ -672,7 +672,22 @@ EXPORT;
$itemObject = Tracker_Item::fromId($id);
- foreach (TikiLib::lib('trk')->get_child_items($itemId) as $info) {
+ if ($this->cascadeChildItems($itemId, $id, $strict, $insertIds)) {
+ foreach ($insertIds as $insertedId) {
+ $this->removeItem($insertedId);
+ }
+ $transaction->commit(); // there is no rollback
+ return false;
+ }
+
+ $transaction->commit();
+
+ return $itemObject;
+ }
+
+ public function cascadeChildItems(int $sourceItemId, int $newParentId, bool $strict = false, array &$insertIds = []): bool
+ {
+ foreach (TikiLib::lib('trk')->get_child_items($sourceItemId) as $info) {
$field = TikiLib::lib('trk')->get_tracker_field($info['field']);
$options = Tracker_Options::fromSerialized($field['options'], Tracker_Field_Factory::getFieldInfo($field['type']));
if (! $options->getParam('duplicateCascade')) {
@@ -680,39 +695,30 @@ EXPORT;
}
$childItem = Tracker_Item::fromId($info['itemId']);
+ if (! $childItem->canView()) {
+ continue;
+ }
- if ($childItem->canView()) {
- $childItem->asNew();
- $data = $childItem->getData();
- $data['fields'][$info['field']] = $id;
-
- $childDefinition = $childItem->getDefinition();
-
- // handle specific cloning actions
+ $childItem->asNew();
+ $data = $childItem->getData();
+ $data['fields'][$info['field']] = $newParentId;
- foreach ($childDefinition->getFields() as $field) {
- $handler = $childDefinition->getFieldFactory()->getHandler($field, $data);
- if (method_exists($handler, 'handleClone')) {
- $newData = $handler->handleClone($strict);
- $data['fields'][$field['permName']] = $newData['value'];
- }
+ $childDefinition = $childItem->getDefinition();
+ foreach ($childDefinition->getFields() as $childField) {
+ $handler = $childDefinition->getFieldFactory()->getHandler($childField, $data);
+ if (method_exists($handler, 'handleClone')) {
+ $newData = $handler->handleClone($strict);
+ $data['fields'][$childField['permName']] = $newData['value'];
}
+ }
- $new = $this->insertItem($childDefinition, $data);
- if ($new === false) {
- foreach ($insertIds as $id) { // undo items already created
- $this->removeItem($id);
- }
- $transaction->commit(); // there is no rollback
- return false;
- }
- $insertIds[] = $new;
+ $new = $this->insertItem($childDefinition, $data);
+ if ($new === false) {
+ return true;
}
+ $insertIds[] = $new;
}
-
- $transaction->commit();
-
- return $itemObject;
+ return false;
}
public static function convertToDefaultCurrency($data)
=====================================
lib/core/Tracker/Field/ItemLink.php
=====================================
@@ -1197,6 +1197,18 @@ class Tracker_Field_ItemLink extends \Tracker\Field\AbstractItemField implements
return ($this->trackerField->getOption('cascade') & $flag) > 0;
}
+ public static function syncDuplicateCascadeDefaultForUpgrade(array $options): array
+ {
+ if (array_key_exists('duplicateCascade', $options)) {
+ return $options;
+ }
+
+ $cascadeAll = self::CASCADE_CATEG | self::CASCADE_STATUS | self::CASCADE_DELETE;
+ $options['duplicateCascade'] = isset($options['cascade']) && (int) $options['cascade'] === $cascadeAll ? 1 : 0;
+
+ return $options;
+ }
+
public function watchCompare($old, $new)
{
if ($this->canHaveMultipleValues()) {
=====================================
templates/tracker/edit_field.tpl
=====================================
@@ -338,4 +338,11 @@
isPasswordDropdown.val('1');
}
});
+
+ $(document).on("change", "select[name='option~cascade']", function() {
+ const newVal = $(this).val() === '7' ? '1' : '0';
+ const dupNative = document.querySelector("select[name='option~duplicateCascade']");
+ $(dupNative).val(newVal);
+ $(dupNative).trigger("change");
+ });
{/jq}
=====================================
templates/tracker/insert_item.tpl
=====================================
@@ -37,6 +37,7 @@
<input type="button" class="btn btn-secondary previewItemBtn" title="{tr}Preview your changes.{/tr}" name="preview" value="{tr}Preview{/tr}">
{/if}
<input type="hidden" name="trackerId" value="{$trackerId|escape}">
+ {if $cloneFrom}<input type="hidden" name="clone_from" value="{$cloneFrom|escape}">{/if}
<input type="hidden" name="skipRefresh" value="{$skipRefresh|escape}">
<input type="hidden" name="refreshMeta" value="{$refreshMeta|escape}">
<input type="hidden" name="refreshObject" value="{$refreshObject|escape}">
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/ae48e56b0cb39713ef8047ecc85f67cb210dcb8e
--
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/ae48e56b0cb39713ef8047ecc85f67cb210dcb8e
You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help
_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs