Merge pull request #1140 from InfinityIo/sitetree-docblock-improvements

PHPDoc improvements for SiteTree and SiteTreeLinkTracking
This commit is contained in:
Ingo Schommer 2015-04-26 18:43:43 +12:00
commit a5ef364e67
2 changed files with 307 additions and 319 deletions

View File

@ -1,17 +1,16 @@
<?php <?php
/** /**
* Basic data-object representing all pages within the site tree. * Basic data-object representing all pages within the site tree. All page types that live within the hierarchy should
* This data-object takes care of the heirachy. All page types that live within the hierarchy should inherit from this. * inherit from this. In addition, it contains a number of static methods for querying the site tree and working with
* In addition, it contains a number of static methods for querying the site tree. * draft and published states.
* *
* <h2>URLs</h2> * <h2>URLs</h2>
* A page is identified during request handling via its "URLSegment" database column. * A page is identified during request handling via its "URLSegment" database column. As pages can be nested, the full
* As pages can be nested, the full path of a URL might contain multiple segments. * path of a URL might contain multiple segments. Each segment is stored in its filtered representation (through
* Each segment is stored in its filtered representation (through {@link URLSegmentFilter}). * {@link URLSegmentFilter}). The full path is constructed via {@link Link()}, {@link RelativeLink()} and
* The full path is constructed via {@link Link()}, {@link RelativeLink()} and {@link AbsoluteLink()}. * {@link AbsoluteLink()}. You can allow these segments to contain multibyte characters through
* You can allow these segments to contain multibyte characters through {@link URLSegmentFilter::$default_allow_multibyte}. * {@link URLSegmentFilter::$default_allow_multibyte}.
* *
* @property integer ID ID of the SiteTree object.
* @property string URLSegment * @property string URLSegment
* @property string Title * @property string Title
* @property string MenuTitle * @property string MenuTitle
@ -21,17 +20,17 @@
* @property string ShowInMenus * @property string ShowInMenus
* @property string ShowInSearch * @property string ShowInSearch
* @property string Sort Integer value denoting the sort order. * @property string Sort Integer value denoting the sort order.
* @property string HasBrokenFile
* @property string HasBrokenLink
* @property string ReportClass * @property string ReportClass
* @property string CanViewType Type of restriction for viewing this object. * @property string CanViewType Type of restriction for viewing this object.
* @property string CanEditType Type of restriction for editing this object. * @property string CanEditType Type of restriction for editing this object.
* *
* @method ManyManyList LinkTracking() List of site pages linked on this page. * @method ManyManyList ViewerGroups List of groups that can view this object.
* @method ManyManyList ImageTracking() List of Images linked on this page. * @method ManyManyList EditorGroups List of groups that can edit this object.
* @method ManyManyList ViewerGroups() List of groups that can view this object. * @method ManyManyList BackLinkTracking List of site pages that link to this page.
* @method ManyManyList EditorGroups() List of groups that can edit this object. *
* @method ManyManyList BackLinkTracking() List of site pages that link to this page. * @mixin Hierarchy
* @mixin Versioned
* @mixin SiteTreeLinkTracking
* *
* @package cms * @package cms
*/ */
@ -162,8 +161,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* If this is false, the class cannot be created in the CMS by regular content authors, only by ADMINs. * If this is false, the class cannot be created in the CMS by regular content authors, only by ADMINs.
* @var boolean * @var boolean
* @config * @config
*/ */
private static $can_create = true; private static $can_create = true;
/** /**
@ -228,7 +227,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
private static $enforce_strict_hierarchy = true; private static $enforce_strict_hierarchy = true;
/** /**
* The value used for the meta generator tag. Leave blank to omit the tag. * The value used for the meta generator tag. Leave blank to omit the tag.
* *
* @config * @config
* @var string * @var string
@ -317,8 +316,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* Note that if no model can be found, this method will fall over to a extended alternateGetByLink method provided * Note that if no model can be found, this method will fall over to a extended alternateGetByLink method provided
* by a extension attached to {@link SiteTree} * by a extension attached to {@link SiteTree}
* *
* @param string $link * @param string $link The link of the page to search for
* @param bool $cache * @param bool $cache True (default) to use caching, false to force a fresh search from the database
* @return SiteTree * @return SiteTree
*/ */
static public function get_by_link($link, $cache = true) { static public function get_by_link($link, $cache = true) {
@ -388,9 +387,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Return a subclass map of SiteTree * Return a subclass map of SiteTree that shouldn't be hidden through {@link SiteTree::$hide_ancestor}
* that shouldn't be hidden through
* {@link SiteTree::$hide_ancestor}
* *
* @return array * @return array
*/ */
@ -413,7 +410,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
} }
// If any of the descendents don't want any of the elders to show up, cruelly render the elders surplus to requirements. // If any of the descendents don't want any of the elders to show up, cruelly render the elders surplus to
// requirements
if($kill_ancestors) { if($kill_ancestors) {
$kill_ancestors = array_unique($kill_ancestors); $kill_ancestors = array_unique($kill_ancestors);
foreach($kill_ancestors as $mark) { foreach($kill_ancestors as $mark) {
@ -429,10 +427,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Replace a "[sitetree_link id=n]" shortcode with a link to the page with the corresponding ID. * Replace a "[sitetree_link id=n]" shortcode with a link to the page with the corresponding ID.
* *
* @param array $arguments * @param array $arguments
* @param mixed $content * @param string $content
* @param object|null $parser * @param TextParser $parser
* @return string|void * @return string
*/ */
static public function link_shortcode_handler($arguments, $content = null, $parser = null) { static public function link_shortcode_handler($arguments, $content = null, $parser = null) {
if(!isset($arguments['id']) || !is_numeric($arguments['id'])) return; if(!isset($arguments['id']) || !is_numeric($arguments['id'])) return;
@ -453,14 +451,14 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $link; return $link;
} }
} }
/** /**
* Return the link for this {@link SiteTree} object, with the {@link Director::baseURL()} included. * Return the link for this {@link SiteTree} object, with the {@link Director::baseURL()} included.
* *
* @param string $action Optional controller action (method). * @param string $action Optional controller action (method).
* Note: URI encoding of this parameter is applied automatically through template casting, * Note: URI encoding of this parameter is applied automatically through template casting,
* don't encode the passed parameter. * don't encode the passed parameter. Please use {@link Controller::join_links()} instead to
* Please use {@link Controller::join_links()} instead to append GET parameters. * append GET parameters.
* @return string * @return string
*/ */
public function Link($action = null) { public function Link($action = null) {
@ -482,9 +480,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Base link used for previewing. Defaults to absolute URL, * Base link used for previewing. Defaults to absolute URL, in order to account for domain changes, e.g. on multi
* in order to account for domain changes, e.g. on multi site setups. * site setups. Does not contain hints about the stage, see {@link SilverStripeNavigator} for details.
* Does not contain hints about the stage, see {@link SilverStripeNavigator} for details.
* *
* @param string $action See {@link Link()} * @param string $action See {@link Link()}
* @return string * @return string
@ -500,7 +497,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Return the link for this {@link SiteTree} object relative to the SilverStripe root. * Return the link for this {@link SiteTree} object relative to the SilverStripe root.
* *
* By default, it this page is the current home page, and there is no action specified then this will return a link * By default, if this page is the current home page, and there is no action specified then this will return a link
* to the root of the site. However, if you set the $action parameter to TRUE then the link will not be rewritten * to the root of the site. However, if you set the $action parameter to TRUE then the link will not be rewritten
* and returned in its full form. * and returned in its full form.
* *
@ -529,9 +526,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return Controller::join_links($base, '/', $action); return Controller::join_links($base, '/', $action);
} }
/** /**
* Get the absolute URL for this page on the Live site. * Get the absolute URL for this page on the Live site.
*
* @param bool $includeStageEqualsLive Whether to append the URL with ?stage=Live to force Live mode
* @return string
*/ */
public function getAbsoluteLiveLink($includeStageEqualsLive = true) { public function getAbsoluteLiveLink($includeStageEqualsLive = true) {
$oldStage = Versioned::current_stage(); $oldStage = Versioned::current_stage();
@ -549,7 +549,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* @return String * Generates a link to edit this page in the CMS.
*
* @return string
*/ */
public function CMSEditLink() { public function CMSEditLink() {
return Controller::join_links(singleton('CMSPageEditController')->Link('show'), $this->ID); return Controller::join_links(singleton('CMSPageEditController')->Link('show'), $this->ID);
@ -566,7 +568,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Returns TRUE if this is the currently active page that is being used to handle a request. * Returns true if this is the currently active page being used to handle this request.
* *
* @return bool * @return bool
*/ */
@ -575,8 +577,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Check if this page is in the currently active section (e.g. it is either current or one of it's children is * Check if this page is in the currently active section (e.g. it is either current or one of its children is
* currently being viewed. * currently being viewed).
* *
* @return bool * @return bool
*/ */
@ -587,9 +589,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Check if the parent of this page has been removed (or made otherwise unavailable), and * Check if the parent of this page has been removed (or made otherwise unavailable), and is still referenced by
* is still referenced by this child. Any such orphaned page may still require access via * this child. Any such orphaned page may still require access via the CMS, but should not be shown as accessible
* the cms, but should not be shown as accessible to external users. * to external users.
* *
* @return bool * @return bool
*/ */
@ -621,8 +623,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Return "link", "current" or section depending on if this page is the current page, or not on the current page but * Return "link", "current" or "section" depending on if this page is the current page, or not on the current page
* in the current section. * but in the current section.
* *
* @return string * @return string
*/ */
@ -639,8 +641,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Check if this page is in the given current section. * Check if this page is in the given current section.
* *
* @param string $sectionName Name of the section to check. * @param string $sectionName Name of the section to check
* @return boolean True if we are in the given section. * @return bool True if we are in the given section
*/ */
public function InSection($sectionName) { public function InSection($sectionName) {
$page = Director::get_current_page(); $page = Director::get_current_page();
@ -653,11 +655,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Create a duplicate of this node. Doesn't affect joined data - create a * Create a duplicate of this node. Doesn't affect joined data - create a custom overloading of this if you need
* custom overloading of this if you need such behaviour. * such behaviour.
* *
* @param bool $doWrite * @param bool $doWrite Whether to write the new object before returning it
* @return SiteTree The duplicated object. * @return self The duplicated object
*/ */
public function duplicate($doWrite = true) { public function duplicate($doWrite = true) {
@ -675,12 +677,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $page; return $page;
} }
/** /**
* Duplicates each child of this node recursively and returns the * Duplicates each child of this node recursively and returns the top-level duplicate node.
* duplicate node.
* *
* @return SiteTree The duplicated object. * @return self The duplicated object
*/ */
public function duplicateWithChildren() { public function duplicateWithChildren() {
$clone = $this->duplicate(); $clone = $this->duplicate();
@ -699,10 +699,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $clone; return $clone;
} }
/** /**
* Duplicate this node and its children as a child of the node with the * Duplicate this node and its children as a child of the node with the given ID
* given ID
* *
* @param int $id ID of the new node's new parent * @param int $id ID of the new node's new parent
*/ */
@ -714,13 +712,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Return a breadcrumb trail to this page. Excludes "hidden" pages * Return a breadcrumb trail to this page. Excludes "hidden" pages (with ShowInMenus=0) by default.
* (with ShowInMenus=0).
* *
* @param int $maxDepth The maximum depth to traverse. * @param int $maxDepth The maximum depth to traverse.
* @param boolean $unlinked Do not make page names links * @param bool $unlinked Do not make page names links
* @param boolean|string $stopAtPageType ClassName of a page to stop the upwards traversal. * @param bool|string $stopAtPageType ClassName of a page to stop the upwards traversal.
* @param boolean $showHidden Include pages marked with the attribute ShowInMenus = 0 * @param bool $showHidden Include pages marked with the attribute ShowInMenus = 0
* @return HTMLText The breadcrumb trail. * @return HTMLText The breadcrumb trail.
*/ */
public function Breadcrumbs($maxDepth = 20, $unlinked = false, $stopAtPageType = false, $showHidden = false) { public function Breadcrumbs($maxDepth = 20, $unlinked = false, $stopAtPageType = false, $showHidden = false) {
@ -749,8 +746,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Make this page a child of another page. * Make this page a child of another page.
* *
* If the parent page does not exist, resolve it to a valid ID * If the parent page does not exist, resolve it to a valid ID before updating this page's reference.
* before updating this page's reference.
* *
* @param SiteTree|int $item Either the parent object, or the parent ID * @param SiteTree|int $item Either the parent object, or the parent ID
*/ */
@ -766,7 +762,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Get the parent of this page. * Get the parent of this page.
* *
* @return SiteTree Parent of this page. * @return SiteTree Parent of this page
*/ */
public function getParent() { public function getParent() {
if ($this->getField("ParentID")) { if ($this->getField("ParentID")) {
@ -775,8 +771,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Return a string of the form "parent - page" or * Return a string of the form "parent - page" or "grandparent - parent - page" using page titles
* "grandparent - parent - page".
* *
* @param int $level The maximum amount of levels to traverse. * @param int $level The maximum amount of levels to traverse.
* @param string $separator Seperating string * @param string $separator Seperating string
@ -793,8 +788,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* This function should return true if the current user can execute this action. * This function should return true if the current user can execute this action. It can be overloaded to customise
* It can be overloaded to customise the security model for an application. * the security model for an application.
* *
* Slightly altered from parent behaviour in {@link DataObject->can()}: * Slightly altered from parent behaviour in {@link DataObject->can()}:
* - Checks for existence of a method named "can<$perm>()" on the object * - Checks for existence of a method named "can<$perm>()" on the object
@ -804,10 +799,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* *
* @uses DataObjectDecorator->can() * @uses DataObjectDecorator->can()
* *
* @param string $perm The permission to be checked, such as 'View'. * @param string $perm The permission to be checked, such as 'View'
* @param Member $member The member whose permissions need checking. * @param Member $member The member whose permissions need checking. Defaults to the currently logged in user.
* Defaults to the currently logged in user. * @return bool True if the the member is allowed to do the given action
* @return boolean True if the the member is allowed to do the given action.
*/ */
public function can($perm, $member = null) { public function can($perm, $member = null) {
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) { if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
@ -827,14 +821,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return ($member && Permission::checkMember($member, $perm)); return ($member && Permission::checkMember($member, $perm));
} }
/** /**
* This function should return true if the current user can add children * This function should return true if the current user can add children to this page. It can be overloaded to
* to this page. It can be overloaded to customise the security model for an * customise the security model for an application.
* application.
* *
* Denies permission if any of the following conditions is TRUE: * Denies permission if any of the following conditions is true:
* - alternateCanAddChildren() on a extension returns FALSE * - alternateCanAddChildren() on a extension returns false
* - canEdit() is not granted * - canEdit() is not granted
* - There are no classes defined in {@link $allowed_children} * - There are no classes defined in {@link $allowed_children}
* *
@ -842,8 +834,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @uses canEdit() * @uses canEdit()
* @uses $allowed_children * @uses $allowed_children
* *
* @param Member|int|null $member * @param Member|int $member
* @return boolean True if the current user can add children. * @return bool True if the current user can add children
*/ */
public function canAddChildren($member = null) { public function canAddChildren($member = null) {
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) { if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
@ -859,14 +851,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $this->canEdit($member) && $this->stat('allowed_children') != 'none'; return $this->canEdit($member) && $this->stat('allowed_children') != 'none';
} }
/** /**
* This function should return true if the current user can view this * This function should return true if the current user can view this page. It can be overloaded to customise the
* page. It can be overloaded to customise the security model for an * security model for an application.
* application.
* *
* Denies permission if any of the following conditions is TRUE: * Denies permission if any of the following conditions is true:
* - canView() on any extension returns FALSE * - canView() on any extension returns false
* - "CanViewType" directive is set to "Inherit" and any parent page return false for canView() * - "CanViewType" directive is set to "Inherit" and any parent page return false for canView()
* - "CanViewType" directive is set to "LoggedInUsers" and no user is logged in * - "CanViewType" directive is set to "LoggedInUsers" and no user is logged in
* - "CanViewType" directive is set to "OnlyTheseUsers" and user is not in the given groups * - "CanViewType" directive is set to "OnlyTheseUsers" and user is not in the given groups
@ -874,8 +864,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @uses DataExtension->canView() * @uses DataExtension->canView()
* @uses ViewerGroups() * @uses ViewerGroups()
* *
* @param Member|int|null $member * @param Member|int $member
* @return boolean True if the current user can view this page. * @return bool True if the current user can view this page
*/ */
public function canView($member = null) { public function canView($member = null) {
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) { if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
@ -940,9 +930,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* *
* @todo Implement in CMS UI. * @todo Implement in CMS UI.
* *
* @param String $stage * @param string $stage
* @param Member $member * @param Member $member
* @return boolean * @return bool
*/ */
public function canViewStage($stage = 'Live', $member = null) { public function canViewStage($stage = 'Live', $member = null) {
$oldMode = Versioned::get_reading_mode(); $oldMode = Versioned::get_reading_mode();
@ -955,21 +945,20 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* This function should return true if the current user can delete this * This function should return true if the current user can delete this page. It can be overloaded to customise the
* page. It can be overloaded to customise the security model for an * security model for an application.
* application.
* *
* Denies permission if any of the following conditions is TRUE: * Denies permission if any of the following conditions is true:
* - canDelete() returns FALSE on any extension * - canDelete() returns false on any extension
* - canEdit() returns FALSE * - canEdit() returns false
* - any descendant page returns FALSE for canDelete() * - any descendant page returns false for canDelete()
* *
* @uses canDelete() * @uses canDelete()
* @uses SiteTreeExtension->canDelete() * @uses SiteTreeExtension->canDelete()
* @uses canEdit() * @uses canEdit()
* *
* @param Member $member * @param Member $member
* @return boolean True if the current user can delete this page. * @return bool True if the current user can delete this page
*/ */
public function canDelete($member = null) { public function canDelete($member = null) {
if($member instanceof Member) $memberID = $member->ID; if($member instanceof Member) $memberID = $member->ID;
@ -993,13 +982,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* This function should return true if the current user can create new * This function should return true if the current user can create new pages of this class, regardless of class. It
* pages of this class, regardless of context. It can be overloaded * can be overloaded to customise the security model for an application.
* to customise the security model for an application.
* *
* By default, permission to create at the root level is based on the SiteConfig * By default, permission to create at the root level is based on the SiteConfig configuration, and permission to
* configuration, and permission to create beneath a parent is based on the * create beneath a parent is based on the ability to edit that parent page.
* ability to edit that parent page.
* *
* Use {@link canAddChildren()} to control behaviour of creating children under this page. * Use {@link canAddChildren()} to control behaviour of creating children under this page.
* *
@ -1008,9 +995,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* *
* @param Member $member * @param Member $member
* @param array $context Optional array which may contain array('Parent' => $parentObj) * @param array $context Optional array which may contain array('Parent' => $parentObj)
* If a parent page is known, it will be checked for validity. * If a parent page is known, it will be checked for validity.
* If omitted, it will be assumed this is to be created as a top level page. * If omitted, it will be assumed this is to be created as a top level page.
* @return boolean True if the current user can create pages on this class. * @return bool True if the current user can create pages on this class.
*/ */
public function canCreate($member = null) { public function canCreate($member = null) {
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) { if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
@ -1043,23 +1030,24 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* This function should return true if the current user can edit this * This function should return true if the current user can edit this page. It can be overloaded to customise the
* page. It can be overloaded to customise the security model for an * security model for an application.
* application.
* *
* Denies permission if any of the following conditions is TRUE: * Denies permission if any of the following conditions is true:
* - canEdit() on any extension returns FALSE * - canEdit() on any extension returns false
* - canView() return false * - canView() return false
* - "CanEditType" directive is set to "Inherit" and any parent page return false for canEdit() * - "CanEditType" directive is set to "Inherit" and any parent page return false for canEdit()
* - "CanEditType" directive is set to "LoggedInUsers" and no user is logged in or doesn't have the CMS_Access_CMSMAIN permission code * - "CanEditType" directive is set to "LoggedInUsers" and no user is logged in or doesn't have the
* CMS_Access_CMSMAIN permission code
* - "CanEditType" directive is set to "OnlyTheseUsers" and user is not in the given groups * - "CanEditType" directive is set to "OnlyTheseUsers" and user is not in the given groups
* *
* @uses canView() * @uses canView()
* @uses EditorGroups() * @uses EditorGroups()
* @uses DataExtension->canEdit() * @uses DataExtension->canEdit()
* *
* @param Member $member Set to FALSE if you want to explicitly test permissions without a valid user (useful for unit tests) * @param Member $member Set to false if you want to explicitly test permissions without a valid user (useful for
* @return boolean True if the current user can edit this page. * unit tests)
* @return bool True if the current user can edit this page
*/ */
public function canEdit($member = null) { public function canEdit($member = null) {
if($member instanceof Member) $memberID = $member->ID; if($member instanceof Member) $memberID = $member->ID;
@ -1087,18 +1075,17 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* This function should return true if the current user can publish this * This function should return true if the current user can publish this page. It can be overloaded to customise
* page. It can be overloaded to customise the security model for an * the security model for an application.
* application.
* *
* Denies permission if any of the following conditions is TRUE: * Denies permission if any of the following conditions is true:
* - canPublish() on any extension returns FALSE * - canPublish() on any extension returns false
* - canEdit() returns FALSE * - canEdit() returns false
* *
* @uses SiteTreeExtension->canPublish() * @uses SiteTreeExtension->canPublish()
* *
* @param Member $member * @param Member $member
* @return boolean True if the current user can publish this page. * @return bool True if the current user can publish this page.
*/ */
public function canPublish($member = null) { public function canPublish($member = null) {
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser(); if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
@ -1122,7 +1109,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Stub method to get the site config, provided so it's easy to override * Stub method to get the site config, unless the current class can provide an alternate.
*
* @return SiteConfig
*/ */
public function getSiteConfig() { public function getSiteConfig() {
@ -1135,13 +1124,13 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Pre-populate the cache of canEdit, canView, canDelete, canPublish permissions. * Pre-populate the cache of canEdit, canView, canDelete, canPublish permissions. This method will use the static
* This method will use the static can_(perm)_multiple method for efficiency. * can_(perm)_multiple method for efficiency.
* *
* @param string $permission The permission: edit, view, publish, approve, etc. * @param string $permission The permission: edit, view, publish, approve, etc.
* @param array $ids An array of page IDs * @param array $ids An array of page IDs
* @param callback|null $batchCallback The function/static method to call to calculate permissions. Defaults * @param callable|string $batchCallback The function/static method to call to calculate permissions. Defaults
* to 'SiteTree::can_(permission)_multiple' * to 'SiteTree::can_(permission)_multiple'
*/ */
static public function prepopulate_permission_cache($permission = 'CanEditType', $ids, $batchCallback = null) { static public function prepopulate_permission_cache($permission = 'CanEditType', $ids, $batchCallback = null) {
if(!$batchCallback) $batchCallback = "SiteTree::can_{$permission}_multiple"; if(!$batchCallback) $batchCallback = "SiteTree::can_{$permission}_multiple";
@ -1153,26 +1142,27 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
. "with callback '$batchCallback'", E_USER_WARNING); . "with callback '$batchCallback'", E_USER_WARNING);
} }
} }
/** /**
* This method is NOT a full replacement for the individual can*() methods, e.g. {@link canEdit()}. * This method is NOT a full replacement for the individual can*() methods, e.g. {@link canEdit()}. Rather than
* Rather than checking (potentially slow) PHP logic, it relies on the database group associations, * checking (potentially slow) PHP logic, it relies on the database group associations, e.g. the "CanEditType" field
* e.g. the "CanEditType" field plus the "SiteTree_EditorGroups" many-many table. * plus the "SiteTree_EditorGroups" many-many table. By batch checking multiple records, we can combine the queries
* By batch checking multiple records, we can combine the queries efficiently. * efficiently.
* *
* Caches based on $typeField data. To invalidate the cache, use {@link SiteTree::reset()} * Caches based on $typeField data. To invalidate the cache, use {@link SiteTree::reset()} or set the $useCached
* or set the $useCached property to FALSE. * property to FALSE.
* *
* @param Array $ids Of {@link SiteTree} IDs * @param array $ids Of {@link SiteTree} IDs
* @param Int $memberID Member ID * @param int $memberID Member ID
* @param String $typeField A property on the data record, e.g. "CanEditType". * @param string $typeField A property on the data record, e.g. "CanEditType".
* @param String $groupJoinTable A many-many table name on this record, e.g. "SiteTree_EditorGroups" * @param string $groupJoinTable A many-many table name on this record, e.g. "SiteTree_EditorGroups"
* @param String $siteConfigMethod Method to call on {@link SiteConfig} for toplevel items, e.g. "canEdit" * @param string $siteConfigMethod Method to call on {@link SiteConfig} for toplevel items, e.g. "canEdit"
* @param String $globalPermission If the member doesn't have this permission code, don't bother iterating deeper. * @param string $globalPermission If the member doesn't have this permission code, don't bother iterating deeper
* @param Boolean $useCached * @param bool $useCached
* @return Array An map of {@link SiteTree} ID keys, to boolean values * @return array An map of {@link SiteTree} ID keys to boolean values
*/ */
static public function batch_permission_check($ids, $memberID, $typeField, $groupJoinTable, $siteConfigMethod, $globalPermission = null, $useCached = true) { public static function batch_permission_check($ids, $memberID, $typeField, $groupJoinTable, $siteConfigMethod,
$globalPermission = null, $useCached = true) {
if($globalPermission === NULL) $globalPermission = array('CMS_ACCESS_LeftAndMain', 'CMS_ACCESS_CMSMain'); if($globalPermission === NULL) $globalPermission = array('CMS_ACCESS_LeftAndMain', 'CMS_ACCESS_CMSMain');
// Sanitise the IDs // Sanitise the IDs
@ -1205,8 +1195,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$SQL_idList = implode($ids, ", "); $SQL_idList = implode($ids, ", ");
// if page can't be viewed, don't grant edit permissions // If page can't be viewed, don't grant edit permissions to do - implement can_view_multiple(), so this can
// to do - implement can_view_multiple(), so this can be enabled // be enabled
//$ids = array_keys(array_filter(self::can_view_multiple($ids, $memberID))); //$ids = array_keys(array_filter(self::can_view_multiple($ids, $memberID)));
// Get the groups that the given member belongs to // Get the groups that the given member belongs to
@ -1221,7 +1211,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$table = ($stage=='Stage') ? "SiteTree" : "SiteTree_$stage"; $table = ($stage=='Stage') ? "SiteTree" : "SiteTree_$stage";
$result = array_fill_keys( $result = array_fill_keys(
($ids) ? DB::query("SELECT \"ID\" FROM \"$table\" WHERE \"ID\" IN (".implode(", ", $ids).")")->column() : array(), ($ids) ? DB::query("SELECT \"ID\" FROM \"$table\" WHERE \"ID\" IN (".implode(", ", $ids).")")->column() : array(),
false false
); );
@ -1242,15 +1232,16 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
AND \"SiteTree\".\"ID\" IN ($SQL_idList)"); AND \"SiteTree\".\"ID\" IN ($SQL_idList)");
if($potentiallyInherited) { if($potentiallyInherited) {
// Group $potentiallyInherited by ParentID; we'll look at the permission of all those // Group $potentiallyInherited by ParentID; we'll look at the permission of all those parents and
// parents and then see which ones the user has permission on // then see which ones the user has permission on
$groupedByParent = array(); $groupedByParent = array();
foreach($potentiallyInherited as $item) { foreach($potentiallyInherited as $item) {
if($item->ParentID) { if($item->ParentID) {
if(!isset($groupedByParent[$item->ParentID])) $groupedByParent[$item->ParentID] = array(); if(!isset($groupedByParent[$item->ParentID])) $groupedByParent[$item->ParentID] = array();
$groupedByParent[$item->ParentID][] = $item->ID; $groupedByParent[$item->ParentID][] = $item->ID;
} else { } else {
// Might return different site config based on record context, e.g. when subsites module is used // Might return different site config based on record context, e.g. when subsites module
// is used
$siteConfig = $item->getSiteConfig(); $siteConfig = $item->getSiteConfig();
$result[$item->ID] = $siteConfig->{$siteConfigMethod}($memberID); $result[$item->ID] = $siteConfig->{$siteConfigMethod}($memberID);
} }
@ -1283,15 +1274,15 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return array(); return array();
} }
} }
/** /**
* Get the 'can edit' information for a number of SiteTree pages. * Get the 'can edit' information for a number of SiteTree pages.
* *
* @param array $ids An array of IDs of the SiteTree pages to look up. * @param array $ids An array of IDs of the SiteTree pages to look up
* @param int $memberID ID of member. * @param int $memberID ID of member
* @param bool $useCached Return values from the permission cache if they exist. * @param bool $useCached Return values from the permission cache if they exist
* @return array A map where the IDs are keys and the values are booleans stating whether the given * @return array A map where the IDs are keys and the values are booleans stating whether the given page can be
* page can be edited. * edited
*/ */
static public function can_edit_multiple($ids, $memberID, $useCached = true) { static public function can_edit_multiple($ids, $memberID, $useCached = true) {
return self::batch_permission_check($ids, $memberID, 'CanEditType', 'SiteTree_EditorGroups', 'canEditPages', null, $useCached); return self::batch_permission_check($ids, $memberID, 'CanEditType', 'SiteTree_EditorGroups', 'canEditPages', null, $useCached);
@ -1299,9 +1290,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Get the 'can edit' information for a number of SiteTree pages. * Get the 'can edit' information for a number of SiteTree pages.
* @param array $ids An array of IDs of the SiteTree pages to look up. *
* @param int $memberID ID of member. * @param array $ids An array of IDs of the SiteTree pages to look up
* @param bool $useCached Return values from the permission cache if they exist. * @param int $memberID ID of member
* @param bool $useCached Return values from the permission cache if they exist
* @return array * @return array
*/ */
static public function can_delete_multiple($ids, $memberID, $useCached = true) { static public function can_delete_multiple($ids, $memberID, $useCached = true) {
@ -1358,23 +1350,19 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$deletable = array(); $deletable = array();
} }
// Convert the array of deletable IDs into a map of the original IDs with true/false as the // Convert the array of deletable IDs into a map of the original IDs with true/false as the value
// value
return array_fill_keys($deletable, true) + array_fill_keys($ids, false); return array_fill_keys($deletable, true) + array_fill_keys($ids, false);
} }
/** /**
* Collate selected descendants of this page. * Collate selected descendants of this page.
* *
* {@link $condition} will be evaluated on each descendant, and if it is * {@link $condition} will be evaluated on each descendant, and if it is succeeds, that item will be added to the
* succeeds, that item will be added to the $collator array. * $collator array.
* *
* @param string $condition The PHP condition to be evaluated. The page * @param string $condition The PHP condition to be evaluated. The page will be called $item
* will be called $item * @param array $collator An array, passed by reference, to collect all of the matching descendants.
* @param array $collator An array, passed by reference, to collect all * @return bool
* of the matching descendants.
* @return true|void
*/ */
public function collateDescendants($condition, &$collator) { public function collateDescendants($condition, &$collator) {
if($children = $this->Children()) { if($children = $this->Children()) {
@ -1386,13 +1374,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
} }
/** /**
* Return the title, description, keywords and language metatags. * Return the title, description, keywords and language metatags.
* *
* @todo Move <title> tag in separate getter for easier customization and more obvious usage * @todo Move <title> tag in separate getter for easier customization and more obvious usage
* *
* @param boolean|string $includeTitle Show default <title>-tag, set to false for custom templating * @param bool $includeTitle Show default <title>-tag, set to false for custom templating
* @return string The XHTML metatags * @return string The XHTML metatags
*/ */
public function MetaTags($includeTitle = true) { public function MetaTags($includeTitle = true) {
@ -1429,29 +1416,23 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $tags; return $tags;
} }
/** /**
* Returns the object that contains the content that a user would * Returns the object that contains the content that a user would associate with this page.
* associate with this page.
* *
* Ordinarily, this is just the page itself, but for example on * Ordinarily, this is just the page itself, but for example on RedirectorPages or VirtualPages ContentSource() will
* RedirectorPages or VirtualPages ContentSource() will return the page * return the page that is linked to.
* that is linked to.
* *
* @return SiteTree The content source. * @return $this
*/ */
public function ContentSource() { public function ContentSource() {
return $this; return $this;
} }
/** /**
* Add default records to database. * Add default records to database.
* *
* This function is called whenever the database is built, after the * This function is called whenever the database is built, after the database tables have all been created. Overload
* database tables have all been created. Overload this to add default * this to add default records when the database is built, but make sure you call parent::requireDefaultRecords().
* records when the database is built, but make sure you call
* parent::requireDefaultRecords().
*/ */
public function requireDefaultRecords() { public function requireDefaultRecords() {
parent::requireDefaultRecords(); parent::requireDefaultRecords();
@ -1503,9 +1484,6 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
} }
//------------------------------------------------------------------------------------//
protected function onBeforeWrite() { protected function onBeforeWrite() {
parent::onBeforeWrite(); parent::onBeforeWrite();
@ -1540,10 +1518,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$fieldsIgnoredByVersioning = array('HasBrokenLink', 'Status', 'HasBrokenFile', 'ToDo', 'VersionID', 'SaveCount'); $fieldsIgnoredByVersioning = array('HasBrokenLink', 'Status', 'HasBrokenFile', 'ToDo', 'VersionID', 'SaveCount');
$changedFields = array_keys($this->getChangedFields(true, 2)); $changedFields = array_keys($this->getChangedFields(true, 2));
// This more rigorous check is inline with the test that write() // This more rigorous check is inline with the test that write() does to dedcide whether or not to write to the
// does to dedcide whether or not to write to the DB. We use that // DB. We use that to avoid cluttering the system with a migrateVersion() call that doesn't get used
// to avoid cluttering the system with a migrateVersion() call
// that doesn't get used
$oneChangedFields = array_keys($this->getChangedFields(true, 1)); $oneChangedFields = array_keys($this->getChangedFields(true, 1));
if($oneChangedFields && !array_diff($changedFields, $fieldsIgnoredByVersioning)) { if($oneChangedFields && !array_diff($changedFields, $fieldsIgnoredByVersioning)) {
@ -1587,7 +1563,6 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
} }
public function onAfterDelete() { public function onAfterDelete() {
// Need to flush cache to avoid outdated versionnumber references // Need to flush cache to avoid outdated versionnumber references
$this->flushCache(); $this->flushCache();
@ -1646,11 +1621,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Returns TRUE if this object has a URLSegment value that does not conflict with any other objects. This methods * Returns true if this object has a URLSegment value that does not conflict with any other objects. This method
* checks for: * checks for:
* - A page with the same URLSegment that has a conflict. * - A page with the same URLSegment that has a conflict
* - Conflicts with actions on the parent page. * - Conflicts with actions on the parent page
* - A conflict caused by a root page having the same URLSegment as a class name. * - A conflict caused by a root page having the same URLSegment as a class name
* *
* @return bool * @return bool
*/ */
@ -1695,13 +1670,13 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Generate a URL segment based on the title provided. * Generate a URL segment based on the title provided.
* *
* If {@link Extension}s wish to alter URL segment generation, they can do so by defining * If {@link Extension}s wish to alter URL segment generation, they can do so by defining
* updateURLSegment(&$url, $title). $url will be passed by reference and should be modified. * updateURLSegment(&$url, $title). $url will be passed by reference and should be modified. $title will contain
* $title will contain the title that was originally used as the source of this generated URL. * the title that was originally used as the source of this generated URL. This lets extensions either start from
* This lets extensions either start from scratch, or incrementally modify the generated URL. * scratch, or incrementally modify the generated URL.
* *
* @param string $title Page title. * @param string $title Page title
* @return string Generated url segment * @return string Generated url segment
*/ */
public function generateURLSegment($title){ public function generateURLSegment($title){
@ -1718,6 +1693,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Gets the URL segment for the latest draft version of this page.
*
* @return string * @return string
*/ */
public function getStageURLSegment() { public function getStageURLSegment() {
@ -1730,6 +1707,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Gets the URL segment for the currently published version of this page.
*
* @return string * @return string
*/ */
public function getLiveURLSegment() { public function getLiveURLSegment() {
@ -1742,8 +1721,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Rewrite a file URL on this page, after its been renamed. * Rewrite a file URL on this page, after its been renamed. Triggers the onRenameLinkedAsset action on extensions.
* Triggers the onRenameLinkedAsset action on extensions.
*/ */
public function rewriteFileURL($old, $new) { public function rewriteFileURL($old, $new) {
$fields = $this->inheritedDatabaseFields(); $fields = $this->inheritedDatabaseFields();
@ -1776,8 +1754,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Returns the pages that depend on this page. * Returns the pages that depend on this page. This includes virtual pages, pages that link to it, etc.
* This includes virtual pages, pages that link to it, etc.
* *
* @param bool $includeVirtuals Set to false to exlcude virtual pages. * @param bool $includeVirtuals Set to false to exlcude virtual pages.
* @return ArrayList * @return ArrayList
@ -1844,7 +1821,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Return all virtual pages that link to this page * Return all virtual pages that link to this page.
*
* @return DataList
*/ */
public function VirtualPages() { public function VirtualPages() {
if(!$this->ID) return null; if(!$this->ID) return null;
@ -1860,14 +1839,13 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Returns a FieldList with which to create the main editing form. * Returns a FieldList with which to create the main editing form.
* *
* You can override this in your child classes to add extra fields - first * You can override this in your child classes to add extra fields - first get the parent fields using
* get the parent fields using parent::getCMSFields(), then use * parent::getCMSFields(), then use addFieldToTab() on the FieldList.
* addFieldToTab() on the FieldList.
*
* See {@link getSettingsFields()} for a different set of fields
* concerned with configuration aspects on the record, e.g. access control
* *
* @return FieldList The fields to be displayed in the CMS. * See {@link getSettingsFields()} for a different set of fields concerned with configuration aspects on the record,
* e.g. access control.
*
* @return FieldList The fields to be displayed in the CMS
*/ */
public function getCMSFields() { public function getCMSFields() {
require_once("forms/Form.php"); require_once("forms/Form.php");
@ -2048,8 +2026,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Returns fields related to configuration aspects on this record, e.g. access control. * Returns fields related to configuration aspects on this record, e.g. access control. See {@link getCMSFields()}
* See {@link getCMSFields()} for content-related fields. * for content-related fields.
* *
* @return FieldList * @return FieldList
*/ */
@ -2108,10 +2086,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$visibility->setTitle($this->fieldLabel('Visibility')); $visibility->setTitle($this->fieldLabel('Visibility'));
/*
* This filter ensures that the ParentID dropdown selection does not show this node, // This filter ensures that the ParentID dropdown selection does not show this node,
* or its descendents, as this causes vanishing bugs. // or its descendents, as this causes vanishing bugs
*/
$parentIDField->setFilterFunction(create_function('$node', "return \$node->ID != {$this->ID};")); $parentIDField->setFilterFunction(create_function('$node', "return \$node->ID != {$this->ID};"));
$parentTypeSelector->addExtraClass('parentTypeSelector'); $parentTypeSelector->addExtraClass('parentTypeSelector');
@ -2164,9 +2141,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* * @param bool $includerelations A boolean value to indicate if the labels returned should include relation fields
* @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields * @return array
* @return array|string
*/ */
public function fieldLabels($includerelations = true) { public function fieldLabels($includerelations = true) {
$cacheKey = $this->class . '_' . $includerelations; $cacheKey = $this->class . '_' . $includerelations;
@ -2207,17 +2183,15 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return self::$_cache_field_labels[$cacheKey]; return self::$_cache_field_labels[$cacheKey];
} }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** /**
* Get the actions available in the CMS for this page - eg Save, Publish. * Get the actions available in the CMS for this page - eg Save, Publish.
* *
* Frontend scripts and styles know how to handle the following FormFields: * Frontend scripts and styles know how to handle the following FormFields:
* * top-level FormActions appear as standalone buttons * - top-level FormActions appear as standalone buttons
* * top-level CompositeField with FormActions within appear as grouped buttons * - top-level CompositeField with FormActions within appear as grouped buttons
* * TabSet & Tabs appear as a drop ups * - TabSet & Tabs appear as a drop ups
* * FormActions within the Tab are restyled as links * - FormActions within the Tab are restyled as links
* * major actions can provide alternate states for richer presentation (see ssui.button widget extension). * - major actions can provide alternate states for richer presentation (see ssui.button widget extension)
* *
* @return FieldList The available actions for this page. * @return FieldList The available actions for this page.
*/ */
@ -2452,7 +2426,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Restore the content in the active copy of this SiteTree page to the stage site. * Restore the content in the active copy of this SiteTree page to the stage site.
* @return The SiteTree object. *
* @return self
*/ */
public function doRestoreToStage() { public function doRestoreToStage() {
// if no record can be found on draft stage (meaning it has been "deleted from draft" before), // if no record can be found on draft stage (meaning it has been "deleted from draft" before),
@ -2490,17 +2465,14 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Check if this page is new - that is, if it has yet to have been written * Check if this page is new - that is, if it has yet to have been written to the database.
* to the database.
* *
* @return boolean True if this page is new. * @return bool
*/ */
public function isNew() { public function isNew() {
/** /**
* This check was a problem for a self-hosted site, and may indicate a * This check was a problem for a self-hosted site, and may indicate a bug in the interpreter on their server,
* bug in the interpreter on their server, or a bug here * or a bug here. Changing the condition from empty($this->ID) to !$this->ID && !$this->record['ID'] fixed this.
* Changing the condition from empty($this->ID) to
* !$this->ID && !$this->record['ID'] fixed this.
*/ */
if(empty($this->ID)) return true; if(empty($this->ID)) return true;
@ -2513,7 +2485,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Check if this page has been published. * Check if this page has been published.
* *
* @return boolean True if this page has been published. * @return bool
*/ */
public function isPublished() { public function isPublished() {
if($this->isNew()) if($this->isNew())
@ -2525,10 +2497,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Get the class dropdown used in the CMS to change the class of a page. * Get the class dropdown used in the CMS to change the class of a page. This returns the list of options in the
* This returns the list of options in the drop as a Map from class name * dropdown as a Map from class name to singular name. Filters by {@link SiteTree->canCreate()}, as well as
* to text in dropdown. Filters by {@link SiteTree->canCreate()}, * {@link SiteTree::$needs_permission}.
* as well as {@link SiteTree::$needs_permission}.
* *
* @return array * @return array
*/ */
@ -2541,7 +2512,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
foreach($classes as $class) { foreach($classes as $class) {
$instance = singleton($class); $instance = singleton($class);
// if the current page type is this the same as the class type always show the page type in the list see open ticket 5880 for why // if the current page type is this the same as the class type always show the page type in the list
if ($this->ClassName != $instance->ClassName) { if ($this->ClassName != $instance->ClassName) {
if((($instance instanceof HiddenClass) || !$instance->canCreate())) continue; if((($instance instanceof HiddenClass) || !$instance->canCreate())) continue;
} }
@ -2555,10 +2526,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$currentClass = $class; $currentClass = $class;
$result[$class] = $pageTypeName; $result[$class] = $pageTypeName;
// if we're in translation mode, the link between the translated pagetype // If we're in translation mode, the link between the translated pagetype title and the actual classname
// title and the actual classname might not be obvious, so we add it in parantheses // might not be obvious, so we add it in parantheses. Example: class "RedirectorPage" has the title
// Example: class "RedirectorPage" has the title "Weiterleitung" in German, // "Weiterleitung" in German, so it shows up as "Weiterleitung (RedirectorPage)"
// so it shows up as "Weiterleitung (RedirectorPage)"
if(i18n::get_lang_from_locale(i18n::get_locale()) != 'en') { if(i18n::get_lang_from_locale(i18n::get_locale()) != 'en') {
$result[$class] = $result[$class] . " ({$class})"; $result[$class] = $result[$class] . " ({$class})";
} }
@ -2577,20 +2547,18 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $result; return $result;
} }
/** /**
* Returns an array of the class names of classes that are allowed * Returns an array of the class names of classes that are allowed to be children of this class.
* to be children of this class.
* *
* @return array * @return string[]
*/ */
public function allowedChildren() { public function allowedChildren() {
$allowedChildren = array(); $allowedChildren = array();
$candidates = $this->stat('allowed_children'); $candidates = $this->stat('allowed_children');
if($candidates && $candidates != "none" && $candidates != "SiteTree_root") { if($candidates && $candidates != "none" && $candidates != "SiteTree_root") {
foreach($candidates as $candidate) { foreach($candidates as $candidate) {
// If a classname is prefixed by "*", such as "*Page", then only that // If a classname is prefixed by "*", such as "*Page", then only that class is allowed - no subclasses.
// class is allowed - no subclasses. Otherwise, the class and all its subclasses are allowed. // Otherwise, the class and all its subclasses are allowed.
if(substr($candidate,0,1) == '*') { if(substr($candidate,0,1) == '*') {
$allowedChildren[] = substr($candidate,1); $allowedChildren[] = substr($candidate,1);
} else { } else {
@ -2605,7 +2573,6 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $allowedChildren; return $allowedChildren;
} }
/** /**
* Returns the class name of the default class for children of this page. * Returns the class name of the default class for children of this page.
* *
@ -2621,10 +2588,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
} }
/** /**
* Returns the class name of the default class for the parent of this * Returns the class name of the default class for the parent of this page.
* page.
* *
* @return string * @return string
*/ */
@ -2633,8 +2598,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Get the title for use in menus for this page. If the MenuTitle * Get the title for use in menus for this page. If the MenuTitle field is set it returns that, else it returns the
* field is set it returns that, else it returns the Title field. * Title field.
* *
* @return string * @return string
*/ */
@ -2661,19 +2626,18 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* A flag provides the user with additional data about the current page status, * A flag provides the user with additional data about the current page status, for example a "removed from draft"
* for example a "removed from draft" status. Each page can have more than one status flag. * status. Each page can have more than one status flag. Returns a map of a unique key to a (localized) title for
* Returns a map of a unique key to a (localized) title for the flag. * the flag. The unique key can be reused as a CSS class. Use the 'updateStatusFlags' extension point to customize
* The unique key can be reused as a CSS class. * the flags.
* Use the 'updateStatusFlags' extension point to customize the flags.
* *
* Example (simple): * Example (simple):
* "deletedonlive" => "Deleted" * "deletedonlive" => "Deleted"
* *
* Example (with optional title attribute): * Example (with optional title attribute):
* "deletedonlive" => array('text' => "Deleted", 'title' => 'This page has been deleted') * "deletedonlive" => array('text' => "Deleted", 'title' => 'This page has been deleted')
* *
* @param Boolean $cached * @param bool $cached Whether to serve the fields from cache; false regenerate them
* @return array * @return array
*/ */
public function getStatusFlags($cached = true) { public function getStatusFlags($cached = true) {
@ -2712,11 +2676,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* getTreeTitle will return three <span> html DOM elements, an empty <span> with * getTreeTitle will return three <span> html DOM elements, an empty <span> with the class 'jstree-pageicon' in
* the class 'jstree-pageicon' in front, following by a <span> wrapping around its * front, following by a <span> wrapping around its MenutTitle, then following by a <span> indicating its
* MenutTitle, then following by a <span> indicating its publication status. * publication status.
* *
* @return string a html string ready to be directly used in a template * @return string An HTML string ready to be directly used in a template
*/ */
public function getTreeTitle() { public function getTreeTitle() {
// Build the list of candidate children // Build the list of candidate children
@ -2749,8 +2713,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Returns the page in the current page stack of the given level. * Returns the page in the current page stack of the given level. Level(1) will return the main menu item that
* Level(1) will return the main menu item that we're currently inside, etc. * we're currently inside, etc.
*
* @param int $level
* @return SiteTree
*/ */
public function Level($level) { public function Level($level) {
$parent = $this; $parent = $this;
@ -2763,7 +2730,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Return the CSS classes to apply to this node in the CMS tree * Return the CSS classes to apply to this node in the CMS tree.
* *
* @param string $numChildrenMethod * @param string $numChildrenMethod
* @return string * @return string
@ -2801,11 +2768,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Compares current draft with live version, * Compares current draft with live version, and returns true if no draft version of this page exists but the page
* and returns TRUE if no draft version of this page exists, * is still published (eg, after triggering "Delete from draft site" in the CMS).
* but the page is still published (after triggering "Delete from draft site" in the CMS).
* *
* @return boolean * @return bool
*/ */
public function getIsDeletedFromStage() { public function getIsDeletedFromStage() {
if(!$this->ID) return true; if(!$this->ID) return true;
@ -2813,26 +2779,27 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID); $stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID);
// Return true for both completely deleted pages and for pages just deleted from stage. // Return true for both completely deleted pages and for pages just deleted from stage
return !($stageVersion); return !($stageVersion);
} }
/** /**
* Return true if this page exists on the live site * Return true if this page exists on the live site
*
* @return bool
*/ */
public function getExistsOnLive() { public function getExistsOnLive() {
return (bool)Versioned::get_versionnumber_by_stage('SiteTree', 'Live', $this->ID); return (bool)Versioned::get_versionnumber_by_stage('SiteTree', 'Live', $this->ID);
} }
/** /**
* Compares current draft with live version, * Compares current draft with live version, and returns true if these versions differ, meaning there have been
* and returns TRUE if these versions differ, * unpublished changes to the draft site.
* meaning there have been unpublished changes to the draft site.
* *
* @return boolean * @return bool
*/ */
public function getIsModifiedOnStage() { public function getIsModifiedOnStage() {
// new unsaved pages could be never be published // New unsaved pages could be never be published
if($this->isNew()) return false; if($this->isNew()) return false;
$stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID); $stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID);
@ -2845,14 +2812,13 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Compares current draft with live version, * Compares current draft with live version, and returns true if no live version exists, meaning the page was never
* and returns true if no live version exists, * published.
* meaning the page was never published.
* *
* @return boolean * @return bool
*/ */
public function getIsAddedToStage() { public function getIsAddedToStage() {
// new unsaved pages could be never be published // New unsaved pages could be never be published
if($this->isNew()) return false; if($this->isNew()) return false;
$stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID); $stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID);
@ -2862,18 +2828,16 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Stops extendCMSFields() being called on getCMSFields(). * Stops extendCMSFields() being called on getCMSFields(). This is useful when you need access to fields added by
* This is useful when you need access to fields added by subclasses * subclasses of SiteTree in a extension. Call before calling parent::getCMSFields(), and reenable afterwards.
* of SiteTree in a extension. Call before calling parent::getCMSFields(),
* and reenable afterwards.
*/ */
static public function disableCMSFieldsExtensions() { static public function disableCMSFieldsExtensions() {
self::$runCMSFieldsExtensions = false; self::$runCMSFieldsExtensions = false;
} }
/** /**
* Reenables extendCMSFields() being called on getCMSFields() after * Reenables extendCMSFields() being called on getCMSFields() after it has been disabled by
* it has been disabled by disableCMSFieldsExtensions(). * disableCMSFieldsExtensions().
*/ */
static public function enableCMSFieldsExtensions() { static public function enableCMSFieldsExtensions() {
self::$runCMSFieldsExtensions = true; self::$runCMSFieldsExtensions = true;
@ -2915,9 +2879,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Return the translated Singular name * Return the translated Singular name.
* *
* @return String * @return string
*/ */
public function i18n_singular_name() { public function i18n_singular_name() {
// Convert 'Page' to 'SiteTree' for correct localization lookups // Convert 'Page' to 'SiteTree' for correct localization lookups
@ -2926,8 +2890,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
/** /**
* Overloaded to also provide entities for 'Page' class which is usually * Overloaded to also provide entities for 'Page' class which is usually located in custom code, hence textcollector
* located in custom code, hence textcollector picks it up for the wrong folder. * picks it up for the wrong folder.
*
* @return array
*/ */
public function provideI18nEntities() { public function provideI18nEntities() {
$entities = parent::provideI18nEntities(); $entities = parent::provideI18nEntities();
@ -2945,12 +2911,20 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $entities; return $entities;
} }
/**
* Returns 'root' if the current page has no parent, or 'subpage' otherwise
*
* @return string
*/
public function getParentType() { public function getParentType() {
return $this->ParentID == 0 ? 'root' : 'subpage'; return $this->ParentID == 0 ? 'root' : 'subpage';
} }
static public function reset() { /**
* Clear the permissions cache for SiteTree
*/
public static function reset() {
self::$cache_permissions = array(); self::$cache_permissions = array();
} }

View File

@ -1,12 +1,19 @@
<?php <?php
/** /**
* Adds tracking of links in any HTMLText fields which reference SiteTree or File items * Adds tracking of links in any HTMLText fields which reference SiteTree or File items.
* *
* Attaching this to any DataObject will add four fields which contain all links to SiteTree and File items * Attaching this to any DataObject will add four fields which contain all links to SiteTree and File items
* referenced in any HTMLText fields, and two booleans to indicate if there are any broken links * referenced in any HTMLText fields, and two booleans to indicate if there are any broken links. Call
* augmentSyncLinkTracking to update those fields with any changes to those fields.
* *
* Call augmentSyncLinkTracking to update those fields with any changes to those fields * @property SiteTree owner
*
* @property bool HasBrokenFile
* @property bool HasBrokenLink
*
* @method ManyManyList LinkTracking List of site pages linked on this page.
* @method ManyManyList ImageTracking List of Images linked on this page.
*/ */
class SiteTreeLinkTracking extends DataExtension { class SiteTreeLinkTracking extends DataExtension {
@ -25,6 +32,11 @@ class SiteTreeLinkTracking extends DataExtension {
"ImageTracking" => array("FieldName" => "Varchar") "ImageTracking" => array("FieldName" => "Varchar")
); );
/**
* Scrape the content of a field to detect anly links to local SiteTree pages or files
*
* @param string $field The name of the field on {@link @owner} to scrape
*/
function trackLinksInField($field) { function trackLinksInField($field) {
$record = $this->owner; $record = $this->owner;
@ -102,7 +114,9 @@ class SiteTreeLinkTracking extends DataExtension {
} }
} }
/**
* Find HTMLText fields on {@link owner} to scrape for links that need tracking
*/
function augmentSyncLinkTracking() { function augmentSyncLinkTracking() {
// Reset boolean broken flags // Reset boolean broken flags
$this->owner->HasBrokenLink = false; $this->owner->HasBrokenLink = false;
@ -122,4 +136,4 @@ class SiteTreeLinkTracking extends DataExtension {
foreach($htmlFields as $field) $this->trackLinksInField($field); foreach($htmlFields as $field) $this->trackLinksInField($field);
} }
} }