From 0bff8728b19f7d89cd32f37a1f9134bd7d849a3e Mon Sep 17 00:00:00 2001 From: Maxime Rainville Date: Wed, 14 Nov 2018 18:01:29 +1300 Subject: [PATCH 1/6] MINOR Speed up DependentPages by shifting existence check to table join --- code/Model/SiteTree.php | 70 ++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/code/Model/SiteTree.php b/code/Model/SiteTree.php index 85be8e33..e7347328 100755 --- a/code/Model/SiteTree.php +++ b/code/Model/SiteTree.php @@ -1727,19 +1727,37 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi /** * Get the back-link tracking objects that link to this page * - * @retun ArrayList|DataObject[] + * @return ArrayList|DataObject[] */ public function BackLinkTracking() { // @todo - Implement PolymorphicManyManyList to replace this $list = ArrayList::create(); - foreach ($this->BackLinks() as $link) { - // Ensure parent record exists - $item = $link->Parent(); - if ($item && $item->isInDB()) { - $list->push($item); - } + + $joinClause = sprintf( + "\"%s\".\"ParentID\"=\"ParentRelationTable\".\"ID\"", + SiteTreeLink::singleton()->baseTable() + ); + + // Get the list of back links classes + $linkClasses = $this->BackLinks()->exclude(['ParentClass' => null])->columnUnique('ParentClass'); + + // Get list of sitreTreelink and join them to the their parent class to make sure we don't get orphan records. + foreach ($linkClasses as $linkClass) { + $links = $this->BackLinks() + ->filter(['ParentClass' => $linkClass]) + ->innerJoin( + DataObject::singleton($linkClass)->baseTable(), + $joinClause, + 'ParentRelationTable' + ) + ->alterDataQuery(function ($query) { + $query->selectField("'Content link'", "DependentLinkType"); + }) + ; + $list->merge($links); } + return $list; } @@ -1761,40 +1779,26 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi // We merge all into a regular SS_List, because DataList doesn't support merge if ($contentLinks = $this->BackLinkTracking()) { - $linkList = new ArrayList(); - foreach ($contentLinks as $item) { - $item->DependentLinkType = 'Content link'; - $linkList->push($item); - } - $items->merge($linkList); + $items->merge($contentLinks); } // Virtual pages if ($includeVirtuals) { - $virtuals = $this->VirtualPages(); - if ($virtuals) { - $virtualList = new ArrayList(); - foreach ($virtuals as $item) { - $item->DependentLinkType = 'Virtual page'; - $virtualList->push($item); - } - $items->merge($virtualList); - } + $virtuals = $this->VirtualPages() + ->alterDataQuery(function ($query) { + $query->selectField("'Virtual page'", "DependentLinkType"); + }); + $items->merge($virtuals); } // Redirector pages $redirectors = RedirectorPage::get()->where(array( - '"RedirectorPage"."RedirectionType"' => 'Internal', - '"RedirectorPage"."LinkToID"' => $this->ID - )); - if ($redirectors) { - $redirectorList = new ArrayList(); - foreach ($redirectors as $item) { - $item->DependentLinkType = 'Redirector page'; - $redirectorList->push($item); - } - $items->merge($redirectorList); - } + '"RedirectorPage"."RedirectionType"' => 'Internal', + '"RedirectorPage"."LinkToID"' => $this->ID + ))->alterDataQuery(function ($query) { + $query->selectField("'Redirector page'", "DependentLinkType"); + }); + $items->merge($redirectors); if (class_exists('Subsite')) { Subsite::disable_subsite_filter($origDisableSubsiteFilter); From b138eb06ff03308021ddffd75626dea73281b489 Mon Sep 17 00:00:00 2001 From: Maxime Rainville Date: Thu, 15 Nov 2018 15:57:17 +1300 Subject: [PATCH 2/6] Revert BackLinkTracking to return Parent Object of the SiteTreeLink rather than SiteTreeLink itself --- code/Model/SiteTree.php | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/code/Model/SiteTree.php b/code/Model/SiteTree.php index e7347328..eb5dfd66 100755 --- a/code/Model/SiteTree.php +++ b/code/Model/SiteTree.php @@ -1734,27 +1734,32 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi // @todo - Implement PolymorphicManyManyList to replace this $list = ArrayList::create(); - $joinClause = sprintf( - "\"%s\".\"ParentID\"=\"ParentRelationTable\".\"ID\"", - SiteTreeLink::singleton()->baseTable() - ); + $siteTreelinkTable = SiteTreeLink::singleton()->baseTable(); // Get the list of back links classes - $linkClasses = $this->BackLinks()->exclude(['ParentClass' => null])->columnUnique('ParentClass'); + $parentClasses = $this->BackLinks()->exclude(['ParentClass' => null])->columnUnique('ParentClass'); // Get list of sitreTreelink and join them to the their parent class to make sure we don't get orphan records. - foreach ($linkClasses as $linkClass) { - $links = $this->BackLinks() - ->filter(['ParentClass' => $linkClass]) + foreach ($parentClasses as $parentClass) { + $joinClause = sprintf( + "\"%s\".\"ParentID\"=\"%s\".\"ID\"", + $siteTreelinkTable, + $linkTable, + DataObject::singleton($parentClass)->baseTable() + ); + + $links = DataObject::get($parentClass) ->innerJoin( - DataObject::singleton($linkClass)->baseTable(), - $joinClause, - 'ParentRelationTable' + $siteTreelinkTable, + $joinClause ) + ->where([ + "\"$siteTreelinkTable\".\"LinkedID\"" => $this->ID, + "\"$siteTreelinkTable\".\"ParentClass\"" => $parentClass, + ]) ->alterDataQuery(function ($query) { $query->selectField("'Content link'", "DependentLinkType"); - }) - ; + }); $list->merge($links); } From 03869b1627ed934e51f8c2291b2f41f943e53a26 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Thu, 15 Nov 2018 13:30:33 +0200 Subject: [PATCH 3/6] Remove undefined variable, should use the baseTable() from the $parentClass --- code/Model/SiteTree.php | 1 - 1 file changed, 1 deletion(-) diff --git a/code/Model/SiteTree.php b/code/Model/SiteTree.php index eb5dfd66..3280a26d 100755 --- a/code/Model/SiteTree.php +++ b/code/Model/SiteTree.php @@ -1744,7 +1744,6 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi $joinClause = sprintf( "\"%s\".\"ParentID\"=\"%s\".\"ID\"", $siteTreelinkTable, - $linkTable, DataObject::singleton($parentClass)->baseTable() ); From 8977e4e79ea404e977f21b763b332a39f6b81f1b Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Thu, 15 Nov 2018 15:02:41 +0200 Subject: [PATCH 4/6] Update dependencies to have a minimum of SilverStripe 4.3 --- composer.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index cf9b5a3b..3d997053 100644 --- a/composer.json +++ b/composer.json @@ -19,12 +19,12 @@ } ], "require": { - "silverstripe/admin": "^1.1@dev", - "silverstripe/campaign-admin": "^1.1@dev", - "silverstripe/framework": "^4.1@dev", - "silverstripe/reports": "^4.1@dev", - "silverstripe/siteconfig": "^4.1@dev", - "silverstripe/versioned": "^1.1@dev", + "silverstripe/admin": "^1.3@dev", + "silverstripe/campaign-admin": "^1.3@dev", + "silverstripe/framework": "^4.3@dev", + "silverstripe/reports": "^4.3@dev", + "silverstripe/siteconfig": "^4.3@dev", + "silverstripe/versioned": "^1.3@dev", "silverstripe/vendor-plugin": "^1.0" }, "require-dev": { @@ -49,4 +49,4 @@ }, "prefer-stable": true, "minimum-stability": "dev" -} \ No newline at end of file +} From 4896004b504e1ac2b0a32c0b94f96a9cd0019dc9 Mon Sep 17 00:00:00 2001 From: micmania1 Date: Fri, 16 Nov 2018 14:12:01 +1300 Subject: [PATCH 5/6] BUGFIX reverting to publish still shows draft changees --- code/Controllers/CMSMain.php | 1 + 1 file changed, 1 insertion(+) diff --git a/code/Controllers/CMSMain.php b/code/Controllers/CMSMain.php index 8e8e37ce..a52558c4 100644 --- a/code/Controllers/CMSMain.php +++ b/code/Controllers/CMSMain.php @@ -2081,6 +2081,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr ); } else { $record->doRevertToLive(); + $record->publishRecursive(); $message = _t( __CLASS__ . '.ROLLEDBACKPUBv2', "Rolled back to published version." From 309dc97a325925b99e297343f5f76c71a33286e5 Mon Sep 17 00:00:00 2001 From: Guy Marriott Date: Fri, 23 Nov 2018 13:07:01 +1300 Subject: [PATCH 6/6] FIX Pages should use rollback recursive to revert to previous versions (#2329) --- _config/graphql.yml | 1 + client/dist/js/bundle.js | 2 +- client/src/boot/registerComponents.js | 11 ++++- .../src/state/history/rollbackPageMutation.js | 41 +++++++++++++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 client/src/state/history/rollbackPageMutation.js diff --git a/_config/graphql.yml b/_config/graphql.yml index 8399f913..26808626 100644 --- a/_config/graphql.yml +++ b/_config/graphql.yml @@ -10,6 +10,7 @@ SilverStripe\GraphQL\Manager: fields: [ID, LastEdited, AbsoluteLink] operations: copyToStage: true + rollback: true readOne: true SilverStripe\Security\Member: fields: [ID, FirstName, Surname] diff --git a/client/dist/js/bundle.js b/client/dist/js/bundle.js index 90d2cc32..1c4889d0 100644 --- a/client/dist/js/bundle.js +++ b/client/dist/js/bundle.js @@ -1 +1 @@ -!function(e){function t(a){if(n[a])return n[a].exports;var i=n[a]={i:a,l:!1,exports:{}};return e[a].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,a){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:a})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s="./client/src/bundles/bundle.js")}({"./client/src/boot/index.js":function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}var i=n("./client/src/boot/registerReducers.js"),r=a(i),o=n("./client/src/boot/registerComponents.js"),s=a(o);window.document.addEventListener("DOMContentLoaded",function(){(0,s.default)(),(0,r.default)()})},"./client/src/boot/registerComponents.js":function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(2),r=a(i),o=n("./client/src/components/AnchorSelectorField/AnchorSelectorField.js"),s=a(o),l=n("./client/src/state/history/readOnePageQuery.js"),d=a(l),c=n("./client/src/state/history/revertToPageVersionMutation.js"),u=a(c);t.default=function(){r.default.component.register("AnchorSelectorField",s.default),r.default.transform("pages-history",function(e){e.component("HistoryViewer.pages-controller-cms-content",d.default,"PageHistoryViewer")}),r.default.transform("pages-history-revert",function(e){e.component("HistoryViewerToolbar.VersionedAdmin.HistoryViewer.SiteTree.HistoryViewerVersionDetail",u.default,"PageRevertMutation")})}},"./client/src/boot/registerReducers.js":function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(2),r=a(i),o=n(11),s=n("./client/src/state/anchorSelector/AnchorSelectorReducer.js"),l=a(s);t.default=function(){r.default.reducer.register("cms",(0,o.combineReducers)({anchorSelector:l.default}))}},"./client/src/bundles/bundle.js":function(e,t,n){"use strict";n("./client/src/legacy/CMSMain.AddForm.js"),n("./client/src/legacy/CMSMain.EditForm.js"),n("./client/src/legacy/CMSMain.js"),n("./client/src/legacy/CMSMain.Tree.js"),n("./client/src/legacy/CMSPageHistoryController.js"),n("./client/src/legacy/RedirectorPage.js"),n("./client/src/legacy/SiteTreeURLSegmentField.js"),n("./client/src/boot/index.js")},"./client/src/components/AnchorSelectorField/AnchorSelectorField.js":function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function o(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function s(e,t){var n=(0,_.formValueSelector)(t.formid,I.default),a=t&&t.data&&t.data.targetFieldName||"PageID",i=Number(n(e,a)||0),r=[],o=i?e.cms.anchorSelector.pages.find(function(e){return e.id===i}):null;o&&o.loadingState===P.default.SUCCESS&&(r=o.anchors);var s=null;return s=o?o.loadingState:i?P.default.DIRTY:P.default.SUCCESS,{pageId:i,anchors:r,loadingState:s}}function l(e){return{actions:{anchorSelector:(0,v.bindActionCreators)(w,e)}}}Object.defineProperty(t,"__esModule",{value:!0}),t.ConnectedAnchorSelectorField=t.Component=void 0;var d=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:this.props;if(t.loadingState!==P.default.DIRTY||!t.pageId)return Promise.resolve();t.actions.anchorSelector.beginUpdating(t.pageId);var n=t.data.endpoint.replace(/:id/,t.pageId);return(0,m.default)(n,{credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){return t.actions.anchorSelector.updated(t.pageId,e),e}).catch(function(n){t.actions.anchorSelector.updateFailed(t.pageId),e.handleLoadingError(n,t)})}},{key:"getDropdownOptions",value:function(){var e=this,t=this.props.anchors.map(function(e){return{value:e}});return this.props.value&&!this.props.anchors.find(function(t){return t===e.props.value})&&t.unshift({value:this.props.value}),t}},{key:"handleChange",value:function(e){"function"==typeof this.props.onChange&&this.props.onChange(e?e.value:"")}},{key:"handleLoadingError",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.props;if(t.onLoadingError===O)throw e;return t.onLoadingError({errors:[{value:e.message,type:"error"}]})}},{key:"render",value:function(){var e={id:this.props.id},t=(0,j.default)("anchorselectorfield",this.props.extraClass),n=this.getDropdownOptions(),a=this.props.value||"",i=u.default._t("CMS.ANCHOR_SELECT_OR_TYPE","Select or enter anchor");return h.default.createElement(E.Creatable,{searchable:!0,options:n,className:t,name:this.props.name,inputProps:e,onChange:this.handleChange,onBlurResetsInput:!0,value:a,placeholder:i,labelKey:"value"})}}]),t}(S.default);R.propTypes={extraClass:x.default.string,id:x.default.string,name:x.default.string.isRequired,onChange:x.default.func,value:x.default.string,attributes:x.default.oneOfType([x.default.object,x.default.array]),pageId:x.default.number,anchors:x.default.array,loadingState:x.default.oneOf(Object.keys(P.default).map(function(e){return P.default[e]})),onLoadingError:x.default.func,data:x.default.shape({endpoint:x.default.string,targetFieldName:x.default.string})},R.defaultProps={value:"",extraClass:"",onLoadingError:O,attributes:{}};var L=(0,g.connect)(s,l)(R);t.Component=R,t.ConnectedAnchorSelectorField=L,t.default=(0,F.default)(L)},"./client/src/legacy/CMSMain.AddForm.js":function(e,t,n){"use strict";var a=n(0);(function(e){return e&&e.__esModule?e:{default:e}})(a).default.entwine("ss",function(e){e(".TreeDropdownField").entwine({OldValue:null}),e("#Form_AddForm_ParentID_Holder .treedropdownfield").entwine({onmatch:function(){this._super(),e(".cms-add-form").updateTypeList()}}),e(".cms-add-form .parent-mode :input").entwine({onclick:function(e){var t=this.closest("form").find("#Form_AddForm_ParentID_Holder .TreeDropdownField");"top"==this.val()?(t.setOldValue(t.getValue()),t.setValue(0)):(t.setValue(t.getOldValue()||0),t.setOldValue(null)),t.refresh(),t.trigger("change")}}),e(".cms-add-form").entwine({ParentCache:{},onadd:function(){var t=this;this.find("#Form_AddForm_ParentID_Holder .TreeDropdownField").bind("change",function(){t.updateTypeList()}),this.find(".SelectionGroup.parent-mode").bind("change",function(){t.updateTypeList()}),"top"==e(".cms-add-form .parent-mode :input").val()&&this.updateTypeList()},loadCachedChildren:function(e){var t=this.getParentCache();return void 0!==t[e]?t[e]:null},saveCachedChildren:function(e,t){var n=this.getParentCache();n[e]=t,this.setParentCache(n)},updateTypeList:function(){var t=this.data("hints"),n=this.find("#Form_AddForm_ParentID"),a=this.find("input[name=ParentModeField]:checked").val(),i=n.data("metadata"),r="child"===a?n.getValue():null,o=i?i.ClassName:null,s=o&&"child"===a&&r?o:"Root",l=void 0!==t[s]?t[s]:null,d=this,c=l&&void 0!==l.defaultChild?l.defaultChild:null,u=[];if(r){if(this.hasClass("loading"))return;return this.addClass("loading"),null!==(u=this.loadCachedChildren(r))?(this.updateSelectionFilter(u,c),void this.removeClass("loading")):(e.ajax({url:d.data("childfilter"),data:{ParentID:r},success:function(e){d.saveCachedChildren(r,e),d.updateSelectionFilter(e,c)},complete:function(){d.removeClass("loading")}}),!1)}u=l&&void 0!==l.disallowedChildren?l.disallowedChildren:[],this.updateSelectionFilter(u,c)},updateSelectionFilter:function(t,n){var a=null;if(this.find("#Form_AddForm_PageType div.radio").each(function(){var n=e(this).find("input").val(),i=-1===e.inArray(n,t);e(this).setEnabled(i),i||e(this).setSelected(!1),a=null===a?i:a&&i}),n)var i=this.find("#Form_AddForm_PageType div.radio input[value="+n+"]").parents("li:first");else var i=this.find("#Form_AddForm_PageType div.radio:not(.disabled):first");i.setSelected(!0),i.siblings().setSelected(!1),this.find("#Form_AddForm_PageType div.radio:not(.disabled)").length?this.find("button[name=action_doAdd]").removeAttr("disabled"):this.find("button[name=action_doAdd]").attr("disabled","disabled"),this.find(".message-restricted")[a?"hide":"show"]()}}),e(".cms-add-form #Form_AddForm_PageType div.radio").entwine({onclick:function(e){this.setSelected(!0)},setSelected:function(e){var t=this.find("input");e&&!t.is(":disabled")?(this.siblings().setSelected(!1),this.toggleClass("selected",!0),t.prop("checked",!0)):(this.toggleClass("selected",!1),t.prop("checked",!1))},setEnabled:function(t){e(this).toggleClass("disabled",!t),t?e(this).find("input").removeAttr("disabled"):e(this).find("input").attr("disabled","disabled").removeAttr("checked")}}),e(".cms-content-addpage-button").entwine({onclick:function(t){var n,a=e(".cms-tree"),i=e(".cms-list"),r=0;if(a.is(":visible")){var o=a.jstree("get_selected");r=o?e(o[0]).data("id"):null}else{var s=i.find('input[name="Page[GridState]"]').val();s&&(r=parseInt(JSON.parse(s).ParentID,10))}var l,d={selector:this.data("targetPanel"),pjax:this.data("pjax")};r?(n=this.data("extraParams")?this.data("extraParams"):"",l=e.path.addSearchParams(i18n.sprintf(this.data("urlAddpage"),r),n)):l=this.attr("href"),e(".cms-container").loadPanel(l,null,d),t.preventDefault(),this.blur()}})})},"./client/src/legacy/CMSMain.EditForm.js":function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}var i=n(0),r=a(i),o=n(1),s=a(o);r.default.entwine("ss",function(e){e(".cms-edit-form :input[name=ClassName]").entwine({onchange:function(){alert(s.default._t("CMS.ALERTCLASSNAME"))}}),e(".cms-edit-form input[name=Title]").entwine({onmatch:function(){var t=this;t.data("OrigVal",t.val());var n=t.closest("form"),a=e("input:text[name=URLSegment]",n),i=e("input[name=LiveLink]",n);a.length>0&&(t._addActions(),this.bind("change",function(n){var r=t.data("OrigVal"),o=t.val();t.data("OrigVal",o),0===a.val().indexOf(a.data("defaultUrl"))&&""==i.val()?t.updateURLSegment(o):e(".update",t.parent()).show(),t.updateRelatedFields(o,r),t.updateBreadcrumbLabel(o)})),this._super()},onunmatch:function(){this._super()},updateRelatedFields:function(t,n){this.parents("form").find("input[name=MetaTitle], input[name=MenuTitle]").each(function(){var a=e(this);a.val()==n&&(a.val(t),a.updatedRelatedFields&&a.updatedRelatedFields())})},updateURLSegment:function(t){var n=e("input:text[name=URLSegment]",this.closest("form")),a=n.closest(".field.urlsegment"),i=e(".update",this.parent());a.update(t),i.is(":visible")&&i.hide()},updateBreadcrumbLabel:function(t){var n=(e(".cms-edit-form input[name=ID]").val(),e("span.cms-panel-link.crumb"));t&&""!=t&&n.text(t)},_addActions:function(){var t,n=this;t=e("