Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like SiteTree often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SiteTree, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
36 | class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvider,CMSPreviewable { |
||
37 | |||
38 | /** |
||
39 | * Indicates what kind of children this page type can have. |
||
40 | * This can be an array of allowed child classes, or the string "none" - |
||
41 | * indicating that this page type can't have children. |
||
42 | * If a classname is prefixed by "*", such as "*Page", then only that |
||
43 | * class is allowed - no subclasses. Otherwise, the class and all its |
||
44 | * subclasses are allowed. |
||
45 | * To control allowed children on root level (no parent), use {@link $can_be_root}. |
||
46 | * |
||
47 | * Note that this setting is cached when used in the CMS, use the "flush" query parameter to clear it. |
||
48 | * |
||
49 | * @config |
||
50 | * @var array |
||
51 | */ |
||
52 | private static $allowed_children = array("SiteTree"); |
||
53 | |||
54 | /** |
||
55 | * The default child class for this page. |
||
56 | * Note: Value might be cached, see {@link $allowed_chilren}. |
||
57 | * |
||
58 | * @config |
||
59 | * @var string |
||
60 | */ |
||
61 | private static $default_child = "Page"; |
||
62 | |||
63 | /** |
||
64 | * Default value for SiteTree.ClassName enum |
||
65 | * {@see DBClassName::getDefault} |
||
66 | * |
||
67 | * @config |
||
68 | * @var string |
||
69 | */ |
||
70 | private static $default_classname = "Page"; |
||
71 | |||
72 | /** |
||
73 | * The default parent class for this page. |
||
74 | * Note: Value might be cached, see {@link $allowed_chilren}. |
||
75 | * |
||
76 | * @config |
||
77 | * @var string |
||
78 | */ |
||
79 | private static $default_parent = null; |
||
80 | |||
81 | /** |
||
82 | * Controls whether a page can be in the root of the site tree. |
||
83 | * Note: Value might be cached, see {@link $allowed_chilren}. |
||
84 | * |
||
85 | * @config |
||
86 | * @var bool |
||
87 | */ |
||
88 | private static $can_be_root = true; |
||
89 | |||
90 | /** |
||
91 | * List of permission codes a user can have to allow a user to create a page of this type. |
||
92 | * Note: Value might be cached, see {@link $allowed_chilren}. |
||
93 | * |
||
94 | * @config |
||
95 | * @var array |
||
96 | */ |
||
97 | private static $need_permission = null; |
||
98 | |||
99 | /** |
||
100 | * If you extend a class, and don't want to be able to select the old class |
||
101 | * in the cms, set this to the old class name. Eg, if you extended Product |
||
102 | * to make ImprovedProduct, then you would set $hide_ancestor to Product. |
||
103 | * |
||
104 | * @config |
||
105 | * @var string |
||
106 | */ |
||
107 | private static $hide_ancestor = null; |
||
108 | |||
109 | private static $db = array( |
||
110 | "URLSegment" => "Varchar(255)", |
||
111 | "Title" => "Varchar(255)", |
||
112 | "MenuTitle" => "Varchar(100)", |
||
113 | "Content" => "HTMLText", |
||
114 | "MetaDescription" => "Text", |
||
115 | "ExtraMeta" => "HTMLText('meta, link')", |
||
116 | "ShowInMenus" => "Boolean", |
||
117 | "ShowInSearch" => "Boolean", |
||
118 | "Sort" => "Int", |
||
119 | "HasBrokenFile" => "Boolean", |
||
120 | "HasBrokenLink" => "Boolean", |
||
121 | "ReportClass" => "Varchar", |
||
122 | "CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers, Inherit', 'Inherit')", |
||
123 | "CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers, Inherit', 'Inherit')", |
||
124 | ); |
||
125 | |||
126 | private static $indexes = array( |
||
127 | "URLSegment" => true, |
||
128 | ); |
||
129 | |||
130 | private static $many_many = array( |
||
131 | "ViewerGroups" => "Group", |
||
132 | "EditorGroups" => "Group", |
||
133 | ); |
||
134 | |||
135 | private static $has_many = array( |
||
136 | "VirtualPages" => "VirtualPage.CopyContentFrom" |
||
137 | ); |
||
138 | |||
139 | private static $owned_by = array( |
||
140 | "VirtualPages" |
||
141 | ); |
||
142 | |||
143 | private static $casting = array( |
||
144 | "Breadcrumbs" => "HTMLText", |
||
145 | "LastEdited" => "SS_Datetime", |
||
146 | "Created" => "SS_Datetime", |
||
147 | 'Link' => 'Text', |
||
148 | 'RelativeLink' => 'Text', |
||
149 | 'AbsoluteLink' => 'Text', |
||
150 | 'TreeTitle' => 'HTMLText', |
||
151 | ); |
||
152 | |||
153 | private static $defaults = array( |
||
154 | "ShowInMenus" => 1, |
||
155 | "ShowInSearch" => 1, |
||
156 | "CanViewType" => "Inherit", |
||
157 | "CanEditType" => "Inherit" |
||
158 | ); |
||
159 | |||
160 | private static $versioning = array( |
||
161 | "Stage", "Live" |
||
162 | ); |
||
163 | |||
164 | private static $default_sort = "\"Sort\""; |
||
165 | |||
166 | /** |
||
167 | * If this is false, the class cannot be created in the CMS by regular content authors, only by ADMINs. |
||
168 | * @var boolean |
||
169 | * @config |
||
170 | */ |
||
171 | private static $can_create = true; |
||
172 | |||
173 | /** |
||
174 | * Icon to use in the CMS page tree. This should be the full filename, relative to the webroot. |
||
175 | * Also supports custom CSS rule contents (applied to the correct selector for the tree UI implementation). |
||
176 | * |
||
177 | * @see CMSMain::generateTreeStylingCSS() |
||
178 | * @config |
||
179 | * @var string |
||
180 | */ |
||
181 | private static $icon = null; |
||
182 | |||
183 | /** |
||
184 | * @config |
||
185 | * @var string Description of the class functionality, typically shown to a user |
||
186 | * when selecting which page type to create. Translated through {@link provideI18nEntities()}. |
||
187 | */ |
||
188 | private static $description = 'Generic content page'; |
||
189 | |||
190 | private static $extensions = array( |
||
191 | "Hierarchy", |
||
192 | "Versioned", |
||
193 | "SiteTreeLinkTracking" |
||
194 | ); |
||
195 | |||
196 | private static $searchable_fields = array( |
||
197 | 'Title', |
||
198 | 'Content', |
||
199 | ); |
||
200 | |||
201 | private static $field_labels = array( |
||
202 | 'URLSegment' => 'URL' |
||
203 | ); |
||
204 | |||
205 | /** |
||
206 | * @config |
||
207 | */ |
||
208 | private static $nested_urls = true; |
||
209 | |||
210 | /** |
||
211 | * @config |
||
212 | */ |
||
213 | private static $create_default_pages = true; |
||
214 | |||
215 | /** |
||
216 | * This controls whether of not extendCMSFields() is called by getCMSFields. |
||
217 | */ |
||
218 | private static $runCMSFieldsExtensions = true; |
||
219 | |||
220 | /** |
||
221 | * Cache for canView/Edit/Publish/Delete permissions. |
||
222 | * Keyed by permission type (e.g. 'edit'), with an array |
||
223 | * of IDs mapped to their boolean permission ability (true=allow, false=deny). |
||
224 | * See {@link batch_permission_check()} for details. |
||
225 | */ |
||
226 | private static $cache_permissions = array(); |
||
227 | |||
228 | /** |
||
229 | * @config |
||
230 | * @var boolean |
||
231 | */ |
||
232 | private static $enforce_strict_hierarchy = true; |
||
233 | |||
234 | /** |
||
235 | * The value used for the meta generator tag. Leave blank to omit the tag. |
||
236 | * |
||
237 | * @config |
||
238 | * @var string |
||
239 | */ |
||
240 | private static $meta_generator = 'SilverStripe - http://silverstripe.org'; |
||
241 | |||
242 | protected $_cache_statusFlags = null; |
||
243 | |||
244 | /** |
||
245 | * Fetches the {@link SiteTree} object that maps to a link. |
||
246 | * |
||
247 | * If you have enabled {@link SiteTree::config()->nested_urls} on this site, then you can use a nested link such as |
||
248 | * "about-us/staff/", and this function will traverse down the URL chain and grab the appropriate link. |
||
249 | * |
||
250 | * Note that if no model can be found, this method will fall over to a extended alternateGetByLink method provided |
||
251 | * by a extension attached to {@link SiteTree} |
||
252 | * |
||
253 | * @param string $link The link of the page to search for |
||
254 | * @param bool $cache True (default) to use caching, false to force a fresh search from the database |
||
255 | * @return SiteTree |
||
256 | */ |
||
257 | static public function get_by_link($link, $cache = true) { |
||
323 | |||
324 | /** |
||
325 | * Return a subclass map of SiteTree that shouldn't be hidden through {@link SiteTree::$hide_ancestor} |
||
326 | * |
||
327 | * @return array |
||
328 | */ |
||
329 | public static function page_type_classes() { |
||
363 | |||
364 | /** |
||
365 | * Replace a "[sitetree_link id=n]" shortcode with a link to the page with the corresponding ID. |
||
366 | * |
||
367 | * @param array $arguments |
||
368 | * @param string $content |
||
369 | * @param TextParser $parser |
||
370 | * @return string |
||
371 | */ |
||
372 | static public function link_shortcode_handler($arguments, $content = null, $parser = null) { |
||
390 | |||
391 | /** |
||
392 | * Return the link for this {@link SiteTree} object, with the {@link Director::baseURL()} included. |
||
393 | * |
||
394 | * @param string $action Optional controller action (method). |
||
395 | * Note: URI encoding of this parameter is applied automatically through template casting, |
||
396 | * don't encode the passed parameter. Please use {@link Controller::join_links()} instead to |
||
397 | * append GET parameters. |
||
398 | * @return string |
||
399 | */ |
||
400 | public function Link($action = null) { |
||
403 | |||
404 | /** |
||
405 | * Get the absolute URL for this page, including protocol and host. |
||
406 | * |
||
407 | * @param string $action See {@link Link()} |
||
408 | * @return string |
||
409 | */ |
||
410 | public function AbsoluteLink($action = null) { |
||
417 | |||
418 | /** |
||
419 | * Base link used for previewing. Defaults to absolute URL, in order to account for domain changes, e.g. on multi |
||
420 | * site setups. Does not contain hints about the stage, see {@link SilverStripeNavigator} for details. |
||
421 | * |
||
422 | * @param string $action See {@link Link()} |
||
423 | * @return string |
||
424 | */ |
||
425 | public function PreviewLink($action = null) { |
||
432 | |||
433 | /** |
||
434 | * Return the link for this {@link SiteTree} object relative to the SilverStripe root. |
||
435 | * |
||
436 | * By default, if this page is the current home page, and there is no action specified then this will return a link |
||
437 | * to the root of the site. However, if you set the $action parameter to TRUE then the link will not be rewritten |
||
438 | * and returned in its full form. |
||
439 | * |
||
440 | * @uses RootURLController::get_homepage_link() |
||
441 | * |
||
442 | * @param string $action See {@link Link()} |
||
443 | * @return string |
||
444 | */ |
||
445 | public function RelativeLink($action = null) { |
||
470 | |||
471 | /** |
||
472 | * Get the absolute URL for this page on the Live site. |
||
473 | * |
||
474 | * @param bool $includeStageEqualsLive Whether to append the URL with ?stage=Live to force Live mode |
||
475 | * @return string |
||
476 | */ |
||
477 | public function getAbsoluteLiveLink($includeStageEqualsLive = true) { |
||
493 | |||
494 | /** |
||
495 | * Generates a link to edit this page in the CMS. |
||
496 | * |
||
497 | * @return string |
||
498 | */ |
||
499 | public function CMSEditLink() { |
||
502 | |||
503 | |||
504 | /** |
||
505 | * Return a CSS identifier generated from this page's link. |
||
506 | * |
||
507 | * @return string The URL segment |
||
508 | */ |
||
509 | public function ElementName() { |
||
512 | |||
513 | /** |
||
514 | * Returns true if this is the currently active page being used to handle this request. |
||
515 | * |
||
516 | * @return bool |
||
517 | */ |
||
518 | public function isCurrent() { |
||
521 | |||
522 | /** |
||
523 | * Check if this page is in the currently active section (e.g. it is either current or one of its children is |
||
524 | * currently being viewed). |
||
525 | * |
||
526 | * @return bool |
||
527 | */ |
||
528 | public function isSection() { |
||
533 | |||
534 | /** |
||
535 | * Check if the parent of this page has been removed (or made otherwise unavailable), and is still referenced by |
||
536 | * this child. Any such orphaned page may still require access via the CMS, but should not be shown as accessible |
||
537 | * to external users. |
||
538 | * |
||
539 | * @return bool |
||
540 | */ |
||
541 | public function isOrphaned() { |
||
549 | |||
550 | /** |
||
551 | * Return "link" or "current" depending on if this is the {@link SiteTree::isCurrent()} current page. |
||
552 | * |
||
553 | * @return string |
||
554 | */ |
||
555 | public function LinkOrCurrent() { |
||
558 | |||
559 | /** |
||
560 | * Return "link" or "section" depending on if this is the {@link SiteTree::isSeciton()} current section. |
||
561 | * |
||
562 | * @return string |
||
563 | */ |
||
564 | public function LinkOrSection() { |
||
567 | |||
568 | /** |
||
569 | * Return "link", "current" or "section" depending on if this page is the current page, or not on the current page |
||
570 | * but in the current section. |
||
571 | * |
||
572 | * @return string |
||
573 | */ |
||
574 | public function LinkingMode() { |
||
583 | |||
584 | /** |
||
585 | * Check if this page is in the given current section. |
||
586 | * |
||
587 | * @param string $sectionName Name of the section to check |
||
588 | * @return bool True if we are in the given section |
||
589 | */ |
||
590 | public function InSection($sectionName) { |
||
599 | |||
600 | /** |
||
601 | * Create a duplicate of this node. Doesn't affect joined data - create a custom overloading of this if you need |
||
602 | * such behaviour. |
||
603 | * |
||
604 | * @param bool $doWrite Whether to write the new object before returning it |
||
605 | * @return self The duplicated object |
||
606 | */ |
||
607 | public function duplicate($doWrite = true) { |
||
622 | |||
623 | /** |
||
624 | * Duplicates each child of this node recursively and returns the top-level duplicate node. |
||
625 | * |
||
626 | * @return self The duplicated object |
||
627 | */ |
||
628 | public function duplicateWithChildren() { |
||
644 | |||
645 | /** |
||
646 | * Duplicate this node and its children as a child of the node with the given ID |
||
647 | * |
||
648 | * @param int $id ID of the new node's new parent |
||
649 | */ |
||
650 | public function duplicateAsChild($id) { |
||
656 | |||
657 | /** |
||
658 | * Return a breadcrumb trail to this page. Excludes "hidden" pages (with ShowInMenus=0) by default. |
||
659 | * |
||
660 | * @param int $maxDepth The maximum depth to traverse. |
||
661 | * @param boolean $unlinked Whether to link page titles. |
||
662 | * @param boolean|string $stopAtPageType ClassName of a page to stop the upwards traversal. |
||
663 | * @param boolean $showHidden Include pages marked with the attribute ShowInMenus = 0 |
||
664 | * @return HTMLText The breadcrumb trail. |
||
665 | */ |
||
666 | public function Breadcrumbs($maxDepth = 20, $unlinked = false, $stopAtPageType = false, $showHidden = false) { |
||
674 | |||
675 | |||
676 | /** |
||
677 | * Returns a list of breadcrumbs for the current page. |
||
678 | * |
||
679 | * @param int $maxDepth The maximum depth to traverse. |
||
680 | * @param boolean|string $stopAtPageType ClassName of a page to stop the upwards traversal. |
||
681 | * @param boolean $showHidden Include pages marked with the attribute ShowInMenus = 0 |
||
682 | * |
||
683 | * @return ArrayList |
||
684 | */ |
||
685 | public function getBreadcrumbItems($maxDepth = 20, $stopAtPageType = false, $showHidden = false) { |
||
703 | |||
704 | |||
705 | /** |
||
706 | * Make this page a child of another page. |
||
707 | * |
||
708 | * If the parent page does not exist, resolve it to a valid ID before updating this page's reference. |
||
709 | * |
||
710 | * @param SiteTree|int $item Either the parent object, or the parent ID |
||
711 | */ |
||
712 | public function setParent($item) { |
||
720 | |||
721 | /** |
||
722 | * Get the parent of this page. |
||
723 | * |
||
724 | * @return SiteTree Parent of this page |
||
725 | */ |
||
726 | public function getParent() { |
||
731 | |||
732 | /** |
||
733 | * Return a string of the form "parent - page" or "grandparent - parent - page" using page titles |
||
734 | * |
||
735 | * @param int $level The maximum amount of levels to traverse. |
||
736 | * @param string $separator Seperating string |
||
737 | * @return string The resulting string |
||
738 | */ |
||
739 | public function NestedTitle($level = 2, $separator = " - ") { |
||
748 | |||
749 | /** |
||
750 | * This function should return true if the current user can execute this action. It can be overloaded to customise |
||
751 | * the security model for an application. |
||
752 | * |
||
753 | * Slightly altered from parent behaviour in {@link DataObject->can()}: |
||
754 | * - Checks for existence of a method named "can<$perm>()" on the object |
||
755 | * - Calls decorators and only returns for FALSE "vetoes" |
||
756 | * - Falls back to {@link Permission::check()} |
||
757 | * - Does NOT check for many-many relations named "Can<$perm>" |
||
758 | * |
||
759 | * @uses DataObjectDecorator->can() |
||
760 | * |
||
761 | * @param string $perm The permission to be checked, such as 'View' |
||
762 | * @param Member $member The member whose permissions need checking. Defaults to the currently logged in user. |
||
763 | * @param array $context Context argument for canCreate() |
||
764 | * @return bool True if the the member is allowed to do the given action |
||
765 | */ |
||
766 | public function can($perm, $member = null, $context = array()) { |
||
783 | |||
784 | /** |
||
785 | * This function should return true if the current user can add children to this page. It can be overloaded to |
||
786 | * customise the security model for an application. |
||
787 | * |
||
788 | * Denies permission if any of the following conditions is true: |
||
789 | * - alternateCanAddChildren() on a extension returns false |
||
790 | * - canEdit() is not granted |
||
791 | * - There are no classes defined in {@link $allowed_children} |
||
792 | * |
||
793 | * @uses SiteTreeExtension->canAddChildren() |
||
794 | * @uses canEdit() |
||
795 | * @uses $allowed_children |
||
796 | * |
||
797 | * @param Member|int $member |
||
798 | * @return bool True if the current user can add children |
||
799 | */ |
||
800 | public function canAddChildren($member = null) { |
||
818 | |||
819 | /** |
||
820 | * This function should return true if the current user can view this page. It can be overloaded to customise the |
||
821 | * security model for an application. |
||
822 | * |
||
823 | * Denies permission if any of the following conditions is true: |
||
824 | * - canView() on any extension returns false |
||
825 | * - "CanViewType" directive is set to "Inherit" and any parent page return false for canView() |
||
826 | * - "CanViewType" directive is set to "LoggedInUsers" and no user is logged in |
||
827 | * - "CanViewType" directive is set to "OnlyTheseUsers" and user is not in the given groups |
||
828 | * |
||
829 | * @uses DataExtension->canView() |
||
830 | * @uses ViewerGroups() |
||
831 | * |
||
832 | * @param Member|int $member |
||
833 | * @return bool True if the current user can view this page |
||
834 | */ |
||
835 | public function canView($member = null) { |
||
874 | |||
875 | /** |
||
876 | * This function should return true if the current user can delete this page. It can be overloaded to customise the |
||
877 | * security model for an application. |
||
878 | * |
||
879 | * Denies permission if any of the following conditions is true: |
||
880 | * - canDelete() returns false on any extension |
||
881 | * - canEdit() returns false |
||
882 | * - any descendant page returns false for canDelete() |
||
883 | * |
||
884 | * @uses canDelete() |
||
885 | * @uses SiteTreeExtension->canDelete() |
||
886 | * @uses canEdit() |
||
887 | * |
||
888 | * @param Member $member |
||
889 | * @return bool True if the current user can delete this page |
||
890 | */ |
||
891 | public function canDelete($member = null) { |
||
911 | |||
912 | /** |
||
913 | * This function should return true if the current user can create new pages of this class, regardless of class. It |
||
914 | * can be overloaded to customise the security model for an application. |
||
915 | * |
||
916 | * By default, permission to create at the root level is based on the SiteConfig configuration, and permission to |
||
917 | * create beneath a parent is based on the ability to edit that parent page. |
||
918 | * |
||
919 | * Use {@link canAddChildren()} to control behaviour of creating children under this page. |
||
920 | * |
||
921 | * @uses $can_create |
||
922 | * @uses DataExtension->canCreate() |
||
923 | * |
||
924 | * @param Member $member |
||
925 | * @param array $context Optional array which may contain array('Parent' => $parentObj) |
||
926 | * If a parent page is known, it will be checked for validity. |
||
927 | * If omitted, it will be assumed this is to be created as a top level page. |
||
928 | * @return bool True if the current user can create pages on this class. |
||
929 | */ |
||
930 | public function canCreate($member = null, $context = array()) { |
||
962 | |||
963 | /** |
||
964 | * This function should return true if the current user can edit this page. It can be overloaded to customise the |
||
965 | * security model for an application. |
||
966 | * |
||
967 | * Denies permission if any of the following conditions is true: |
||
968 | * - canEdit() on any extension returns false |
||
969 | * - canView() return false |
||
970 | * - "CanEditType" directive is set to "Inherit" and any parent page return false for canEdit() |
||
971 | * - "CanEditType" directive is set to "LoggedInUsers" and no user is logged in or doesn't have the |
||
972 | * CMS_Access_CMSMAIN permission code |
||
973 | * - "CanEditType" directive is set to "OnlyTheseUsers" and user is not in the given groups |
||
974 | * |
||
975 | * @uses canView() |
||
976 | * @uses EditorGroups() |
||
977 | * @uses DataExtension->canEdit() |
||
978 | * |
||
979 | * @param Member $member Set to false if you want to explicitly test permissions without a valid user (useful for |
||
980 | * unit tests) |
||
981 | * @return bool True if the current user can edit this page |
||
982 | */ |
||
983 | public function canEdit($member = null) { |
||
1007 | |||
1008 | /** |
||
1009 | * Stub method to get the site config, unless the current class can provide an alternate. |
||
1010 | * |
||
1011 | * @return SiteConfig |
||
1012 | */ |
||
1013 | public function getSiteConfig() { |
||
1022 | |||
1023 | /** |
||
1024 | * Pre-populate the cache of canEdit, canView, canDelete, canPublish permissions. This method will use the static |
||
1025 | * can_(perm)_multiple method for efficiency. |
||
1026 | * |
||
1027 | * @param string $permission The permission: edit, view, publish, approve, etc. |
||
1028 | * @param array $ids An array of page IDs |
||
1029 | * @param callable|string $batchCallback The function/static method to call to calculate permissions. Defaults |
||
1030 | * to 'SiteTree::can_(permission)_multiple' |
||
1031 | */ |
||
1032 | static public function prepopulate_permission_cache($permission = 'CanEditType', $ids, $batchCallback = null) { |
||
1042 | |||
1043 | /** |
||
1044 | * This method is NOT a full replacement for the individual can*() methods, e.g. {@link canEdit()}. Rather than |
||
1045 | * checking (potentially slow) PHP logic, it relies on the database group associations, e.g. the "CanEditType" field |
||
1046 | * plus the "SiteTree_EditorGroups" many-many table. By batch checking multiple records, we can combine the queries |
||
1047 | * efficiently. |
||
1048 | * |
||
1049 | * Caches based on $typeField data. To invalidate the cache, use {@link SiteTree::reset()} or set the $useCached |
||
1050 | * property to FALSE. |
||
1051 | * |
||
1052 | * @param array $ids Of {@link SiteTree} IDs |
||
1053 | * @param int $memberID Member ID |
||
1054 | * @param string $typeField A property on the data record, e.g. "CanEditType". |
||
1055 | * @param string $groupJoinTable A many-many table name on this record, e.g. "SiteTree_EditorGroups" |
||
1056 | * @param string $siteConfigMethod Method to call on {@link SiteConfig} for toplevel items, e.g. "canEdit" |
||
1057 | * @param string $globalPermission If the member doesn't have this permission code, don't bother iterating deeper |
||
1058 | * @param bool $useCached |
||
1059 | * @return array An map of {@link SiteTree} ID keys to boolean values |
||
1060 | */ |
||
1061 | public static function batch_permission_check($ids, $memberID, $typeField, $groupJoinTable, $siteConfigMethod, |
||
1184 | |||
1185 | /** |
||
1186 | * Get the 'can edit' information for a number of SiteTree pages. |
||
1187 | * |
||
1188 | * @param array $ids An array of IDs of the SiteTree pages to look up |
||
1189 | * @param int $memberID ID of member |
||
1190 | * @param bool $useCached Return values from the permission cache if they exist |
||
1191 | * @return array A map where the IDs are keys and the values are booleans stating whether the given page can be |
||
1192 | * edited |
||
1193 | */ |
||
1194 | static public function can_edit_multiple($ids, $memberID, $useCached = true) { |
||
1197 | |||
1198 | /** |
||
1199 | * Get the 'can edit' information for a number of SiteTree pages. |
||
1200 | * |
||
1201 | * @param array $ids An array of IDs of the SiteTree pages to look up |
||
1202 | * @param int $memberID ID of member |
||
1203 | * @param bool $useCached Return values from the permission cache if they exist |
||
1204 | * @return array |
||
1205 | */ |
||
1206 | static public function can_delete_multiple($ids, $memberID, $useCached = true) { |
||
1265 | |||
1266 | /** |
||
1267 | * Collate selected descendants of this page. |
||
1268 | * |
||
1269 | * {@link $condition} will be evaluated on each descendant, and if it is succeeds, that item will be added to the |
||
1270 | * $collator array. |
||
1271 | * |
||
1272 | * @param string $condition The PHP condition to be evaluated. The page will be called $item |
||
1273 | * @param array $collator An array, passed by reference, to collect all of the matching descendants. |
||
1274 | * @return bool |
||
1275 | */ |
||
1276 | public function collateDescendants($condition, &$collator) { |
||
1285 | |||
1286 | /** |
||
1287 | * Return the title, description, keywords and language metatags. |
||
1288 | * |
||
1289 | * @todo Move <title> tag in separate getter for easier customization and more obvious usage |
||
1290 | * |
||
1291 | * @param bool $includeTitle Show default <title>-tag, set to false for custom templating |
||
1292 | * @return string The XHTML metatags |
||
1293 | */ |
||
1294 | public function MetaTags($includeTitle = true) { |
||
1327 | |||
1328 | /** |
||
1329 | * Returns the object that contains the content that a user would associate with this page. |
||
1330 | * |
||
1331 | * Ordinarily, this is just the page itself, but for example on RedirectorPages or VirtualPages ContentSource() will |
||
1332 | * return the page that is linked to. |
||
1333 | * |
||
1334 | * @return $this |
||
1335 | */ |
||
1336 | public function ContentSource() { |
||
1339 | |||
1340 | /** |
||
1341 | * Add default records to database. |
||
1342 | * |
||
1343 | * This function is called whenever the database is built, after the database tables have all been created. Overload |
||
1344 | * this to add default records when the database is built, but make sure you call parent::requireDefaultRecords(). |
||
1345 | */ |
||
1346 | public function requireDefaultRecords() { |
||
1347 | parent::requireDefaultRecords(); |
||
1348 | |||
1349 | // default pages |
||
1350 | if($this->class == 'SiteTree' && $this->config()->create_default_pages) { |
||
1351 | if(!SiteTree::get_by_link(Config::inst()->get('RootURLController', 'default_homepage_link'))) { |
||
1352 | $homepage = new Page(); |
||
1353 | $homepage->Title = _t('SiteTree.DEFAULTHOMETITLE', 'Home'); |
||
1354 | $homepage->Content = _t('SiteTree.DEFAULTHOMECONTENT', '<p>Welcome to SilverStripe! This is the default homepage. You can edit this page by opening <a href="admin/">the CMS</a>.</p><p>You can now access the <a href="http://docs.silverstripe.org">developer documentation</a>, or begin the <a href="http://www.silverstripe.org/learn/lessons">SilverStripe lessons</a>.</p>'); |
||
1355 | $homepage->URLSegment = Config::inst()->get('RootURLController', 'default_homepage_link'); |
||
1356 | $homepage->Sort = 1; |
||
1357 | $homepage->write(); |
||
1358 | $homepage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); |
||
1359 | $homepage->flushCache(); |
||
1360 | DB::alteration_message('Home page created', 'created'); |
||
1361 | } |
||
1362 | |||
1363 | if(DB::query("SELECT COUNT(*) FROM \"SiteTree\"")->value() == 1) { |
||
1364 | $aboutus = new Page(); |
||
1365 | $aboutus->Title = _t('SiteTree.DEFAULTABOUTTITLE', 'About Us'); |
||
1366 | $aboutus->Content = _t('SiteTree.DEFAULTABOUTCONTENT', '<p>You can fill this page out with your own content, or delete it and create your own pages.<br /></p>'); |
||
1367 | $aboutus->Sort = 2; |
||
1368 | $aboutus->write(); |
||
1369 | $aboutus->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); |
||
1370 | $aboutus->flushCache(); |
||
1371 | DB::alteration_message('About Us page created', 'created'); |
||
1372 | |||
1373 | $contactus = new Page(); |
||
1374 | $contactus->Title = _t('SiteTree.DEFAULTCONTACTTITLE', 'Contact Us'); |
||
1375 | $contactus->Content = _t('SiteTree.DEFAULTCONTACTCONTENT', '<p>You can fill this page out with your own content, or delete it and create your own pages.<br /></p>'); |
||
1376 | $contactus->Sort = 3; |
||
1377 | $contactus->write(); |
||
1378 | $contactus->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); |
||
1379 | $contactus->flushCache(); |
||
1380 | DB::alteration_message('Contact Us page created', 'created'); |
||
1381 | } |
||
1382 | } |
||
1383 | |||
1384 | // schema migration |
||
1385 | // @todo Move to migration task once infrastructure is implemented |
||
1386 | if($this->class == 'SiteTree') { |
||
1387 | $conn = DB::get_schema(); |
||
1388 | // only execute command if fields haven't been renamed to _obsolete_<fieldname> already by the task |
||
1389 | if($conn->hasField('SiteTree' ,'Viewers')) { |
||
1390 | $task = new UpgradeSiteTreePermissionSchemaTask(); |
||
1391 | $task->run(new SS_HTTPRequest('GET','/')); |
||
1392 | } |
||
1393 | } |
||
1394 | } |
||
1395 | |||
1396 | protected function onBeforeWrite() { |
||
1446 | |||
1447 | /** |
||
1448 | * Trigger synchronisation of link tracking |
||
1449 | * |
||
1450 | * {@see SiteTreeLinkTracking::augmentSyncLinkTracking} |
||
1451 | */ |
||
1452 | public function syncLinkTracking() { |
||
1455 | |||
1456 | public function onBeforeDelete() { |
||
1466 | |||
1467 | public function onAfterDelete() { |
||
1480 | |||
1481 | public function flushCache($persistent = true) { |
||
1485 | |||
1486 | public function validate() { |
||
1523 | |||
1524 | /** |
||
1525 | * Returns true if this object has a URLSegment value that does not conflict with any other objects. This method |
||
1526 | * checks for: |
||
1527 | * - A page with the same URLSegment that has a conflict |
||
1528 | * - Conflicts with actions on the parent page |
||
1529 | * - A conflict caused by a root page having the same URLSegment as a class name |
||
1530 | * |
||
1531 | * @return bool |
||
1532 | */ |
||
1533 | public function validURLSegment() { |
||
1567 | |||
1568 | /** |
||
1569 | * Generate a URL segment based on the title provided. |
||
1570 | * |
||
1571 | * If {@link Extension}s wish to alter URL segment generation, they can do so by defining |
||
1572 | * updateURLSegment(&$url, $title). $url will be passed by reference and should be modified. $title will contain |
||
1573 | * the title that was originally used as the source of this generated URL. This lets extensions either start from |
||
1574 | * scratch, or incrementally modify the generated URL. |
||
1575 | * |
||
1576 | * @param string $title Page title |
||
1577 | * @return string Generated url segment |
||
1578 | */ |
||
1579 | public function generateURLSegment($title){ |
||
1591 | |||
1592 | /** |
||
1593 | * Gets the URL segment for the latest draft version of this page. |
||
1594 | * |
||
1595 | * @return string |
||
1596 | */ |
||
1597 | public function getStageURLSegment() { |
||
1603 | |||
1604 | /** |
||
1605 | * Gets the URL segment for the currently published version of this page. |
||
1606 | * |
||
1607 | * @return string |
||
1608 | */ |
||
1609 | public function getLiveURLSegment() { |
||
1615 | |||
1616 | /** |
||
1617 | * Returns the pages that depend on this page. This includes virtual pages, pages that link to it, etc. |
||
1618 | * |
||
1619 | * @param bool $includeVirtuals Set to false to exlcude virtual pages. |
||
1620 | * @return ArrayList |
||
1621 | */ |
||
1622 | public function DependentPages($includeVirtuals = true) { |
||
1672 | |||
1673 | /** |
||
1674 | * Return all virtual pages that link to this page. |
||
1675 | * |
||
1676 | * @return DataList |
||
1677 | */ |
||
1678 | public function VirtualPages() { |
||
1688 | |||
1689 | /** |
||
1690 | * Returns a FieldList with which to create the main editing form. |
||
1691 | * |
||
1692 | * You can override this in your child classes to add extra fields - first get the parent fields using |
||
1693 | * parent::getCMSFields(), then use addFieldToTab() on the FieldList. |
||
1694 | * |
||
1695 | * See {@link getSettingsFields()} for a different set of fields concerned with configuration aspects on the record, |
||
1696 | * e.g. access control. |
||
1697 | * |
||
1698 | * @return FieldList The fields to be displayed in the CMS |
||
1699 | */ |
||
1700 | public function getCMSFields() { |
||
1880 | |||
1881 | |||
1882 | /** |
||
1883 | * Returns fields related to configuration aspects on this record, e.g. access control. See {@link getCMSFields()} |
||
1884 | * for content-related fields. |
||
1885 | * |
||
1886 | * @return FieldList |
||
1887 | */ |
||
1888 | public function getSettingsFields() { |
||
1994 | |||
1995 | /** |
||
1996 | * @param bool $includerelations A boolean value to indicate if the labels returned should include relation fields |
||
1997 | * @return array |
||
1998 | */ |
||
1999 | public function fieldLabels($includerelations = true) { |
||
2037 | |||
2038 | /** |
||
2039 | * Get the actions available in the CMS for this page - eg Save, Publish. |
||
2040 | * |
||
2041 | * Frontend scripts and styles know how to handle the following FormFields: |
||
2042 | * - top-level FormActions appear as standalone buttons |
||
2043 | * - top-level CompositeField with FormActions within appear as grouped buttons |
||
2044 | * - TabSet & Tabs appear as a drop ups |
||
2045 | * - FormActions within the Tab are restyled as links |
||
2046 | * - major actions can provide alternate states for richer presentation (see ssui.button widget extension) |
||
2047 | * |
||
2048 | * @return FieldList The available actions for this page. |
||
2049 | */ |
||
2050 | public function getCMSActions() { |
||
2051 | $existsOnLive = $this->isPublished(); |
||
2052 | |||
2053 | // Major actions appear as buttons immediately visible as page actions. |
||
2054 | $majorActions = CompositeField::create()->setName('MajorActions')->setTag('fieldset')->addExtraClass('ss-ui-buttonset noborder'); |
||
2055 | |||
2056 | // Minor options are hidden behind a drop-up and appear as links (although they are still FormActions). |
||
2057 | $rootTabSet = new TabSet('ActionMenus'); |
||
2058 | $moreOptions = new Tab( |
||
2059 | 'MoreOptions', |
||
2060 | _t('SiteTree.MoreOptions', 'More options', 'Expands a view for more buttons') |
||
2061 | ); |
||
2062 | $rootTabSet->push($moreOptions); |
||
2063 | $rootTabSet->addExtraClass('ss-ui-action-tabset action-menus noborder'); |
||
2064 | |||
2065 | // Render page information into the "more-options" drop-up, on the top. |
||
2066 | $live = Versioned::get_one_by_stage('SiteTree', Versioned::LIVE, array( |
||
2067 | '"SiteTree"."ID"' => $this->ID |
||
2068 | )); |
||
2069 | $moreOptions->push( |
||
2070 | new LiteralField('Information', |
||
2071 | $this->customise(array( |
||
2072 | 'Live' => $live, |
||
2073 | 'ExistsOnLive' => $existsOnLive |
||
2074 | ))->renderWith('SiteTree_Information') |
||
2075 | ) |
||
2076 | ); |
||
2077 | |||
2078 | // "readonly"/viewing version that isn't the current version of the record |
||
2079 | $stageOrLiveRecord = Versioned::get_one_by_stage($this->class, Versioned::get_stage(), array( |
||
2080 | '"SiteTree"."ID"' => $this->ID |
||
2081 | )); |
||
2082 | if($stageOrLiveRecord && $stageOrLiveRecord->Version != $this->Version) { |
||
2083 | $moreOptions->push(FormAction::create('email', _t('CMSMain.EMAIL', 'Email'))); |
||
2084 | $moreOptions->push(FormAction::create('rollback', _t('CMSMain.ROLLBACK', 'Roll back to this version'))); |
||
2085 | |||
2086 | $actions = new FieldList(array($majorActions, $rootTabSet)); |
||
2087 | |||
2088 | // getCMSActions() can be extended with updateCMSActions() on a extension |
||
2089 | $this->extend('updateCMSActions', $actions); |
||
2090 | |||
2091 | return $actions; |
||
2092 | } |
||
2093 | |||
2094 | if($this->isPublished() && $this->canPublish() && !$this->getIsDeletedFromStage() && $this->canUnpublish()) { |
||
2095 | // "unpublish" |
||
2096 | $moreOptions->push( |
||
2097 | FormAction::create('unpublish', _t('SiteTree.BUTTONUNPUBLISH', 'Unpublish'), 'delete') |
||
2098 | ->setDescription(_t('SiteTree.BUTTONUNPUBLISHDESC', 'Remove this page from the published site')) |
||
2099 | ->addExtraClass('ss-ui-action-destructive') |
||
2100 | ); |
||
2101 | } |
||
2102 | |||
2103 | if($this->stagesDiffer(Versioned::DRAFT, Versioned::LIVE) && !$this->getIsDeletedFromStage()) { |
||
2104 | if($this->isPublished() && $this->canEdit()) { |
||
2105 | // "rollback" |
||
2106 | $moreOptions->push( |
||
2107 | FormAction::create('rollback', _t('SiteTree.BUTTONCANCELDRAFT', 'Cancel draft changes'), 'delete') |
||
2108 | ->setDescription(_t('SiteTree.BUTTONCANCELDRAFTDESC', 'Delete your draft and revert to the currently published page')) |
||
2109 | ); |
||
2110 | } |
||
2111 | } |
||
2112 | |||
2113 | if($this->canEdit()) { |
||
2114 | if($this->getIsDeletedFromStage()) { |
||
2115 | // The usual major actions are not available, so we provide alternatives here. |
||
2116 | if($existsOnLive) { |
||
2117 | // "restore" |
||
2118 | $majorActions->push(FormAction::create('revert',_t('CMSMain.RESTORE','Restore'))); |
||
2119 | if($this->canDelete() && $this->canUnpublish()) { |
||
2120 | // "delete from live" |
||
2121 | $majorActions->push( |
||
2122 | FormAction::create('deletefromlive',_t('CMSMain.DELETEFP','Delete')) |
||
2123 | ->addExtraClass('ss-ui-action-destructive') |
||
2124 | ); |
||
2125 | } |
||
2126 | } else { |
||
2127 | // Determine if we should force a restore to root (where once it was a subpage) |
||
2128 | $restoreToRoot = $this->isParentArchived(); |
||
2129 | |||
2130 | // "restore" |
||
2131 | $title = $restoreToRoot |
||
2132 | ? _t('CMSMain.RESTORE_TO_ROOT','Restore draft at top level') |
||
2133 | : _t('CMSMain.RESTORE','Restore draft'); |
||
2134 | $description = $restoreToRoot |
||
2135 | ? _t('CMSMain.RESTORE_TO_ROOT_DESC','Restore the archived version to draft as a top level page') |
||
2136 | : _t('CMSMain.RESTORE_DESC', 'Restore the archived version to draft'); |
||
2137 | $majorActions->push( |
||
2138 | FormAction::create('restore', $title) |
||
2139 | ->setDescription($description) |
||
2140 | ->setAttribute('data-to-root', $restoreToRoot) |
||
2141 | ->setAttribute('data-icon', 'decline') |
||
2142 | ); |
||
2143 | } |
||
2144 | } else { |
||
2145 | if($this->canDelete()) { |
||
2146 | // delete |
||
2147 | $moreOptions->push( |
||
2148 | FormAction::create('delete',_t('CMSMain.DELETE','Delete draft')) |
||
2149 | ->addExtraClass('delete ss-ui-action-destructive') |
||
2150 | ); |
||
2151 | } |
||
2152 | if($this->canArchive()) { |
||
2153 | // "archive" |
||
2154 | $moreOptions->push( |
||
2155 | FormAction::create('archive',_t('CMSMain.ARCHIVE','Archive')) |
||
2156 | ->setDescription(_t( |
||
2157 | 'SiteTree.BUTTONARCHIVEDESC', |
||
2158 | 'Unpublish and send to archive' |
||
2159 | )) |
||
2160 | ->addExtraClass('delete ss-ui-action-destructive') |
||
2161 | ); |
||
2162 | } |
||
2163 | |||
2164 | // "save", supports an alternate state that is still clickable, but notifies the user that the action is not needed. |
||
2165 | $majorActions->push( |
||
2166 | FormAction::create('save', _t('SiteTree.BUTTONSAVED', 'Saved')) |
||
2167 | ->setAttribute('data-icon', 'accept') |
||
2168 | ->setAttribute('data-icon-alternate', 'addpage') |
||
2169 | ->setAttribute('data-text-alternate', _t('CMSMain.SAVEDRAFT','Save draft')) |
||
2170 | ); |
||
2171 | } |
||
2172 | } |
||
2173 | |||
2174 | if($this->canPublish() && !$this->getIsDeletedFromStage()) { |
||
2175 | // "publish", as with "save", it supports an alternate state to show when action is needed. |
||
2176 | $majorActions->push( |
||
2177 | $publish = FormAction::create('publish', _t('SiteTree.BUTTONPUBLISHED', 'Published')) |
||
2178 | ->setAttribute('data-icon', 'accept') |
||
2179 | ->setAttribute('data-icon-alternate', 'disk') |
||
2180 | ->setAttribute('data-text-alternate', _t('SiteTree.BUTTONSAVEPUBLISH', 'Save & publish')) |
||
2181 | ); |
||
2182 | |||
2183 | // Set up the initial state of the button to reflect the state of the underlying SiteTree object. |
||
2184 | if($this->stagesDiffer(Versioned::DRAFT, Versioned::LIVE)) { |
||
2185 | $publish->addExtraClass('ss-ui-alternate'); |
||
2186 | } |
||
2187 | } |
||
2188 | |||
2189 | $actions = new FieldList(array($majorActions, $rootTabSet)); |
||
2190 | |||
2191 | // Hook for extensions to add/remove actions. |
||
2192 | $this->extend('updateCMSActions', $actions); |
||
2193 | |||
2194 | return $actions; |
||
2195 | } |
||
2196 | |||
2197 | public function onAfterPublish() { |
||
2205 | |||
2206 | /** |
||
2207 | * Update draft dependant pages |
||
2208 | */ |
||
2209 | public function onAfterRevertToLive() { |
||
2221 | |||
2222 | /** |
||
2223 | * Determine if this page references a parent which is archived, and not available in stage |
||
2224 | * |
||
2225 | * @return bool True if there is an archived parent |
||
2226 | */ |
||
2227 | protected function isParentArchived() { |
||
2236 | |||
2237 | /** |
||
2238 | * Restore the content in the active copy of this SiteTree page to the stage site. |
||
2239 | * |
||
2240 | * @return self |
||
2241 | */ |
||
2242 | public function doRestoreToStage() { |
||
2278 | |||
2279 | /** |
||
2280 | * Check if this page is new - that is, if it has yet to have been written to the database. |
||
2281 | * |
||
2282 | * @return bool |
||
2283 | */ |
||
2284 | public function isNew() { |
||
2295 | |||
2296 | /** |
||
2297 | * Get the class dropdown used in the CMS to change the class of a page. This returns the list of options in the |
||
2298 | * dropdown as a Map from class name to singular name. Filters by {@link SiteTree->canCreate()}, as well as |
||
2299 | * {@link SiteTree::$needs_permission}. |
||
2300 | * |
||
2301 | * @return array |
||
2302 | */ |
||
2303 | protected function getClassDropdown() { |
||
2347 | |||
2348 | /** |
||
2349 | * Returns an array of the class names of classes that are allowed to be children of this class. |
||
2350 | * |
||
2351 | * @return string[] |
||
2352 | */ |
||
2353 | public function allowedChildren() { |
||
2373 | |||
2374 | /** |
||
2375 | * Returns the class name of the default class for children of this page. |
||
2376 | * |
||
2377 | * @return string |
||
2378 | */ |
||
2379 | public function defaultChild() { |
||
2388 | |||
2389 | /** |
||
2390 | * Returns the class name of the default class for the parent of this page. |
||
2391 | * |
||
2392 | * @return string |
||
2393 | */ |
||
2394 | public function defaultParent() { |
||
2397 | |||
2398 | /** |
||
2399 | * Get the title for use in menus for this page. If the MenuTitle field is set it returns that, else it returns the |
||
2400 | * Title field. |
||
2401 | * |
||
2402 | * @return string |
||
2403 | */ |
||
2404 | public function getMenuTitle(){ |
||
2411 | |||
2412 | |||
2413 | /** |
||
2414 | * Set the menu title for this page. |
||
2415 | * |
||
2416 | * @param string $value |
||
2417 | */ |
||
2418 | public function setMenuTitle($value) { |
||
2425 | |||
2426 | /** |
||
2427 | * A flag provides the user with additional data about the current page status, for example a "removed from draft" |
||
2428 | * status. Each page can have more than one status flag. Returns a map of a unique key to a (localized) title for |
||
2429 | * the flag. The unique key can be reused as a CSS class. Use the 'updateStatusFlags' extension point to customize |
||
2430 | * the flags. |
||
2431 | * |
||
2432 | * Example (simple): |
||
2433 | * "deletedonlive" => "Deleted" |
||
2434 | * |
||
2435 | * Example (with optional title attribute): |
||
2436 | * "deletedonlive" => array('text' => "Deleted", 'title' => 'This page has been deleted') |
||
2437 | * |
||
2438 | * @param bool $cached Whether to serve the fields from cache; false regenerate them |
||
2439 | * @return array |
||
2440 | */ |
||
2441 | public function getStatusFlags($cached = true) { |
||
2475 | |||
2476 | /** |
||
2477 | * getTreeTitle will return three <span> html DOM elements, an empty <span> with the class 'jstree-pageicon' in |
||
2478 | * front, following by a <span> wrapping around its MenutTitle, then following by a <span> indicating its |
||
2479 | * publication status. |
||
2480 | * |
||
2481 | * @return string An HTML string ready to be directly used in a template |
||
2482 | */ |
||
2483 | public function getTreeTitle() { |
||
2512 | |||
2513 | /** |
||
2514 | * Returns the page in the current page stack of the given level. Level(1) will return the main menu item that |
||
2515 | * we're currently inside, etc. |
||
2516 | * |
||
2517 | * @param int $level |
||
2518 | * @return SiteTree |
||
2519 | */ |
||
2520 | public function Level($level) { |
||
2529 | |||
2530 | /** |
||
2531 | * Gets the depth of this page in the sitetree, where 1 is the root level |
||
2532 | * |
||
2533 | * @return int |
||
2534 | */ |
||
2535 | public function getPageLevel() { |
||
2541 | |||
2542 | /** |
||
2543 | * Return the CSS classes to apply to this node in the CMS tree. |
||
2544 | * |
||
2545 | * @param string $numChildrenMethod |
||
2546 | * @return string |
||
2547 | */ |
||
2548 | public function CMSTreeClasses($numChildrenMethod="numChildren") { |
||
2579 | |||
2580 | /** |
||
2581 | * Compares current draft with live version, and returns true if no draft version of this page exists but the page |
||
2582 | * is still published (eg, after triggering "Delete from draft site" in the CMS). |
||
2583 | * |
||
2584 | * @return bool |
||
2585 | */ |
||
2586 | public function getIsDeletedFromStage() { |
||
2595 | |||
2596 | /** |
||
2597 | * Return true if this page exists on the live site |
||
2598 | * |
||
2599 | * @return bool |
||
2600 | */ |
||
2601 | public function getExistsOnLive() { |
||
2604 | |||
2605 | /** |
||
2606 | * Compares current draft with live version, and returns true if these versions differ, meaning there have been |
||
2607 | * unpublished changes to the draft site. |
||
2608 | * |
||
2609 | * @return bool |
||
2610 | */ |
||
2611 | public function getIsModifiedOnStage() { |
||
2623 | |||
2624 | /** |
||
2625 | * Compares current draft with live version, and returns true if no live version exists, meaning the page was never |
||
2626 | * published. |
||
2627 | * |
||
2628 | * @return bool |
||
2629 | */ |
||
2630 | public function getIsAddedToStage() { |
||
2639 | |||
2640 | /** |
||
2641 | * Stops extendCMSFields() being called on getCMSFields(). This is useful when you need access to fields added by |
||
2642 | * subclasses of SiteTree in a extension. Call before calling parent::getCMSFields(), and reenable afterwards. |
||
2643 | */ |
||
2644 | static public function disableCMSFieldsExtensions() { |
||
2647 | |||
2648 | /** |
||
2649 | * Reenables extendCMSFields() being called on getCMSFields() after it has been disabled by |
||
2650 | * disableCMSFieldsExtensions(). |
||
2651 | */ |
||
2652 | static public function enableCMSFieldsExtensions() { |
||
2655 | |||
2656 | public function providePermissions() { |
||
2690 | |||
2691 | /** |
||
2692 | * Return the translated Singular name. |
||
2693 | * |
||
2694 | * @return string |
||
2695 | */ |
||
2696 | public function i18n_singular_name() { |
||
2701 | |||
2702 | /** |
||
2703 | * Overloaded to also provide entities for 'Page' class which is usually located in custom code, hence textcollector |
||
2704 | * picks it up for the wrong folder. |
||
2705 | * |
||
2706 | * @return array |
||
2707 | */ |
||
2708 | public function provideI18nEntities() { |
||
2724 | |||
2725 | /** |
||
2726 | * Returns 'root' if the current page has no parent, or 'subpage' otherwise |
||
2727 | * |
||
2728 | * @return string |
||
2729 | */ |
||
2730 | public function getParentType() { |
||
2733 | |||
2734 | /** |
||
2735 | * Clear the permissions cache for SiteTree |
||
2736 | */ |
||
2737 | public static function reset() { |
||
2740 | |||
2741 | static public function on_db_reset() { |
||
2744 | |||
2745 | } |
||
2746 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.