From 83bd75e3ecab7daa3ff06453cbd78f22f4307084 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Thu, 17 Oct 2024 12:49:24 +1300 Subject: [PATCH] API Make CMSMain more generic Remove hardcoded references to pages and SiteTree Remove assumption that records are versioned Remove or validate assumptions about methods on the model class Improve general architecture of CMSMain --- _config/adminpanels.yml | 2 +- _config/cache.yml | 8 +- _config/config.yml | 2 +- _config/permissions.yml | 1 - client/dist/js/bundle.js | 2 +- client/src/legacy/CMSMain.AddForm.js | 16 +- client/src/legacy/CMSMain.Tree.js | 5 +- code/Controllers/CMSMain.php | 1309 +++++++++-------- code/Controllers/CMSPageAddController.php | 255 ---- .../Controllers/CMSPageSettingsController.php | 13 +- code/Controllers/CMSPagesController.php | 48 - code/Controllers/CMSSiteTreeFilter.php | 12 +- .../CMSSiteTreeFilter_PublishedPages.php | 2 +- .../CMSSiteTreeFilter_StatusDeletedPages.php | 2 +- .../CMSSiteTreeFilter_StatusDraftPages.php | 2 +- ...hp => LeftAndMainRecordIconsExtension.php} | 50 +- code/Forms/CMSMainAddForm.php | 238 +++ code/Forms/InternalLinkFormFactory.php | 4 +- ...tifier.php => CurrentRecordIdentifier.php} | 6 +- code/Model/RedirectorPage.php | 5 +- code/Model/SiteTree.php | 409 ++--- code/Model/VirtualPage.php | 13 +- code/Reports/BrokenLinksReport.php | 2 +- lang/en.yml | 2 + .../Controllers/Includes/CMSMain_AddForm.ss | 47 + .../Controllers/Includes/CMSMain_Content.ss | 23 +- ...tions.ss => CMSMain_ContentToolActions.ss} | 6 +- .../Controllers/Includes/CMSMain_EditForm.ss | 5 - .../Controllers/Includes/CMSMain_Filter.ss | 2 +- .../Controllers/Includes/CMSMain_LeftPanel.ss | 24 + .../Controllers/Includes/CMSMain_ListView.ss | 4 +- .../Includes/CMSMain_PageList_Sidebar.ss | 1 - ...Main_PageList.ss => CMSMain_RecordList.ss} | 0 .../Controllers/Includes/CMSMain_SubTree.ss | 4 +- .../CMS/Controllers/Includes/CMSMain_Tools.ss | 33 +- .../Controllers/Includes/CMSMain_TreeNode.ss | 6 +- .../Controllers/Includes/CMSMain_TreeView.ss | 20 +- .../Includes/CMSMain_ViewControls.ss | 6 +- .../Includes/CMSPageAddController_Content.ss | 45 - .../Includes/CMSPagesController_Content.ss | 18 - .../Includes/CMSPagesController_Tools.ss | 3 - tests/behat/features/create-a-page.feature | 4 +- tests/behat/features/duplicate-a-page.feature | 2 +- tests/behat/features/insert-a-link.feature | 14 +- .../behat/features/insert-anchor-link.feature | 8 +- tests/behat/features/sitetree.feature | 8 +- tests/php/Controllers/CMSMainTest.php | 158 +- .../TestHierarchicalDataObject.php | 18 + .../TestHierarchicalDataObjectWithSort.php | 20 + .../php/Controllers/CMSSiteTreeFilterTest.php | 42 +- .../LeftAndMainPageIconsExtensionTest.php | 30 - .../ModuleIconB.php | 11 - .../LeftAndMainRecordIconsExtensionTest.php | 35 + .../ModuleIconA.php | 4 +- .../ModuleIconB.php | 11 + .../ModuleIconC.php | 2 +- .../ModuleIconD.php | 13 + .../ModuleIconExtension.php | 6 +- .../icon_b.jpg | Bin .../icon_c.jpg | Bin .../icon_d.jpg | Bin 0 -> 2292 bytes tests/php/Model/SiteTreePermissionsTest.php | 4 +- tests/php/Model/SiteTreeTest.php | 82 +- tests/php/Model/SiteTreeTest_ClassA.php | 5 - .../Model/SiteTreeTest_StageStatusInherit.php | 18 - 65 files changed, 1451 insertions(+), 1699 deletions(-) delete mode 100644 code/Controllers/CMSPageAddController.php delete mode 100644 code/Controllers/CMSPagesController.php rename code/Controllers/{LeftAndMainPageIconsExtension.php => LeftAndMainRecordIconsExtension.php} (50%) create mode 100644 code/Forms/CMSMainAddForm.php rename code/Model/{CurrentPageIdentifier.php => CurrentRecordIdentifier.php} (82%) create mode 100644 templates/SilverStripe/CMS/Controllers/Includes/CMSMain_AddForm.ss rename templates/SilverStripe/CMS/Controllers/Includes/{CMSPagesController_ContentToolActions.ss => CMSMain_ContentToolActions.ss} (73%) create mode 100644 templates/SilverStripe/CMS/Controllers/Includes/CMSMain_LeftPanel.ss delete mode 100644 templates/SilverStripe/CMS/Controllers/Includes/CMSMain_PageList_Sidebar.ss rename templates/SilverStripe/CMS/Controllers/Includes/{CMSMain_PageList.ss => CMSMain_RecordList.ss} (100%) delete mode 100644 templates/SilverStripe/CMS/Controllers/Includes/CMSPageAddController_Content.ss delete mode 100644 templates/SilverStripe/CMS/Controllers/Includes/CMSPagesController_Content.ss delete mode 100644 templates/SilverStripe/CMS/Controllers/Includes/CMSPagesController_Tools.ss create mode 100644 tests/php/Controllers/CMSMainTest/TestHierarchicalDataObject.php create mode 100644 tests/php/Controllers/CMSMainTest/TestHierarchicalDataObjectWithSort.php delete mode 100644 tests/php/Controllers/LeftAndMainPageIconsExtensionTest.php delete mode 100644 tests/php/Controllers/LeftAndMainPageIconsExtensionTest/ModuleIconB.php create mode 100644 tests/php/Controllers/LeftAndMainRecordIconsExtensionTest.php rename tests/php/Controllers/{LeftAndMainPageIconsExtensionTest => LeftAndMainRecordIconsExtensionTest}/ModuleIconA.php (50%) create mode 100644 tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/ModuleIconB.php rename tests/php/Controllers/{LeftAndMainPageIconsExtensionTest => LeftAndMainRecordIconsExtensionTest}/ModuleIconC.php (72%) create mode 100644 tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/ModuleIconD.php rename tests/php/Controllers/{LeftAndMainPageIconsExtensionTest => LeftAndMainRecordIconsExtensionTest}/ModuleIconExtension.php (65%) rename tests/php/Controllers/{LeftAndMainPageIconsExtensionTest => LeftAndMainRecordIconsExtensionTest}/icon_b.jpg (100%) rename tests/php/Controllers/{LeftAndMainPageIconsExtensionTest => LeftAndMainRecordIconsExtensionTest}/icon_c.jpg (100%) create mode 100644 tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_d.jpg delete mode 100644 tests/php/Model/SiteTreeTest_StageStatusInherit.php diff --git a/_config/adminpanels.yml b/_config/adminpanels.yml index 0c13ba40bf..3704d1016d 100644 --- a/_config/adminpanels.yml +++ b/_config/adminpanels.yml @@ -2,4 +2,4 @@ Name: cmsdefaultadmin --- SilverStripe\Admin\AdminRootController: - default_panel: SilverStripe\CMS\Controllers\CMSPagesController + default_panel: SilverStripe\CMS\Controllers\CMSMain diff --git a/_config/cache.yml b/_config/cache.yml index 65c7b08084..a6abd6ff10 100644 --- a/_config/cache.yml +++ b/_config/cache.yml @@ -4,15 +4,15 @@ After: - '#corecache' --- SilverStripe\Core\Injector\Injector: - Psr\SimpleCache\CacheInterface.CMSMain_SiteTreeHints: + Psr\SimpleCache\CacheInterface.CMSMain_TreeHints: factory: SilverStripe\Core\Cache\CacheFactory constructor: - namespace: "CMSMain_SiteTreeHints" + namespace: "CMSMain_TreeHints" Psr\SimpleCache\CacheInterface.SiteTree_CreatableChildren: factory: SilverStripe\Core\Cache\CacheFactory constructor: namespace: "SiteTree_CreatableChildren" - Psr\SimpleCache\CacheInterface.SiteTree_PageIcons: + Psr\SimpleCache\CacheInterface.CMS_RecordIcons: factory: SilverStripe\Core\Cache\CacheFactory constructor: - namespace: "SiteTree_PageIcons" \ No newline at end of file + namespace: "CMS_RecordIcons" diff --git a/_config/config.yml b/_config/config.yml index a179cf9e0e..ef35968709 100644 --- a/_config/config.yml +++ b/_config/config.yml @@ -3,7 +3,7 @@ Name: cmsextensions --- SilverStripe\Admin\LeftAndMain: extensions: - - SilverStripe\CMS\Controllers\LeftAndMainPageIconsExtension + - SilverStripe\CMS\Controllers\LeftAndMainRecordIconsExtension - SilverStripe\CMS\Controllers\LeftAndMainBatchActionsExtension --- Name: cmsmodals diff --git a/_config/permissions.yml b/_config/permissions.yml index e1401cf66c..00bb904817 100644 --- a/_config/permissions.yml +++ b/_config/permissions.yml @@ -17,4 +17,3 @@ SilverStripe\Core\Injector\Injector: Services: - '%$SilverStripe\Security\PermissionChecker.sitetree' - '%$SilverStripe\CMS\Controllers\CMSMain' - - '%$SilverStripe\CMS\Model\SiteTree' diff --git a/client/dist/js/bundle.js b/client/dist/js/bundle.js index 45acbd6d8a..1c7c028a0c 100644 --- a/client/dist/js/bundle.js +++ b/client/dist/js/bundle.js @@ -1 +1 @@ -!function(){"use strict";var e={38:function(e,t,n){var a=i(n(420)),o=i(n(121));function i(e){return e&&e.__esModule?e:{default:e}}window.document.addEventListener("DOMContentLoaded",(()=>{(0,o.default)(),(0,a.default)()}))},121:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=i(n(207)),o=i(n(269));function i(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{a.default.component.register("AnchorSelectorField",o.default)}},420:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=r(n(207)),o=n(367),i=r(n(796));function r(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{a.default.reducer.register("cms",(0,o.combineReducers)({anchorSelector:i.default}))}},269:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.ConnectedAnchorSelectorField=t.Component=void 0;var a=C(n(815)),o=C(n(594)),i=C(n(950)),r=n(40),s=n(367),l=n(381),d=C(n(898)),u=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=_(t);if(n&&n.has(e))return n.get(e);var a={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&{}.hasOwnProperty.call(e,i)){var r=o?Object.getOwnPropertyDescriptor(e,i):null;r&&(r.get||r.set)?Object.defineProperty(a,i,r):a[i]=e[i]}return a.default=e,n&&n.set(e,a),a}(n(979)),c=C(n(996)),f=C(n(623)),h=C(n(315)),p=C(n(657)),m=C(n(432)),g=C(n(304)),v=C(n(935));function _(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(_=function(e){return e?n:t})(e)}function C(e){return e&&e.__esModule?e:{default:e}}const b=()=>null;class w extends d.default{constructor(e){super(e),this.handleChange=this.handleChange.bind(this),this.handleLoadingError=this.handleLoadingError.bind(this)}componentDidMount(){this.ensurePagesLoaded()}componentDidUpdate(e){this.props.pageId!==e.pageId&&this.ensurePagesLoaded()}ensurePagesLoaded(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props;if(e.loadingState===c.default.UPDATING||e.loadingState===c.default.SUCCESS||!e.pageId)return Promise.resolve();let t=[];e.loadingState===c.default.FIELD_ONLY&&(t=this.props.anchors),e.actions.anchorSelector.beginUpdating(e.pageId);const n=e.data.endpoint.replace(/:id/,e.pageId);return(0,i.default)(n,{credentials:"same-origin"}).then((e=>e.json())).then((n=>{const a=[...new Set([...n,...t])];return e.actions.anchorSelector.updated(e.pageId,a),a})).catch((t=>{e.actions.anchorSelector.updateFailed(e.pageId),this.handleLoadingError(t,e)}))}getDropdownOptions(){const e=this.props.anchors.map((e=>({value:e})));return this.props.value&&!this.props.anchors.find((e=>e===this.props.value))&&e.unshift({value:this.props.value}),e}handleChange(e){"function"==typeof this.props.onChange&&this.props.onChange(e?e.value:"")}handleLoadingError(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.props;if(t.onLoadingError===b)throw e;return t.onLoadingError({errors:[{value:e.message,type:"error"}]})}render(){const{extraClass:e,CreatableSelectComponent:t}=this.props,n=(0,g.default)("anchorselectorfield",e),i=this.getDropdownOptions(),r=this.props.value||"",s=a.default._t("CMS.ANCHOR_SELECT_OR_TYPE","Select or enter anchor");return o.default.createElement(p.default,null,o.default.createElement(t,{isSearchable:!0,isClearable:!0,options:i,className:n,name:this.props.name,onChange:this.handleChange,value:{value:r},noOptionsMessage:()=>a.default._t("CMS.ANCHOR_NO_OPTIONS","No options"),placeholder:s,getOptionLabel:e=>{let{value:t}=e;return t},classNamePrefix:"anchorselectorfield"}))}}t.Component=w,w.propTypes={extraClass:v.default.string,id:v.default.string,name:v.default.string.isRequired,onChange:v.default.func,value:v.default.string,attributes:v.default.oneOfType([v.default.object,v.default.array]),pageId:v.default.number,anchors:v.default.array,loadingState:v.default.oneOf(Object.keys(c.default).map((e=>c.default[e]))),onLoadingError:v.default.func,data:v.default.shape({endpoint:v.default.string,targetFieldName:v.default.string})},w.defaultProps={value:"",extraClass:"",onLoadingError:b,attributes:{},CreatableSelectComponent:h.default};const S=t.ConnectedAnchorSelectorField=(0,r.connect)((function(e,t){const n=(0,l.formValueSelector)(t.formid,m.default),a=t&&t.data&&t.data.targetFieldName||"PageID",o=Number(n(e,a)||0);let i=[];const r=o?e.cms.anchorSelector.pages.find((e=>e.id===o)):null;!r||r.loadingState!==c.default.SUCCESS&&r.loadingState!==c.default.DIRTY&&r.loadingState!==c.default.FIELD_ONLY||(i=r.anchors);let s=null;return s=r?r.loadingState:o?c.default.DIRTY:c.default.SUCCESS,{pageId:o,anchors:i,loadingState:s}}),(function(e){return{actions:{anchorSelector:(0,s.bindActionCreators)(u,e)}}}))(w);t.default=(0,f.default)(S)},586:function(e,t,n){var a;((a=n(669))&&a.__esModule?a:{default:a}).default.entwine("ss",(function(e){e(".TreeDropdownField").entwine({OldValue:null}),e("#Form_AddForm_ParentID_Holder .treedropdownfield").entwine({onmatch(){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").on("change",(function(){t.updateTypeList()})),this.find(".SelectionGroup.parent-mode").on("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(),o=n.data("metadata"),i="child"===a?n.getValue():null,r=o?o.ClassName:null,s=r&&"child"===a&&i?r:"Root",l=void 0!==t[s]?t[s]:null,d=this,u=l&&void 0!==l.defaultChild?l.defaultChild:null,c=[];if(i){if(this.hasClass("loading"))return;return this.addClass("loading"),null!==(c=this.loadCachedChildren(i))?(this.updateSelectionFilter(c,u),void this.removeClass("loading")):(e.ajax({url:d.data("childfilter"),data:{ParentID:i},success:function(e){d.saveCachedChildren(i,e),d.updateSelectionFilter(e,u)},complete:function(){d.removeClass("loading")}}),!1)}c=l&&void 0!==l.disallowedChildren?l.disallowedChildren:[],this.updateSelectionFilter(c,u)},updateSelectionFilter:function(t,n){var a=this.find("#Form_AddForm_PageType div.radio.selected")[0],o=!1,i=null;if(this.find("#Form_AddForm_PageType div.radio").each((function(n,r){var s=e(this).find("input").val(),l=-1===e.inArray(s,t);r===a&&l&&(o=!0),e(this).setEnabled(l),l||e(this).setSelected(!1),i=(null===i||i)&&l})),o)var r=e(a).parents("li:first");else if(n)r=this.find("#Form_AddForm_PageType div.radio input[value="+n+"]").parents("li:first");else r=this.find("#Form_AddForm_PageType div.radio:not(.disabled):first");r.setSelected(!0),r.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")[i?"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"),o=e(".cms-list"),i=0;if(a.is(":visible")){var r=a.jstree("get_selected");i=r?e(r[0]).data("id"):null}else{var s=o.find('input[name="Page[GridState]"]').val();s&&(i=parseInt(JSON.parse(s).ParentID,10))}var l,d={selector:this.data("targetPanel"),pjax:this.data("pjax")};i?(n=this.data("extraParams")?this.data("extraParams"):"",l=e.path.addSearchParams(i18n.sprintf(this.data("urlAddpage"),i),n)):l=this.attr("href"),e(".cms-container").loadPanel(l,null,d),t.preventDefault(),this.blur()}})}))},677:function(e,t,n){var a=r(n(669)),o=r(n(815)),i=r(n(216));function r(e){return e&&e.__esModule?e:{default:e}}a.default.entwine("ss",(function(e){e(".cms-edit-form :input#Form_EditForm_ClassName").entwine({onchange:function(){alert(o.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),o=e("input[name=LiveLink]",n);a.length>0&&(t._addActions(),this.on("change",(function(n){var i=t.data("OrigVal"),r=t.val();t.data("OrigVal",r),0===a.val().indexOf(a.data("defaultUrl"))&&""==o.val()?t.updateURLSegment(r):e(".update",t.parent()).show().parent(".form__field-holder").addClass("input-group"),t.updateRelatedFields(r,i),t.updateBreadcrumbLabel(r)}))),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")).closest(".field.urlsegment"),a=e(".update",this.parent());n.update(t),a.is(":visible")&&a.hide().parent(".form__field-holder").removeClass("input-group")},updateBreadcrumbLabel:function(t){e(".cms-edit-form input[name=ID]").val();var n=e("span.cms-panel-link.crumb");t&&""!=t&&n.text(t)},_addActions:function(){var t,n=this;(t=e(" + <% end_if %> diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_LeftPanel.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_LeftPanel.ss new file mode 100644 index 0000000000..12e1feba9b --- /dev/null +++ b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_LeftPanel.ss @@ -0,0 +1,24 @@ +
+
+ <% if $TreeIsFiltered %> + <% include SilverStripe\\Admin\\BackLink_Button Backlink=$BreadcrumbsBacklink %> + <% end_if %> + <% if $CurrentRecord %> + <%-- Explicit breadcrumb item for this menu section --%> +
+ +
+ <% else %> + <%-- Full breadcrumbs (useful for tree view which isn't available when viewing an edit form) --%> + <% include SilverStripe\\Admin\\CMSBreadcrumbs %> + <% end_if %> + <% include SilverStripe\\CMS\\Controllers\\CMSMain_Filter %> +
+
+ +
+
+
+
+ $RecordList +
diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_ListView.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_ListView.ss index aed42dfefd..e9257f3584 100644 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_ListView.ss +++ b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_ListView.ss @@ -1,6 +1,6 @@ -<% include SilverStripe\\CMS\\Controllers\\CMSPagesController_ContentToolActions %> +<% include SilverStripe\\CMS\\Controllers\\CMSMain_ContentToolActions %> -
+
$AddForm
diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_PageList_Sidebar.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_PageList_Sidebar.ss deleted file mode 100644 index 296f8a6e05..0000000000 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_PageList_Sidebar.ss +++ /dev/null @@ -1 +0,0 @@ -<% include SilverStripe\\CMS\\Controllers\\CMSMain_PageList %> diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_PageList.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_RecordList.ss similarity index 100% rename from templates/SilverStripe/CMS/Controllers/Includes/CMSMain_PageList.ss rename to templates/SilverStripe/CMS/Controllers/Includes/CMSMain_RecordList.ss diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_SubTree.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_SubTree.ss index 34140b294a..adf95e06a2 100644 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_SubTree.ss +++ b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_SubTree.ss @@ -4,13 +4,13 @@ <% if $limited %> <% else_if $children %> <% end_if %> <% if not $node.IsInDB %> diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_Tools.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_Tools.ss index d3d94aebda..356780a793 100644 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_Tools.ss +++ b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_Tools.ss @@ -1,26 +1,13 @@ -
-
-
- - <% include SilverStripe\\CMS\\Controllers\\CMSMain_Filter %> +<%-- If we're editing a record, include the left panel and allow it to be collapsed --%> +<% if $CurrentRecord %> +
+ <% include SilverStripe\\CMS\\Controllers\\CMSMain_LeftPanel %> +
+

$CMSTreeTitle

-
-
-
-
+
+ » + «
- $PageListSidebar -
-
-

$SiteConfig.Title

-
-
- » - «
-
+<% end_if %> diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_TreeNode.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_TreeNode.ss index 3a3f0e8bb1..402c37de7a 100644 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_TreeNode.ss +++ b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_TreeNode.ss @@ -1,6 +1,6 @@ -
  •   -   - {$node.TreeTitle} +
  •   +   + {$TreeTitle} $SubTree
  • diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_TreeView.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_TreeView.ss index d28b1e8431..05fc7dd27d 100644 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_TreeView.ss +++ b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_TreeView.ss @@ -1,6 +1,6 @@ -<% include SilverStripe\\CMS\\Controllers\\CMSPagesController_ContentToolActions View='Tree' %> +<% include SilverStripe\\CMS\\Controllers\\CMSMain_ContentToolActions View='Tree' %> -
    +
    $AddForm
    @@ -17,15 +17,15 @@ $ExtraTreeTools data-url-tree="$LinkWithSearch($Link('getsubtree')).ATT" data-url-savetreenode="$Link('savetreenode').ATT" data-url-updatetreenodes="$Link('updatetreenodes').ATT" - data-url-addpage="{$LinkPageAdd('AddForm/?action_doAdd=1', 'ParentID=%s&PageType=%s').ATT}" - data-url-editpage="$LinkPageEdit('%s').ATT" + data-url-addpage="{$LinkRecordAdd('AddForm/?action_doAdd=1', 'ParentID=%s&RecordType=%s').ATT}" + data-url-editpage="$LinkRecordEdit('%s').ATT" data-url-duplicate="{$Link('duplicate/%s').ATT}" data-url-duplicatewithchildren="{$Link('duplicatewithchildren/%s').ATT}" data-url-listview="{$Link('?view=list').ATT}" - data-hints="$SiteTreeHints.ATT" + data-hints="$TreeHints.ATT" data-childfilter="$Link('childfilter').ATT" data-extra-params="SecurityID=$SecurityID.ATT"> - $SiteTreeAsUL + $TreeAsUL
    <% else %> @@ -33,14 +33,14 @@ $ExtraTreeTools data-url-tree="$LinkWithSearch($Link('getsubtree')).ATT" data-url-savetreenode="$Link('savetreenode').ATT" data-url-updatetreenodes="$Link('updatetreenodes').ATT" - data-url-addpage="{$LinkPageAdd('AddForm/?action_doAdd=1', 'ParentID=%s&PageType=%s').ATT}" - data-url-editpage="$LinkPageEdit('%s').ATT" + data-url-addpage="{$LinkRecordAdd('AddForm/?action_doAdd=1', 'ParentID=%s&RecordType=%s').ATT}" + data-url-editpage="$LinkRecordEdit('%s').ATT" data-url-duplicate="{$Link('duplicate/%s').ATT}" data-url-duplicatewithchildren="{$Link('duplicatewithchildren/%s').ATT}" data-url-listview="{$Link('?view=list').ATT}" - data-hints="$SiteTreeHints.ATT" + data-hints="$TreeHints.ATT" data-childfilter="$Link('childfilter').ATT" data-extra-params="SecurityID=$SecurityID.ATT"> - $SiteTreeAsUL + $TreeAsUL
    <% end_if %> diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_ViewControls.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_ViewControls.ss index c9709e9ad8..a91c480623 100644 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_ViewControls.ss +++ b/templates/SilverStripe/CMS/Controllers/Includes/CMSMain_ViewControls.ss @@ -1,18 +1,18 @@
    <% if not $TreeIsFiltered %> - <%-- Change to data-pjax-target="Content-PageList" to enable in-edit listview --%> + <%-- Change to data-pjax-target="Content-RecordList" to enable in-edit listview --%> <% end_if %>
    diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSPageAddController_Content.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSPageAddController_Content.ss deleted file mode 100644 index b8e50ac91e..0000000000 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSPageAddController_Content.ss +++ /dev/null @@ -1,45 +0,0 @@ -
    - <% with $AddForm %> -
    -
    -
    - -
    -
    - -
    - <% if $Message %> -

    $Message

    - <% else %> - - <% end_if %> - -
    - <% if $Legend %>$Legend<% end_if %> - <% loop $Fields %> - $FieldHolder - <% end_loop %> -
    -
    - -
    - <% if $Actions %> -
    - <% loop $Actions %> - $Field - <% end_loop %> -
    - <% end_if %> -
    -
    - <% end_with %> -
    diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSPagesController_Content.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSPagesController_Content.ss deleted file mode 100644 index 956e7536a4..0000000000 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSPagesController_Content.ss +++ /dev/null @@ -1,18 +0,0 @@ -
    -
    -
    - <% if $TreeIsFiltered %> - - <%t SilverStripe\Admin\LeftAndMain.NavigateUp "Return to Pages" %> - - <% end_if %> - <% include SilverStripe\\Admin\\CMSBreadcrumbs %> - <% include SilverStripe\\CMS\\Controllers\\CMSMain_Filter %> -
    -
    - -
    - $Tools - $PageList -
    -
    diff --git a/templates/SilverStripe/CMS/Controllers/Includes/CMSPagesController_Tools.ss b/templates/SilverStripe/CMS/Controllers/Includes/CMSPagesController_Tools.ss deleted file mode 100644 index d82c105fb9..0000000000 --- a/templates/SilverStripe/CMS/Controllers/Includes/CMSPagesController_Tools.ss +++ /dev/null @@ -1,3 +0,0 @@ -
    -
    -
    diff --git a/tests/behat/features/create-a-page.feature b/tests/behat/features/create-a-page.feature index cec74cd147..e52d98d926 100644 --- a/tests/behat/features/create-a-page.feature +++ b/tests/behat/features/create-a-page.feature @@ -31,12 +31,12 @@ Feature: Create a page # Virtual page doesn't allow children, page radio button below should be disabled And I select "MyVirtualPage" in the "#Form_AddForm_ParentID_Holder" tree dropdown And I wait for 2 seconds - Then I should see a "#Form_AddForm_PageType_Page[disabled]" element + Then I should see a "#Form_AddForm_RecordType_Page[disabled]" element # Normal pages allows children, page radio button below should not be disabled When I select "MyPage" in the "#Form_AddForm_ParentID_Holder" tree dropdown And I wait for 2 seconds And I select the "Page" radio button - Then I should not see a "#Form_AddForm_PageType_Page[disabled]" element + Then I should not see a "#Form_AddForm_RecordType_Page[disabled]" element And I press the "Create" button Then I should see an edit page form diff --git a/tests/behat/features/duplicate-a-page.feature b/tests/behat/features/duplicate-a-page.feature index 2a3884ac62..129f97a457 100644 --- a/tests/behat/features/duplicate-a-page.feature +++ b/tests/behat/features/duplicate-a-page.feature @@ -18,7 +18,7 @@ Feature: Duplicate a page And I right click on "Page1" in the tree And I hover on "Duplicate" in the context menu And I click on "This page and subpages" in the context menu - Then I should see a "Duplicated 'Page1' and children successfully" success toast + Then I should see a "Duplicated Page "Page1" and children" success toast When I fill in "MenuTitle" with "Duplicate Page" And I press the "Publish" button diff --git a/tests/behat/features/insert-a-link.feature b/tests/behat/features/insert-a-link.feature index 960967622e..2466bb402c 100644 --- a/tests/behat/features/insert-a-link.feature +++ b/tests/behat/features/insert-a-link.feature @@ -29,7 +29,7 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "awesome" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can wrap an image in a link to an internal page Given I fill in the "Content" HTML field with "

    " @@ -43,7 +43,7 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can edit a link to an internal page Given I fill in the "Content" HTML field with "awesome" @@ -60,7 +60,7 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "awesome" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can link to an external URL Given I select "awesome" in the "Content" HTML field @@ -73,7 +73,7 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "awesome" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can wrap an image in a link to an external URL Given I fill in the "Content" HTML field with "

    " @@ -87,7 +87,7 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can edit an external link Given I fill in the "Content" HTML field with "

    My awesome content" @@ -102,7 +102,7 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "awesome" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can remove an external link Given I fill in the "Content" HTML field with "My awesome content" @@ -112,7 +112,7 @@ So that I can link to a external website or a page on my site And the "Content" HTML field should not contain "http://silverstripe.org" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can navigate list of Site tree links by clicking on the dropdown elements When I select "awesome" in the "Content" HTML field diff --git a/tests/behat/features/insert-anchor-link.feature b/tests/behat/features/insert-anchor-link.feature index 931405f2f7..8527d55eea 100644 --- a/tests/behat/features/insert-anchor-link.feature +++ b/tests/behat/features/insert-anchor-link.feature @@ -28,7 +28,7 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "awesome" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can wrap an image in a link to an anchor in an internal page Given I fill in the "Content" HTML field with "

    " @@ -44,7 +44,7 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can link to an anchor from a dataobject on the current page When I select "awesome" in the "Content" HTML field @@ -59,7 +59,7 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "awesome" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast Scenario: I can link to an unsaved anchor in the current page Given I fill in the "Content" HTML field with "

    My awesome content

    unsaved content

    " @@ -77,4 +77,4 @@ So that I can link to a external website or a page on my site Then the "Content" HTML field should contain "awesome" # Required to avoid "unsaved changes" browser dialog When I press the "Save" button - Then I should see a "Saved 'About Us' successfully" success toast + Then I should see a "Saved Page "About Us"" success toast diff --git a/tests/behat/features/sitetree.feature b/tests/behat/features/sitetree.feature index d6ac54971b..bb38d84921 100644 --- a/tests/behat/features/sitetree.feature +++ b/tests/behat/features/sitetree.feature @@ -44,7 +44,7 @@ Feature: Sitetree When I click on the ".toast__close" element # Wait a little time to ensure the last toast is cleared And I wait for 2 seconds - + # Unpublish pages in a batch When I click on the "#record-2 .jstree-checkbox" element And I select "Unpublish" from the "Form_BatchActionsForm_Action" field with javascript @@ -66,10 +66,10 @@ Feature: Sitetree Then I should not see "Three" # Toggle list and tree views - Then I should not see a "#Form_ListViewForm_Page" element + Then I should not see a "#Form_ListViewForm_Record" element When I click on the "[data-view='listview']" element And I wait for 5 seconds - Then I should see a "#Form_ListViewForm_Page" element + Then I should see a "#Form_ListViewForm_Record" element When I click on the "[data-view='treeview']" element And I wait for 5 seconds - Then I should not see a "#Form_ListViewForm_Page" element + Then I should not see a "#Form_ListViewForm_Record" element diff --git a/tests/php/Controllers/CMSMainTest.php b/tests/php/Controllers/CMSMainTest.php index 0a9d0c8543..0312f74e37 100644 --- a/tests/php/Controllers/CMSMainTest.php +++ b/tests/php/Controllers/CMSMainTest.php @@ -2,11 +2,16 @@ namespace SilverStripe\CMS\Tests\Controllers; +use LogicException; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\SimpleCache\CacheInterface; +use ReflectionMethod; use SilverStripe\Admin\CMSBatchActionHandler; use SilverStripe\CMS\Controllers\CMSMain; use SilverStripe\CMS\Model\RedirectorPage; use SilverStripe\CMS\Model\SiteTree; +use SilverStripe\CMS\Tests\Controllers\CMSMainTest\TestHierarchicalDataObject; +use SilverStripe\CMS\Tests\Controllers\CMSMainTest\TestHierarchicalDataObjectWithSort; use SilverStripe\CMS\Tests\Controllers\CMSMainTest\TestStatusFlagsPage; use SilverStripe\Control\Controller; use SilverStripe\Control\HTTPRequest; @@ -35,6 +40,8 @@ class CMSMainTest extends FunctionalTest protected static $extraDataObjects = [ TestStatusFlagsPage::class, + TestHierarchicalDataObject::class, + TestHierarchicalDataObjectWithSort::class, ]; protected function setUp(): void @@ -50,15 +57,15 @@ protected function setUp(): void } } - public function testSiteTreeHints() + public function testTreeHints() { - $cache = Injector::inst()->get(CacheInterface::class . '.CMSMain_SiteTreeHints'); + $cache = Injector::inst()->get(CacheInterface::class . '.CMSMain_TreeHints'); // Login as user with root creation privileges $user = $this->objFromFixture(Member::class, 'rootedituser'); Security::setCurrentUser($user); $cache->clear(); - $rawHints = singleton(CMSMain::class)->SiteTreeHints(); + $rawHints = singleton(CMSMain::class)->TreeHints(); $this->assertNotNull($rawHints); $rawHints = preg_replace('/^"(.*)"$/', '$1', Convert::xml2raw($rawHints) ?? ''); @@ -127,7 +134,7 @@ public function testChildFilter() * Test that getCMSFields works on each page type. * Mostly, this is just checking that the method doesn't return an error */ - public function testThatGetCMSFieldsWorksOnEveryPageType() + public function testThatGetCMSFieldsWorksOnEveryRecordType() { $classes = ClassInfo::subclassesFor(SiteTree::class); array_shift($classes); @@ -245,10 +252,10 @@ public function testCreationOfTopLevelPage() Security::setCurrentUser($cmsUser); $this->get('admin/pages/add'); $response = $this->post( - 'admin/pages/add/AddForm', + 'admin/pages/AddForm', [ 'ParentID' => '0', - 'PageType' => RedirectorPage::class, + 'RecordType' => RedirectorPage::class, 'Locale' => 'en_US', 'action_doAdd' => 1, 'ajax' => 1, @@ -265,10 +272,10 @@ public function testCreationOfTopLevelPage() $response = $this->get('admin/pages/add'); $response = $this->post( - 'admin/pages/add/AddForm', + 'admin/pages/AddForm', [ 'ParentID' => '0', - 'PageType' => RedirectorPage::class, + 'RecordType' => RedirectorPage::class, 'Locale' => 'en_US', 'action_doAdd' => 1, 'ajax' => 1, @@ -296,10 +303,10 @@ public function testCreationOfRestrictedPage() // Create toplevel page $this->get('admin/pages/add'); $response = $this->post( - 'admin/pages/add/AddForm', + 'admin/pages/AddForm', [ 'ParentID' => '0', - 'PageType' => CMSMainTest_ClassA::class, + 'RecordType' => CMSMainTest_ClassA::class, 'Locale' => 'en_US', 'action_doAdd' => 1, 'ajax' => 1, @@ -316,10 +323,10 @@ public function testCreationOfRestrictedPage() // Create allowed child $this->get('admin/pages/add'); $response = $this->post( - 'admin/pages/add/AddForm', + 'admin/pages/AddForm', [ 'ParentID' => $newPageId, - 'PageType' => CMSMainTest_ClassB::class, + 'RecordType' => CMSMainTest_ClassB::class, 'Locale' => 'en_US', 'action_doAdd' => 1, 'ajax' => 1, @@ -342,10 +349,10 @@ public function testCreationOfRestrictedPage() // Create disallowed child $this->get('admin/pages/add'); $response = $this->post( - 'admin/pages/add/AddForm', + 'admin/pages/AddForm', [ 'ParentID' => $newPageId, - 'PageType' => RedirectorPage::class, + 'RecordType' => RedirectorPage::class, 'Locale' => 'en_US', 'action_doAdd' => 1, 'ajax' => 1, @@ -669,13 +676,15 @@ public function testChangeClass() $this->assertEquals('Class A', $newPage->Title); } - public function testSiteTreeHintsCache() + public function testTreeHintsCache() { $cms = CMSMain::create(); + $reflectionAllowedSubclasses = new ReflectionMethod($cms, 'getAllowedSubClasses'); + $reflectionAllowedSubclasses->setAccessible(true); /** @var Member $user */ $user = $this->objFromFixture(Member::class, 'rootedituser'); Security::setCurrentUser($user); - $pageClass = array_values(SiteTree::page_type_classes())[0]; + $pageClass = array_values($reflectionAllowedSubclasses->invoke($cms))[0]; $mockPageMissesCache = $this->getMockBuilder($pageClass) ->onlyMethods(['canCreate']) ->getMock(); @@ -693,31 +702,31 @@ public function testSiteTreeHintsCache() // Initially, cache misses (1) Injector::inst()->registerService($mockPageMissesCache, $pageClass); - $hints = $cms->SiteTreeHints(); + $hints = $cms->TreeHints(); $this->assertNotNull($hints); // Now it hits Injector::inst()->registerService($mockPageHitsCache, $pageClass); - $hints = $cms->SiteTreeHints(); + $hints = $cms->TreeHints(); $this->assertNotNull($hints); // Mutating member record invalidates cache. Misses (2) $user->FirstName = 'changed'; $user->write(); Injector::inst()->registerService($mockPageMissesCache, $pageClass); - $hints = $cms->SiteTreeHints(); + $hints = $cms->TreeHints(); $this->assertNotNull($hints); // Now it hits again Injector::inst()->registerService($mockPageHitsCache, $pageClass); - $hints = $cms->SiteTreeHints(); + $hints = $cms->TreeHints(); $this->assertNotNull($hints); // Different user. Misses. (3) $user = $this->objFromFixture(Member::class, 'allcmssectionsuser'); Security::setCurrentUser($user); Injector::inst()->registerService($mockPageMissesCache, $pageClass); - $hints = $cms->SiteTreeHints(); + $hints = $cms->TreeHints(); $this->assertNotNull($hints); } @@ -761,21 +770,118 @@ public function testSearchField() ); } - public function testCanOrganiseSitetree() + public function testCanOrganiseTree() { $cms = CMSMain::create(); - $this->assertFalse($cms->CanOrganiseSitetree()); + $this->assertFalse($cms->CanOrganiseTree()); $this->logInWithPermission('CMS_ACCESS_CMSMain'); - $this->assertFalse($cms->CanOrganiseSitetree()); + $this->assertFalse($cms->CanOrganiseTree()); $this->logOut(); $this->logInWithPermission('SITETREE_REORGANISE'); - $this->assertTrue($cms->CanOrganiseSitetree()); + $this->assertTrue($cms->CanOrganiseTree()); $this->logOut(); $this->logInWithPermission('ADMIN'); - $this->assertTrue($cms->CanOrganiseSitetree()); + $this->assertTrue($cms->CanOrganiseTree()); + } + + public function testGetCreatableSubClassesCache() + { + // Use injector because CMSMain defines some injectable dependencies + $cms = CMSMain::create(); + $reflectionMethod = new ReflectionMethod($cms, 'getCreatableSubClasses'); + $reflectionMethod->setAccessible(true); + + $siteTree = new SiteTree(); + $user = $this->objFromFixture(Member::class, 'allcmssectionsuser'); + Security::setCurrentUser($user); + $classes = ClassInfo::getValidSubClasses(SiteTree::class); + SiteTree::singleton()->updateAllowedSubClasses($classes); + $pageClass = array_values($classes)[0]; + + $mockPageMissesCache = $this->getMockBuilder($pageClass) + ->onlyMethods(['canCreate']) + ->getMock(); + $mockPageMissesCache + ->expects($this->exactly(3)) + ->method('canCreate'); + + $mockPageHitsCache = $this->getMockBuilder($pageClass) + ->onlyMethods(['canCreate']) + ->getMock(); + $mockPageHitsCache + ->expects($this->never()) + ->method('canCreate'); + + // Initially, cache misses (1) + Injector::inst()->registerService($mockPageMissesCache, $pageClass); + $result = $reflectionMethod->invoke($cms, $siteTree); + $this->assertNotNull($result); + + // Now it hits + Injector::inst()->registerService($mockPageHitsCache, $pageClass); + $result = $reflectionMethod->invoke($cms, $siteTree); + $this->assertNotNull($result); + + + // Mutating member record invalidates cache. Misses (2) + $user->FirstName = 'changed'; + $user->write(); + Injector::inst()->registerService($mockPageMissesCache, $pageClass); + $result = $reflectionMethod->invoke($cms, $siteTree); + $this->assertNotNull($result); + + // Now it hits again + Injector::inst()->registerService($mockPageHitsCache, $pageClass); + $result = $reflectionMethod->invoke($cms, $siteTree); + $this->assertNotNull($result); + + // Different user. Misses. (3) + $user = $this->objFromFixture(Member::class, 'rootedituser'); + Security::setCurrentUser($user); + Injector::inst()->registerService($mockPageMissesCache, $pageClass); + $result = $reflectionMethod->invoke($cms, $siteTree); + $this->assertNotNull($result); + } + + public static function provideInit(): array + { + return [ + [ + 'class' => DataObject::class, + 'throwsException' => true, + ], + [ + 'class' => TestHierarchicalDataObject::class, + 'throwsException' => true, + ], + [ + 'class' => TestHierarchicalDataObjectWithSort::class, + 'throwsException' => false, + ], + [ + 'class' => SiteTree::class, + 'throwsException' => false, + ], + ]; + } + + #[DataProvider('provideInit')] + public function testInit(string $class, bool $throwsException): void + { + CMSMain::config()->set('model_class', $class); + // Use injector because CMSMain defines some injectable dependencies + $cms = CMSMain::create(); + $initReflection = new ReflectionMethod($cms, 'init'); + $initReflection->setAccessible(true); + if ($throwsException) { + $this->expectException(LogicException::class); + } else { + $this->expectNotToPerformAssertions(); + } + $initReflection->invoke($cms); } } diff --git a/tests/php/Controllers/CMSMainTest/TestHierarchicalDataObject.php b/tests/php/Controllers/CMSMainTest/TestHierarchicalDataObject.php new file mode 100644 index 0000000000..78ea216b6f --- /dev/null +++ b/tests/php/Controllers/CMSMainTest/TestHierarchicalDataObject.php @@ -0,0 +1,18 @@ + 'Int', + ]; + + private static array $extensions = [ + Hierarchy::class, + ]; +} diff --git a/tests/php/Controllers/CMSMainTest/TestHierarchicalDataObjectWithSort.php b/tests/php/Controllers/CMSMainTest/TestHierarchicalDataObjectWithSort.php new file mode 100644 index 0000000000..bc380c5545 --- /dev/null +++ b/tests/php/Controllers/CMSMainTest/TestHierarchicalDataObjectWithSort.php @@ -0,0 +1,20 @@ + 'Int', + ]; + + private static string $sort_field = 'Sort'; + + private static array $extensions = [ + Hierarchy::class, + ]; +} diff --git a/tests/php/Controllers/CMSSiteTreeFilterTest.php b/tests/php/Controllers/CMSSiteTreeFilterTest.php index bf2a925323..9eefb1ce1e 100644 --- a/tests/php/Controllers/CMSSiteTreeFilterTest.php +++ b/tests/php/Controllers/CMSSiteTreeFilterTest.php @@ -24,8 +24,8 @@ public function testSearchFilterEmpty() $f = new CMSSiteTreeFilter_Search(); $results = $f->pagesIncluded(); - $this->assertTrue($f->isPageIncluded($page1)); - $this->assertTrue($f->isPageIncluded($page2)); + $this->assertTrue($f->isRecordIncluded($page1)); + $this->assertTrue($f->isRecordIncluded($page2)); } public function testSearchFilterByTitle() @@ -36,8 +36,8 @@ public function testSearchFilterByTitle() $f = new CMSSiteTreeFilter_Search(['Title' => 'Page 1']); $results = $f->pagesIncluded(); - $this->assertTrue($f->isPageIncluded($page1)); - $this->assertFalse($f->isPageIncluded($page2)); + $this->assertTrue($f->isRecordIncluded($page1)); + $this->assertFalse($f->isRecordIncluded($page2)); $this->assertEquals(1, count($results ?? [])); $this->assertEquals( ['ID' => $page1->ID, 'ParentID' => 0], @@ -50,10 +50,10 @@ public function testUrlSegmentFilter() $page = $this->objFromFixture(SiteTree::class, 'page8'); $filter = CMSSiteTreeFilter_Search::create(['Term' => 'lake-wanaka+adventure']); - $this->assertTrue($filter->isPageIncluded($page)); + $this->assertTrue($filter->isRecordIncluded($page)); $filter = CMSSiteTreeFilter_Search::create(['URLSegment' => 'lake-wanaka+adventure']); - $this->assertTrue($filter->isPageIncluded($page)); + $this->assertTrue($filter->isRecordIncluded($page)); } public function testIncludesParentsForNestedMatches() @@ -64,8 +64,8 @@ public function testIncludesParentsForNestedMatches() $f = new CMSSiteTreeFilter_Search(['Title' => 'Page 3b']); $results = $f->pagesIncluded(); - $this->assertTrue($f->isPageIncluded($parent)); - $this->assertTrue($f->isPageIncluded($child)); + $this->assertTrue($f->isRecordIncluded($parent)); + $this->assertTrue($f->isRecordIncluded($child)); $this->assertEquals(1, count($results ?? [])); $this->assertEquals( ['ID' => $child->ID, 'ParentID' => $parent->ID], @@ -91,8 +91,8 @@ public function testChangedPagesFilter() $f = new CMSSiteTreeFilter_ChangedPages(['Term' => 'Changed']); $results = $f->pagesIncluded(); - $this->assertTrue($f->isPageIncluded($changedPage)); - $this->assertFalse($f->isPageIncluded($unchangedPage)); + $this->assertTrue($f->isRecordIncluded($changedPage)); + $this->assertFalse($f->isRecordIncluded($unchangedPage)); $this->assertEquals(1, count($results ?? [])); $this->assertEquals( ['ID' => $changedPage->ID, 'ParentID' => 0], @@ -130,11 +130,11 @@ public function testDeletedPagesFilter() ); $f = new CMSSiteTreeFilter_DeletedPages(['Term' => 'Page']); - $this->assertTrue($f->isPageIncluded($deletedPage)); + $this->assertTrue($f->isRecordIncluded($deletedPage)); // Check that only changed pages are returned $f = new CMSSiteTreeFilter_DeletedPages(['Term' => 'No Matches']); - $this->assertFalse($f->isPageIncluded($deletedPage)); + $this->assertFalse($f->isRecordIncluded($deletedPage)); } public function testStatusDraftPagesFilter() @@ -148,16 +148,16 @@ public function testStatusDraftPagesFilter() // Check draft page is shown $f = new CMSSiteTreeFilter_StatusDraftPages(['Term' => 'Page']); - $this->assertTrue($f->isPageIncluded($draftPage)); + $this->assertTrue($f->isRecordIncluded($draftPage)); // Check filter respects parameters $f = new CMSSiteTreeFilter_StatusDraftPages(['Term' => 'No Match']); - $this->assertEmpty($f->isPageIncluded($draftPage)); + $this->assertEmpty($f->isRecordIncluded($draftPage)); // Ensures empty array returned if no data to show $f = new CMSSiteTreeFilter_StatusDraftPages(); $draftPage->delete(); - $this->assertEmpty($f->isPageIncluded($draftPage)); + $this->assertEmpty($f->isRecordIncluded($draftPage)); } public function testDateFromToLastSameDate() @@ -171,7 +171,7 @@ public function testDateFromToLastSameDate() 'LastEditedTo' => $date, ]); $this->assertTrue( - $filter->isPageIncluded($draftPage), + $filter->isRecordIncluded($draftPage), 'Using the same date for from and to should show find that page' ); } @@ -189,16 +189,16 @@ public function testStatusRemovedFromDraftFilter() // Check live-only page is included $f = new CMSSiteTreeFilter_StatusRemovedFromDraftPages(['LastEditedFrom' => '2000-01-01 00:00']); - $this->assertTrue($f->isPageIncluded($removedDraftPage)); + $this->assertTrue($f->isRecordIncluded($removedDraftPage)); // Check filter is respected $f = new CMSSiteTreeFilter_StatusRemovedFromDraftPages(['LastEditedTo' => '1999-01-01 00:00']); - $this->assertEmpty($f->isPageIncluded($removedDraftPage)); + $this->assertEmpty($f->isRecordIncluded($removedDraftPage)); // Ensures empty array returned if no data to show $f = new CMSSiteTreeFilter_StatusRemovedFromDraftPages(); $removedDraftPage->delete(); - $this->assertEmpty($f->isPageIncluded($removedDraftPage)); + $this->assertEmpty($f->isRecordIncluded($removedDraftPage)); } public function testStatusDeletedFilter() @@ -214,10 +214,10 @@ public function testStatusDeletedFilter() // Check deleted page is included $f = new CMSSiteTreeFilter_StatusDeletedPages(['Title' => 'Page']); - $this->assertTrue($f->isPageIncluded($checkParentExists)); + $this->assertTrue($f->isRecordIncluded($checkParentExists)); // Check filter is respected $f = new CMSSiteTreeFilter_StatusDeletedPages(['Title' => 'Bobby']); - $this->assertFalse($f->isPageIncluded($checkParentExists)); + $this->assertFalse($f->isRecordIncluded($checkParentExists)); } } diff --git a/tests/php/Controllers/LeftAndMainPageIconsExtensionTest.php b/tests/php/Controllers/LeftAndMainPageIconsExtensionTest.php deleted file mode 100644 index 4529a826d7..0000000000 --- a/tests/php/Controllers/LeftAndMainPageIconsExtensionTest.php +++ /dev/null @@ -1,30 +0,0 @@ -generatePageIconsCss(); - $this->assertStringNotContainsString('some invalid string', $css); - $this->assertStringContainsString( - 'tests/php/Controllers/LeftAndMainPageIconsExtensionTest/icon_b.jpg?m=', - $css - ); - $this->assertStringContainsString( - 'tests/php/Controllers/LeftAndMainPageIconsExtensionTest/icon_c.jpg?m=', - $css - ); - } -} diff --git a/tests/php/Controllers/LeftAndMainPageIconsExtensionTest/ModuleIconB.php b/tests/php/Controllers/LeftAndMainPageIconsExtensionTest/ModuleIconB.php deleted file mode 100644 index 147a044ea0..0000000000 --- a/tests/php/Controllers/LeftAndMainPageIconsExtensionTest/ModuleIconB.php +++ /dev/null @@ -1,11 +0,0 @@ -generateRecordIconsCss(); + $this->assertStringNotContainsString('some invalid string', $css); + $this->assertStringContainsString( + 'tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_b.jpg?m=', + $css + ); + $this->assertStringContainsString( + 'tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_c.jpg?m=', + $css + ); + $this->assertStringNotContainsString( + 'tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_d.jpg?m=', + $css + ); + } +} diff --git a/tests/php/Controllers/LeftAndMainPageIconsExtensionTest/ModuleIconA.php b/tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/ModuleIconA.php similarity index 50% rename from tests/php/Controllers/LeftAndMainPageIconsExtensionTest/ModuleIconA.php rename to tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/ModuleIconA.php index 3b503a34bf..5c1d907104 100644 --- a/tests/php/Controllers/LeftAndMainPageIconsExtensionTest/ModuleIconA.php +++ b/tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/ModuleIconA.php @@ -1,11 +1,11 @@ $path, + 'cms_icon' => $path, ]; } } diff --git a/tests/php/Controllers/LeftAndMainPageIconsExtensionTest/icon_b.jpg b/tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_b.jpg similarity index 100% rename from tests/php/Controllers/LeftAndMainPageIconsExtensionTest/icon_b.jpg rename to tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_b.jpg diff --git a/tests/php/Controllers/LeftAndMainPageIconsExtensionTest/icon_c.jpg b/tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_c.jpg similarity index 100% rename from tests/php/Controllers/LeftAndMainPageIconsExtensionTest/icon_c.jpg rename to tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_c.jpg diff --git a/tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_d.jpg b/tests/php/Controllers/LeftAndMainRecordIconsExtensionTest/icon_d.jpg new file mode 100644 index 0000000000000000000000000000000000000000..beb5a91b0aba93d3b54dadc12cff0104307d718e GIT binary patch literal 2292 zcmbV~c|6qJ9>;%UHjExS$z>*csbTDTlq4fO5~U_1OJm>1u4{=xiK_^q9w8LDu4RZU z8557($~v-CGowgKGnQ!>GxN;U>viux_m6w;=e)k(*IB;jygu)9j^K@e2FN&K9k2ih z1OOmm0|b2FS6eqbn=>wMhfslj2ScL#15xo9v>{3_E+#l45ar-#k8(U^XOD_EGun3m zMU3+e3yw`f9Y$H2N($xxTR;pXk|>Lb1ObaO6aoQ5U{DzBN5Cb-VQ>jJ3?_~cmyi@m z*pos?N{I%dLw;@*gMz_ONjMDtqvU@|f@grNIA8=Afk7I8m@Eh^3ldNOq!1GN!=8}z zr$Az02owev+CT^kNHRkEV6f0MROnb(og!QZAhJ-oy%-yqysIxV&@@|zq+B&*=`}UidnweWz9W@cqyyPi`}c)O^$RrQ0K+Pa62>RVddNbMa@I=jdNl;?v( ze+<7EpO~DYPQRI%r85>jd|X`mwEUU1w!X2+{?6Ij7IA?9@J}pZ{*PR;LM}1U8^A?e zAh85tfMp@jy%?CBjVs)jD6e6ZF0OFwR%LU)gr>0@Q}JT-n52@H30<2dLi<7X-+^WP zUu6FR`#0AtAO!{q9}g@GSOYtk7S!~}8_$uB+tPfA6|UScm#}l9_X_1u&tL^TQrcdj z>+Q>0tL3s|#Fe0ldmx9gHPI4kJ)~!b1g|z(yjN8XLXuJS` zbkD^*z5G3tsmzY%^l%+H!&dUleDZ1USK^@~9a{$<->ldybWF6F1{a6<+N$d#8AAgp zF*E@{=}DkRUa!e;;(^bU4KCsXbS(Fn>-RVSUwuF-0BsG#=yT*B;m`NAB6s9h`d>5U z*+I!zwFZ}WM9j}@ilS9JY$m9{% zsipE$tY6wzt5%oilB;$vxZ$B)^iwIL(cE|@3X!9 zbDTr53I6Tz7Vf2L?$z^&yIy=qePSj`q;Sh*>J)8~lG@3xHx8B!&?D3*4f z(16K+;)d7>XX`?zlMS|;WkY<4M_lzC8P1ia)Nya69S5E28twV6Tr)4-C%HIWYv;`p zTFU*5sQNAVW%oH)uPc)2`u@gP@{ucS0`FF`%&cKK#iMe(X=8+7xbU!S*y$YfG} zd!*;~%s9DPl~}k|wAj%YqC~`n?CF_g;&br>rUQqLThBn~X_7ouUO~4nSB>9a(PEyR zYQ=fM82>hyYA~Vx>0tfi*&?c+Ki5RkW%Z(S<%R3+=sK-?4c_)yg9C<->6uQuAmw+P z;wM73KYb_lJxGnY^I^(JN-JdXWKvPmD@={^;Mhq_QF-2Mi*u)0MeW*Q7fLY8e88IN z^iAG|>;KtsJ~5jw^VZJ5gK<0w(h{lU`qbdX1UyJtlhZtGsk?^cL-gmUr7TrLk#9c^FourW>LL;vTauCJy%?{X4MKQ47hT0+*~|arf=qg$=ZZpIf=5s9ayg_A#PN4J0T-0M|ZS11V(s}GqPVIYIU|8(Oode6acclYO}%9{6kE$M-OZo=C-yyXY&dv9s5YCdN`?_7VMjq_Tz_D9N2jX zzNGAes%lE4CzY=jq&&-;{#(iOONt{y(Z$;lRgq|eJwDf?YF;?+-#s=ml&N7?n6uuL zpVn4EF_<;__FFG&W&dz3x&Q30liRolrQ=!!#9c2b&2z2S2nX6%6as@lfIEU1*V(9j zzpO4?`p6JhBgZU%O|S6;>{IIPs}&x4_u)R5T+^5B6oBju%(2V%8aaBvvke7TJ0MLk F^Cu<`6}$id literal 0 HcmV?d00001 diff --git a/tests/php/Model/SiteTreePermissionsTest.php b/tests/php/Model/SiteTreePermissionsTest.php index ad7c17850c..02a8df272b 100644 --- a/tests/php/Model/SiteTreePermissionsTest.php +++ b/tests/php/Model/SiteTreePermissionsTest.php @@ -96,7 +96,7 @@ public function testPermissionCheckingWorksOnDeletedPages() // Test can_edit_multiple $this->assertEquals( [ $pageID => true ], - SiteTree::getPermissionChecker()->canEditMultiple([$pageID], $member) + $page->getPermissionChecker()->canEditMultiple([$pageID], $member) ); // Test canEdit @@ -119,7 +119,7 @@ public function testPermissionCheckingWorksOnUnpublishedPages() // Test can_edit_multiple $this->assertEquals( [ $pageID => true ], - SiteTree::getPermissionChecker()->canEditMultiple([$pageID], $member) + $page->getPermissionChecker()->canEditMultiple([$pageID], $member) ); // Test canEdit diff --git a/tests/php/Model/SiteTreeTest.php b/tests/php/Model/SiteTreeTest.php index 1de289eee4..2e5c894e5b 100644 --- a/tests/php/Model/SiteTreeTest.php +++ b/tests/php/Model/SiteTreeTest.php @@ -43,6 +43,7 @@ use const RESOURCES_DIR; use PHPUnit\Framework\Attributes\DataProvider; +use SilverStripe\Core\ClassInfo; class SiteTreeTest extends SapphireTest { @@ -64,7 +65,6 @@ class SiteTreeTest extends SapphireTest SiteTreeTest_ClassC::class, SiteTreeTest_ClassD::class, SiteTreeTest_NotRoot::class, - SiteTreeTest_StageStatusInherit::class, SiteTreeTest_DataObject::class, PageWithChild::class, BelongsToPage::class, @@ -445,7 +445,7 @@ public function testRestoreToStage() public function testNoCascadingDeleteWithoutID() { - Config::inst()->set('SiteTree', 'enforce_strict_hierarchy', true); + SiteTree::config()->set('enforce_strict_hierarchy', true); $count = SiteTree::get()->count(); $this->assertNotEmpty($count); $obj = new SiteTree(); @@ -806,7 +806,7 @@ public function testEditPermissionsOnDraftVsLive() // Clear permission cache /** @var InheritedPermissions $checker */ - $checker = SiteTree::getPermissionChecker(); + $checker = SiteTree::singleton()->getPermissionChecker(); $checker->clearCache(); // Confirm that Member.editor can now edit the page @@ -1182,19 +1182,22 @@ public function testVersionsAreCreated() public function testHidePagetypes() { SiteTree::config()->set('hide_pagetypes', ['Page']); - $classes = SiteTree::page_type_classes(); + $classes = ClassInfo::getValidSubClasses(SiteTree::class); + SiteTree::singleton()->updateAllowedSubClasses($classes); $this->assertNotContains('Page', $classes); } public function testPageTypeClasses() { - $classes = SiteTree::page_type_classes(); + $classes = ClassInfo::getValidSubClasses(SiteTree::class); + SiteTree::singleton()->updateAllowedSubClasses($classes); $this->assertNotContains(SiteTree::class, $classes, 'Page types do not include base class'); $this->assertContains('Page', $classes, 'Page types do contain subclasses'); // Testing what happens in an incorrect config value is set - hide_ancestor should be a string Config::modify()->set(SiteTreeTest_ClassA::class, 'hide_ancestor', true); - $newClasses = SiteTree::page_type_classes(); + $newClasses = ClassInfo::getValidSubClasses(SiteTree::class); + SiteTree::singleton()->updateAllowedSubClasses($newClasses); $this->assertEquals( $classes, $newClasses, @@ -1203,7 +1206,8 @@ public function testPageTypeClasses() // Testing what happens if a valid config value is set Config::modify()->set(SiteTreeTest_ClassA::class, 'hide_ancestor', 'Page'); - $classes = SiteTree::page_type_classes(); + $classes = ClassInfo::getValidSubClasses(SiteTree::class); + SiteTree::singleton()->updateAllowedSubClasses($classes); $this->assertNotContains('Page', $classes); } @@ -1289,14 +1293,6 @@ public function testCanBeRoot() } } - public function testModifyStatusFlagByInheritance() - { - $node = new SiteTreeTest_StageStatusInherit(); - $treeTitle = $node->getTreeTitle(); - $this->assertStringContainsString('InheritedTitle', $treeTitle); - $this->assertStringContainsString('inherited-class', $treeTitle); - } - public function testMenuTitleIsUnsetWhenEqualsTitle() { $page = new SiteTree(); @@ -1622,7 +1618,7 @@ public function testGetControllerName() */ public function testGetControllerNameFromConfig() { - Config::inst()->set(SiteTree::class, 'controller_name', 'This\\Is\\A\\New\\Controller'); + SiteTree::config()->set('controller_name', 'This\\Is\\A\\New\\Controller'); $page = new SiteTree(); $this->assertSame('This\\Is\\A\\New\\Controller', $page->getControllerName()); } @@ -1632,7 +1628,7 @@ public function testGetControllerNameFromConfig() */ public function testGetControllerNameFromNamespaceMappingConfig() { - Config::inst()->merge(SiteTree::class, 'namespace_mapping', [ + SiteTree::config()->merge('namespace_mapping', [ 'SilverStripe\\CMS\\Tests\\Page' => 'SilverStripe\\CMS\\Tests\\Controllers', ]); @@ -1640,58 +1636,6 @@ public function testGetControllerNameFromNamespaceMappingConfig() $this->assertSame(SiteTreeTest_NamespaceMapTestNodeController::class, $namespacedSiteTree->getControllerName()); } - public function testTreeTitleCache() - { - $siteTree = new SiteTree(); - $user = $this->objFromFixture(Member::class, 'allsections'); - Security::setCurrentUser($user); - $pageClass = array_values(SiteTree::page_type_classes())[0]; - - $mockPageMissesCache = $this->getMockBuilder($pageClass) - ->onlyMethods(['canCreate']) - ->getMock(); - $mockPageMissesCache - ->expects($this->exactly(3)) - ->method('canCreate'); - - $mockPageHitsCache = $this->getMockBuilder($pageClass) - ->onlyMethods(['canCreate']) - ->getMock(); - $mockPageHitsCache - ->expects($this->never()) - ->method('canCreate'); - - // Initially, cache misses (1) - Injector::inst()->registerService($mockPageMissesCache, $pageClass); - $title = $siteTree->getTreeTitle(); - $this->assertNotNull($title); - - // Now it hits - Injector::inst()->registerService($mockPageHitsCache, $pageClass); - $title = $siteTree->getTreeTitle(); - $this->assertNotNull($title); - - - // Mutating member record invalidates cache. Misses (2) - $user->FirstName = 'changed'; - $user->write(); - Injector::inst()->registerService($mockPageMissesCache, $pageClass); - $title = $siteTree->getTreeTitle(); - $this->assertNotNull($title); - - // Now it hits again - Injector::inst()->registerService($mockPageHitsCache, $pageClass); - $title = $siteTree->getTreeTitle(); - $this->assertNotNull($title); - - // Different user. Misses. (3) - $user = $this->objFromFixture(Member::class, 'editor'); - Security::setCurrentUser($user); - Injector::inst()->registerService($mockPageMissesCache, $pageClass); - $title = $siteTree->getTreeTitle(); - $this->assertNotNull($title); - } - public function testDependentPagesOnUnsavedRecord() { $record = new SiteTree(); diff --git a/tests/php/Model/SiteTreeTest_ClassA.php b/tests/php/Model/SiteTreeTest_ClassA.php index 7cf2020f4d..bf878c9676 100644 --- a/tests/php/Model/SiteTreeTest_ClassA.php +++ b/tests/php/Model/SiteTreeTest_ClassA.php @@ -9,11 +9,6 @@ class SiteTreeTest_ClassA extends SiteTree implements TestOnly { private static $table_name = 'SiteTreeTest_ClassA'; - private static $need_permission = [ - 'ADMIN', - 'CMS_ACCESS_CMSMain', - ]; - private static $allowed_children = [ SiteTreeTest_ClassB::class, ]; diff --git a/tests/php/Model/SiteTreeTest_StageStatusInherit.php b/tests/php/Model/SiteTreeTest_StageStatusInherit.php deleted file mode 100644 index 690c748629..0000000000 --- a/tests/php/Model/SiteTreeTest_StageStatusInherit.php +++ /dev/null @@ -1,18 +0,0 @@ -