2007-07-19 12:40:05 +02:00
< ? php
/**
* The main " content " area of the CMS .
* This class creates a 2 - frame layout - left - tree and right - form - to sit beneath the main
* admin menu .
2008-06-15 15:33:53 +02:00
*
2008-02-25 03:10:37 +01:00
* @ package cms
* @ subpackage content
2007-07-19 12:40:05 +02:00
* @ todo Create some base classes to contain the generic functionality that will be replicated .
*/
class CMSMain extends LeftAndMain implements CurrentPageIdentifier , PermissionProvider {
2008-02-20 10:41:33 +01:00
2008-11-02 22:27:55 +01:00
static $url_segment = '' ;
static $url_rule = '/$Action/$ID/$OtherID' ;
// Maintain a lower priority than other administration sections
// so that Director does not think they are actions of CMSMain
static $url_priority = 40 ;
static $menu_title = 'Site Content' ;
static $menu_priority = 10 ;
2007-07-19 12:40:05 +02:00
static $tree_class = " SiteTree " ;
2007-09-27 22:56:55 +02:00
2007-07-19 12:40:05 +02:00
static $subitem_class = " Member " ;
2007-09-27 22:56:55 +02:00
2008-02-25 03:10:37 +01:00
static $allowed_actions = array (
'addmember' ,
'addpage' ,
'buildbrokenlinks' ,
'canceldraftchangesdialog' ,
'compareversions' ,
'createtranslation' ,
'delete' ,
'deletefromlive' ,
'deleteitems' ,
2009-01-06 03:18:33 +01:00
'DeleteItemsForm' ,
2008-02-25 03:10:37 +01:00
'dialog' ,
'duplicate' ,
'duplicatewithchildren' ,
'getpagecount' ,
'getversion' ,
'publishall' ,
'publishitems' ,
2009-01-06 03:18:33 +01:00
'PublishItemsForm' ,
2009-05-01 00:47:28 +02:00
'restore' ,
2008-02-25 03:10:37 +01:00
'revert' ,
'rollback' ,
'sidereport' ,
'submit' ,
'unpublish' ,
'versions' ,
2008-08-09 05:54:55 +02:00
'EditForm' ,
'AddPageOptionsForm' ,
2008-09-25 16:50:33 +02:00
'SiteTreeAsUL' ,
2009-05-14 08:11:18 +02:00
'getshowdeletedsubtree' ,
'getfilteredsubtree' ,
'batchactions'
2008-02-25 03:10:37 +01:00
);
2007-09-16 17:19:17 +02:00
/**
* SiteTree Columns that can be filtered using the the Site Tree Search button
*/
2007-09-27 22:56:55 +02:00
static $site_tree_filter_options = array (
2009-04-29 03:44:28 +02:00
'Title' => array ( 'CMSMain.TITLE' , 'Title' ),
'MenuTitle' => array ( 'CMSMain.MENUTITLE' , 'Navigation Label' ),
2007-11-07 00:28:54 +01:00
'ClassName' => array ( 'CMSMain.PAGETYPE' , 'Page Type' ),
'Status' => array ( 'CMSMain.STATUS' , 'Status' ),
'MetaDescription' => array ( 'CMSMain.METADESC' , 'Description' ),
'MetaKeywords' => array ( 'CMSMain.METAKEYWORDS' , 'Keywords' )
2007-09-27 22:56:55 +02:00
);
2007-11-07 07:05:52 +01:00
static function T_SiteTreeFilterOptions (){
return array (
2009-04-29 03:44:28 +02:00
'Title' => _t ( 'CMSMain.TITLEOPT' , 'Title' , 0 , 'The dropdown title in CMSMain left SiteTreeFilterOptions' ),
'MenuTitle' => _t ( 'CMSMain.MENUTITLEOPT' , 'Navigation Label' , 0 , 'The dropdown title in CMSMain left SiteTreeFilterOptions' ),
2007-11-07 07:05:52 +01:00
'Status' => _t ( 'CMSMain.STATUSOPT' , 'Status' , 0 , " The dropdown title in CMSMain left SiteTreeFilterOptions " ),
'MetaDescription' => _t ( 'CMSMain.METADESCOPT' , 'Description' , 0 , " The dropdown title in CMSMain left SiteTreeFilterOptions " ),
2009-04-29 03:44:28 +02:00
'MetaKeywords' => _t ( 'CMSMain.METAKEYWORDSOPT' , 'Keywords' , 0 , " The dropdown title in CMSMain left SiteTreeFilterOptions " )
2007-11-07 07:05:52 +01:00
);
}
2009-05-14 08:11:18 +02:00
2007-07-19 12:40:05 +02:00
public function init () {
parent :: init ();
2008-11-10 02:47:13 +01:00
2009-03-20 09:49:27 +01:00
// Locale" attribute is either explicitly added by LeftAndMain Javascript logic,
Merged, debugged and enhanced Translatable patches from branches/translatable at r64523, r64523, 64523, thanks wakeless!
API CHANGE Changed Translatable schema from auxilliary tables (SiteTree_lang, SiteTree_lang_Live) to automatically filtered records on the original table (SiteTree, SiteTree_Live), using $Lang and $OriginalID properties. Incompatible update to old schema, migration script is in the works.
API CHANGE Removed Translatable::get_one(), Translatable::write()
ENHANCEMENT Simplified Translatable tree generation by using getSiteTreeFor() in CMSMain->createtranslation()
ENHANCEMENT Added AllChildrenIncludingDeleted(), augmentNumChildrenCountQuery(), augmentAllChildrenIncludingDeleted(), augmentStageChildren() to Translatable class to allow for more stable tree generation.
ENHANCEMENT Moved definition of Translatable schema from augmentDatabase() to Translatable->extraStatics()
ENHANCEMENT Changes to the CMS language selection refresh the whole admin interface instead of the tree only. This way we can add a URL parameter ?lang=<lang> to /admin, which makes the specific language bookmarkable and reloadable. Changes to LangSelector.js
ENHANCEMENT Added fallback to ModelAsController->getNestedController() to fetch page with matching URLSegment but different language in case no page is found in the current language.
ENHANCEMENT Added helper methods to Translatable: getTranslation(), hasTranslation(), isTranslation(), findOriginalIDs()
ENHANCEMENT Getters and setters for Translatable->getOriginalPage() etc.
ENHANCEMENT Hooking Translatable into ModelAsController and ContentController initialization in order to call choose_site_lang()
ENHANCEMENT Simplified Translatable->augmentSQL(), augmentWrite() by not using auxilliary tables
ENHANCEMENT Showing clickable links for Translations in Translatable->updateCMSFields()
BUGFIX Modifying Hierarchy/SiteTree Children getters to accept optional "context" which can be used to set a language explicitly through the $Lang property, rather than implicitly reyling on the static Translatable::current_lang()
BUGFIX Fixed TranslatableTest to work with new datamodel
BUGFIX Temporarily disabled cookie/session selection in Translatable::choose_site_lang() until we have a good test suite for the side effects.
MINOR Added "untranslated" CSS styles to tree nodes and marking them as inactive/grey
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@69959 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-01-10 13:15:30 +01:00
// or implied on a translated record (see {@link Translatable->updateCMSFields()}).
2009-07-13 23:11:03 +02:00
// $Lang serves as a "context" which can be inspected by Translatable - hence it
// has the same name as the database property on Translatable.
if ( $this -> getRequest () -> requestVar ( " Locale " )) {
$this -> Locale = $this -> getRequest () -> requestVar ( " Locale " );
} elseif ( $this -> getRequest () -> requestVar ( " locale " )) {
$this -> Locale = $this -> getRequest () -> requestVar ( " locale " );
2008-11-10 02:47:13 +01:00
} else {
2009-07-13 23:11:03 +02:00
$this -> Locale = Translatable :: default_locale ();
2008-11-10 02:47:13 +01:00
}
2009-07-13 23:11:03 +02:00
Translatable :: set_current_locale ( $this -> Locale );
// collect languages for TinyMCE spellchecker plugin.
// see http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker
$lang = i18n :: get_lang_from_locale ( $this -> Locale );
$langName = i18n :: get_locale_name ( $this -> Locale );
HtmlEditorConfig :: get ( 'cms' ) -> setOption ( 'spellchecker_languages' , " + { $langName } = { $lang } " );
2009-05-18 02:23:52 +02:00
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: javascript ( CMS_DIR . '/javascript/CMSMain.js' );
Requirements :: javascript ( CMS_DIR . '/javascript/CMSMain_left.js' );
Requirements :: javascript ( CMS_DIR . '/javascript/CMSMain_right.js' );
2007-07-19 12:40:05 +02:00
}
2008-06-24 05:22:39 +02:00
/**
* If this is set to true , the " switchView " context in the
* template is shown , with links to the staging and publish site .
*
* @ return boolean
*/
function ShowSwitchView () {
return true ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
//------------------------------------------------------------------------------------------//
// Main controllers
//------------------------------------------------------------------------------------------//
// Main UI components
2007-09-15 23:54:24 +02:00
2008-11-18 02:48:50 +01:00
/**
* Override { @ link LeftAndMain } Link to allow blank URL segment for CMSMain .
*
* @ return string
*/
public function Link ( $action = null ) {
return Controller :: join_links (
$this -> stat ( 'url_base' , true ),
$this -> stat ( 'url_segment' , true ), // in case we want to change the segment
'/' , // trailing slash needed if $action is null!
" $action "
);
}
2007-07-19 12:40:05 +02:00
/**
* Return the entire site tree as a nested set of ULs
*/
public function SiteTreeAsUL () {
$this -> generateDataTreeHints ();
$this -> generateTreeStylingJS ();
2007-09-15 23:54:24 +02:00
2009-02-03 03:50:25 +01:00
// Pre-cache sitetree version numbers for querying efficiency
Versioned :: prepopulate_versionnumber_cache ( " SiteTree " , " Stage " );
Versioned :: prepopulate_versionnumber_cache ( " SiteTree " , " Live " );
2007-07-19 12:40:05 +02:00
return $this -> getSiteTreeFor ( " SiteTree " );
}
2009-08-04 05:09:26 +02:00
2009-05-01 00:47:28 +02:00
/**
2009-08-04 05:09:26 +02:00
* Use a CMSSiteTreeFilter to only get certain nodes
*
* @ return string
2009-05-01 00:47:28 +02:00
*/
2009-05-14 08:11:18 +02:00
public function getfilteredsubtree () {
2009-08-04 05:09:26 +02:00
// Sanity and security checks
if ( ! isset ( $_REQUEST [ 'filter' ])) die ( 'No filter passed' );
if ( ! ClassInfo :: exists ( $_REQUEST [ 'filter' ])) die ( 'That filter class does not exist' );
if ( ! is_subclass_of ( $_REQUEST [ 'filter' ], 'CMSSiteTreeFilter' )) die ( 'That is not a valid filter' );
2009-05-14 08:11:18 +02:00
2009-08-04 05:09:26 +02:00
// Do eeet!
$filter = new $_REQUEST [ 'filter' ]();
return $filter -> getTree ();
}
/**
* Returns a list of batch actions
*/
function SiteTreeFilters () {
$filters = ClassInfo :: subclassesFor ( 'CMSSiteTreeFilter' );
array_shift ( $filters );
$doSet = new DataObjectSet ();
$doSet -> push ( new ArrayData ( array (
'ClassName' => 'all' ,
'Title' => 'All items'
)));
foreach ( $filters as $filter ) {
if ( call_user_func ( array ( $filter , 'showInList' ))) {
$doSet -> push ( new ArrayData ( array (
'ClassName' => $filter ,
'Title' => call_user_func ( array ( $filter , 'title' ))
)));
}
}
return $doSet ;
2009-05-14 08:11:18 +02:00
}
2007-09-16 17:19:17 +02:00
/**
* Returns the SiteTree columns that can be filtered using the the Site Tree Search button as a DataObjectSet
*/
public function SiteTreeFilterOptions () {
$filter_options = new DataObjectSet ();
2007-11-07 07:05:52 +01:00
foreach ( self :: T_SiteTreeFilterOptions () as $key => $value ) {
2007-09-16 17:19:17 +02:00
$record = array (
'Column' => $key ,
2007-11-07 07:05:52 +01:00
'Title' => $value ,
2007-09-16 17:19:17 +02:00
);
$filter_options -> push ( new ArrayData ( $record ));
}
return $filter_options ;
}
public function SiteTreeFilterDateField () {
$dateField = new CalendarDateField ( 'SiteTreeFilterDate' );
return $dateField -> Field ();
}
2009-05-14 08:11:18 +02:00
public function SiteTreeFilterPageTypeField () {
$types = SiteTree :: page_type_classes (); array_unshift ( $types , 'All' );
2009-07-09 07:41:30 +02:00
$source = array_combine ( $types , $types );
asort ( $source );
$optionsetField = new DropdownField ( 'ClassName' , 'ClassName' , $source , 'Any' );
2009-05-14 08:11:18 +02:00
return $optionsetField -> Field ();
}
2007-09-16 17:19:17 +02:00
2007-07-19 12:40:05 +02:00
public function generateDataTreeHints () {
$classes = ClassInfo :: subclassesFor ( $this -> stat ( 'tree_class' ) );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$def [ 'Root' ] = array ();
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
foreach ( $classes as $class ) {
$obj = singleton ( $class );
if ( $obj instanceof HiddenClass ) continue ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$allowedChildren = $obj -> allowedChildren ();
if ( $allowedChildren != " none " ) $def [ $class ][ 'allowedChildren' ] = $allowedChildren ;
$def [ $class ][ 'defaultChild' ] = $obj -> defaultChild ();
2008-11-02 01:24:46 +01:00
$def [ $class ][ 'defaultParent' ] = isset ( SiteTree :: get_by_url ( $obj -> defaultParent ()) -> ID ) ? SiteTree :: get_by_url ( $obj -> defaultParent ()) -> ID : null ;
2007-07-19 12:40:05 +02:00
if ( is_array ( $allowedChildren )) foreach ( $allowedChildren as $allowedChild ) {
$def [ $allowedChild ][ 'allowedParents' ][] = $class ;
}
if ( $obj -> stat ( 'can_be_root' )) {
$def [ 'Root' ][ 'allowedChildren' ][] = $class ;
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
// Put data hints into a script tag at the top
Requirements :: customScript ( " siteTreeHints = " . $this -> jsDeclaration ( $def ) . " ; " );
}
public function generateTreeStylingJS () {
$classes = ClassInfo :: subclassesFor ( 'SiteTree' );
foreach ( $classes as $class ) {
$obj = singleton ( $class );
if ( $obj instanceof HiddenClass ) continue ;
if ( $icon = $obj -> stat ( 'icon' )) $iconInfo [ $class ] = $icon ;
}
$iconInfo [ 'BrokenLink' ] = 'cms/images/treeicons/brokenlink' ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$js = " var _TREE_ICONS = []; \n " ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
foreach ( $iconInfo as $class => $icon ) {
// SiteTree::$icon can be set to array($icon, $option)
// $option can be "file" or "folder" to force the icon to always be the file or the folder form
$option = null ;
if ( is_array ( $icon )) list ( $icon , $option ) = $icon ;
$fileImage = ( $option == " folder " ) ? $icon . '-openfolder.gif' : $icon . '-file.gif' ;
$openFolderImage = $icon . '-openfolder.gif' ;
if ( ! Director :: fileExists ( $openFolderImage ) || $option = " file " ) $openFolderImage = $fileImage ;
$closedFolderImage = $icon . '-closedfolder.gif' ;
if ( ! Director :: fileExists ( $closedFolderImage ) || $option = " file " ) $closedFolderImage = $fileImage ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$js .= <<< JS
_TREE_ICONS [ '$class' ] = {
fileIcon : '$fileImage' ,
openFolderIcon : '$openFolderImage' ,
closedFolderIcon : '$closedFolderImage'
};
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
JS ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
Requirements :: customScript ( $js );
}
/**
* Return a javascript instanciation of this array
*/
protected function jsDeclaration ( $array ) {
if ( is_array ( $array )) {
$object = false ;
foreach ( array_keys ( $array ) as $key ) {
if ( ! is_numeric ( $key )) {
$object = true ;
break ;
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
if ( $object ) {
foreach ( $array as $k => $v ) {
$parts [] = " $k : " . $this -> jsDeclaration ( $v );
}
return " { \n " . implode ( " , \n " , $parts ) . " } \n " ;
} else {
foreach ( $array as $part ) $parts [] = $this -> jsDeclaration ( $part );
return " [ " . implode ( " , " , $parts ) . " ] \n " ;
}
} else {
return " ' " . addslashes ( $array ) . " ' " ;
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
/**
2008-10-16 11:37:28 +02:00
* Populates an array of classes in the CMS
* which allows the user to change the page type .
*
* @ return DataObjectSet
2007-07-19 12:40:05 +02:00
*/
public function PageTypes () {
2009-02-03 04:22:20 +01:00
$classes = SiteTree :: page_type_classes ();
2007-07-19 12:40:05 +02:00
2009-02-03 04:22:20 +01:00
$result = new DataObjectSet ();
2008-01-17 06:31:38 +01:00
2007-07-19 12:40:05 +02:00
foreach ( $classes as $class ) {
2008-10-16 11:37:28 +02:00
$instance = singleton ( $class );
if ( $instance instanceof HiddenClass ) continue ;
2007-09-15 23:54:24 +02:00
2008-10-16 11:37:28 +02:00
if ( ! $instance -> canCreate ()) continue ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
// skip this type if it is restricted
2008-10-16 11:37:28 +02:00
if ( $instance -> stat ( 'need_permission' ) && ! $this -> can ( singleton ( $class ) -> stat ( 'need_permission' ))) continue ;
2008-02-25 03:10:37 +01:00
$addAction = $instance -> i18n_singular_name ();
2009-01-05 07:17:59 +01:00
// if we're in translation mode, the link between the translated pagetype
// title and the actual classname might not be obvious, so we add it in parantheses
// Example: class "RedirectorPage" has the title "Weiterleitung" in German,
// so it shows up as "Weiterleitung (RedirectorPage)"
if ( i18n :: get_locale () != 'en_US' ) {
$addAction .= " ( { $class } ) " ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$result -> push ( new ArrayData ( array (
2008-10-16 11:37:28 +02:00
'ClassName' => $class ,
'AddAction' => $addAction ,
2007-07-19 12:40:05 +02:00
)));
}
2008-10-16 11:37:28 +02:00
2008-02-25 03:10:37 +01:00
$result -> sort ( 'AddAction' );
2007-07-19 12:40:05 +02:00
return $result ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
/**
2009-03-18 18:18:52 +01:00
* Get a database record to be managed by the CMS
2007-07-19 12:40:05 +02:00
*/
2009-03-18 18:18:52 +01:00
public function getRecord ( $id ) {
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$treeClass = $this -> stat ( 'tree_class' );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
if ( $id && is_numeric ( $id )) {
2008-11-23 23:58:18 +01:00
$record = DataObject :: get_one ( $treeClass , " \" $treeClass\ " . \ " ID \" = $id " );
2007-09-15 23:54:24 +02:00
2009-05-01 00:47:28 +02:00
// Then, try getting a record from the live site
2007-07-19 12:40:05 +02:00
if ( ! $record ) {
2008-11-23 23:58:18 +01:00
// $record = Versioned::get_one_by_stage($treeClass, "Live", "\"$treeClass\".\"ID\" = $id");
2007-07-19 12:40:05 +02:00
Versioned :: reading_stage ( 'Live' );
singleton ( $treeClass ) -> flushCache ();
2009-01-08 00:01:47 +01:00
2008-11-23 23:58:18 +01:00
$record = DataObject :: get_one ( $treeClass , " \" $treeClass\ " . \ " ID \" = $id " );
2008-12-17 23:41:07 +01:00
if ( $record ) Versioned :: reading_stage ( null );
2007-07-19 12:40:05 +02:00
}
2009-05-01 00:47:28 +02:00
// Then, try getting a deleted record
if ( ! $record ) {
$record = Versioned :: get_latest_version ( $treeClass , $id );
}
// Don't open a page from a different locale
2009-05-14 08:06:34 +02:00
if ( $record && Translatable :: is_enabled () && $record -> Locale && $record -> Locale != Translatable :: get_current_locale ()) {
2009-05-01 00:47:28 +02:00
$record = null ;
}
2007-07-19 12:40:05 +02:00
return $record ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
} else if ( substr ( $id , 0 , 3 ) == 'new' ) {
return $this -> getNewItem ( $id );
}
}
public function getEditForm ( $id ) {
$record = $this -> getRecord ( $id );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
if ( $record ) {
2008-12-17 23:41:07 +01:00
if ( $record -> IsDeletedFromStage ) $record -> Status = _t ( 'CMSMain.REMOVEDFD' , " Removed from the draft site " );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$fields = $record -> getCMSFields ( $this );
2007-09-15 23:09:13 +02:00
if ( $fields == null ) {
user_error ( " getCMSFields returned null on a 'Page' object - it should return a FieldSet object. Perhaps you forgot to put a return statement at the end of your method? " , E_USER_ERROR );
}
2007-07-19 12:40:05 +02:00
$fields -> push ( $idField = new HiddenField ( " ID " ));
$fields -> push ( $liveURLField = new HiddenField ( " LiveURLSegment " ));
$fields -> push ( $stageURLField = new HiddenField ( " StageURLSegment " ));
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
/*if( substr($record->ID, 0, 3 ) == 'new' )*/
$fields -> push ( new HiddenField ( 'Sort' , '' , $record -> Sort ));
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$idField -> setValue ( $id );
2007-09-05 08:42:26 +02:00
if ( $record -> ID && is_numeric ( $record -> ID ) ) {
2008-11-23 23:58:18 +01:00
$liveRecord = Versioned :: get_one_by_stage ( 'SiteTree' , 'Live' , " \" SiteTree \" . \" ID \" = $record->ID " );
2007-09-05 08:42:26 +02:00
if ( $liveRecord ) $liveURLField -> setValue ( $liveRecord -> AbsoluteLink ());
}
2008-12-17 23:41:07 +01:00
if ( ! $record -> IsDeletedFromStage ) {
2007-09-05 08:42:26 +02:00
$stageURLField -> setValue ( $record -> AbsoluteLink ());
}
2007-07-19 12:40:05 +02:00
// getAllCMSActions can be used to completely redefine the action list
if ( $record -> hasMethod ( 'getAllCMSActions' )) {
$actions = $record -> getAllCMSActions ();
} else {
2008-12-04 23:38:58 +01:00
$actions = $record -> getCMSActions ();
// add default actions if none are defined
if ( ! $actions || ! $actions -> Count ()) {
2008-03-11 02:02:05 +01:00
if ( $record -> canEdit ()) {
2008-12-04 23:38:58 +01:00
$actions -> push ( new FormAction ( 'save' , _t ( 'CMSMain.SAVE' , 'Save' )));
2008-03-11 02:02:05 +01:00
$actions -> push ( $deleteAction = new FormAction ( 'delete' , _t ( 'CMSMain.DELETE' , 'Delete from the draft site' )));
$deleteAction -> addExtraClass ( 'delete' );
}
2007-07-19 12:40:05 +02:00
}
}
2009-03-18 14:03:52 +01:00
// Add a default or custom validator.
// @todo Currently the default Validator.js implementation
// adds javascript to the document body, meaning it won't
// be included properly if the associated fields are loaded
// through ajax. This means only serverside validation
// will kick in for pages+validation loaded through ajax.
// This will be solved by using less obtrusive javascript validation
// in the future, see http://open.silverstripe.com/ticket/2915 and http://open.silverstripe.com/ticket/3386
if ( $record -> hasMethod ( 'getCMSValidator' )) {
$validator = $record -> getCMSValidator ();
} else {
$validator = new RequiredFields ();
}
// The clientside (mainly LeftAndMain*.js) rely on ajax responses
// which can be evaluated as javascript, hence we need
// to override any global changes to the validation handler.
$validator -> setJavascriptValidationHandler ( 'prototype' );
$form = new Form ( $this , " EditForm " , $fields , $actions , $validator );
2007-07-19 12:40:05 +02:00
$form -> loadDataFrom ( $record );
$form -> disableDefaultAction ();
2009-01-05 07:17:59 +01:00
if ( ! $record -> canEdit () || $record -> IsDeletedFromStage ) {
$readonlyFields = $form -> Fields () -> makeReadonly ();
$form -> setFields ( $readonlyFields );
}
2007-07-19 12:40:05 +02:00
return $form ;
} else if ( $id ) {
return new Form ( $this , " EditForm " , new FieldSet (
2008-10-16 15:27:12 +02:00
new LabelField ( 'PageDoesntExistLabel' , _t ( 'CMSMain.PAGENOTEXISTS' , " This page doesn't exist " ))), new FieldSet ());
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
//------------------------------------------------------------------------------------------//
// Data saving handlers
public function addpage () {
2008-11-18 02:48:50 +01:00
$className = isset ( $_REQUEST [ 'PageType' ]) ? $_REQUEST [ 'PageType' ] : " Page " ;
$parent = isset ( $_REQUEST [ 'ParentID' ]) ? $_REQUEST [ 'ParentID' ] : 0 ;
$suffix = isset ( $_REQUEST [ 'Suffix' ]) ? " - " . $_REQUEST [ 'Suffix' ] : null ;
2007-09-15 23:54:24 +02:00
2009-01-10 12:36:30 +01:00
if ( ! $parent && isset ( $_REQUEST [ 'Parent' ])) {
$page = SiteTree :: get_by_url ( $_REQUEST [ 'Parent' ]);
if ( $page ) $parent = $page -> ID ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
if ( is_numeric ( $parent )) $parentObj = DataObject :: get_by_id ( " SiteTree " , $parent );
if ( ! $parentObj || ! $parentObj -> ID ) $parent = 0 ;
2008-11-03 15:56:36 +01:00
if ( $parentObj && ! $parentObj -> canAddChildren ()) return Security :: permissionFailure ( $this );
if ( ! singleton ( $className ) -> canCreate ()) return Security :: permissionFailure ( $this );
2007-09-15 23:54:24 +02:00
2007-11-02 02:52:04 +01:00
$p = $this -> getNewItem ( " new- $className - $parent " . $suffix , false );
2009-03-20 09:49:27 +01:00
$p -> Locale = $_REQUEST [ 'Locale' ];
2007-11-02 02:52:04 +01:00
$p -> write ();
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
return $this -> returnItemToUser ( $p );
}
2007-09-15 23:54:24 +02:00
2008-11-07 13:21:10 +01:00
/**
* @ uses LeftAndMainDecorator -> augmentNewSiteTreeItem ()
*/
2007-07-19 12:40:05 +02:00
public function getNewItem ( $id , $setID = true ) {
2008-11-18 02:48:50 +01:00
list ( $dummy , $className , $parentID , $suffix ) = array_pad ( explode ( '-' , $id ), 4 , null );
2009-01-10 12:36:30 +01:00
2007-07-19 12:40:05 +02:00
$newItem = new $className ();
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
if ( ! $suffix ) {
$sessionTag = " NewItems. " . $parentID . " . " . $className ;
if ( Session :: get ( $sessionTag )) {
$suffix = '-' . Session :: get ( $sessionTag );
Session :: set ( $sessionTag , Session :: get ( $sessionTag ) + 1 );
}
else
Session :: set ( $sessionTag , 1 );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$id = $id . $suffix ;
}
2007-09-15 23:54:24 +02:00
2007-09-15 22:21:13 +02:00
$newItem -> Title = _t ( 'CMSMain.NEW' , " New " , PR_MEDIUM , '"New " followed by a className' ) . $className ;
2007-07-19 12:40:05 +02:00
$newItem -> URLSegment = " new- " . strtolower ( $className );
$newItem -> ClassName = $className ;
$newItem -> ParentID = $parentID ;
2007-09-15 23:54:24 +02:00
2008-02-25 03:10:37 +01:00
// DataObject::fieldExists only checks the current class, not the hierarchy
// This allows the CMS to set the correct sort value
if ( $newItem -> castingHelperPair ( 'Sort' )) {
2008-11-24 10:30:41 +01:00
$newItem -> Sort = DB :: query ( " SELECT MAX( \" Sort \" ) FROM \" SiteTree \" WHERE \" ParentID \" = ' " . Convert :: raw2sql ( $parentID ) . " ' " ) -> value () + 1 ;
2007-07-19 12:40:05 +02:00
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
if ( Member :: currentUser () )
$newItem -> OwnerID = Member :: currentUser () -> ID ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
if ( $setID ) $newItem -> ID = $id ;
2007-09-15 23:54:24 +02:00
2008-02-25 03:10:37 +01:00
# Some modules like subsites add extra fields that need to be set when the new item is created
$this -> extend ( 'augmentNewSiteTreeItem' , $newItem );
2007-07-19 12:40:05 +02:00
return $newItem ;
}
2007-09-15 23:54:24 +02:00
2008-12-17 23:41:07 +01:00
/**
* Delete the page from live . This means a page in draft mode might still exist .
*
* @ see delete ()
*/
2007-07-19 12:40:05 +02:00
public function deletefromlive ( $urlParams , $form ) {
$id = $_REQUEST [ 'ID' ];
Versioned :: reading_stage ( 'Live' );
$record = DataObject :: get_by_id ( " SiteTree " , $id );
2008-11-03 15:56:36 +01:00
if ( $record && ! $record -> canDelete ()) return Security :: permissionFailure ( $this );
2007-07-27 07:26:00 +02:00
$descRemoved = '' ;
2007-10-02 07:08:36 +02:00
$descendantsRemoved = 0 ;
2007-07-19 12:40:05 +02:00
// before deleting the records, get the descendants of this tree
if ( $record ) {
$descendantIDs = $record -> getDescendantIDList ( 'SiteTree' );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
// then delete them from the live site too
2007-09-15 23:54:24 +02:00
$descendantsRemoved = 0 ;
2007-07-19 12:40:05 +02:00
foreach ( $descendantIDs as $descID )
if ( $descendant = DataObject :: get_by_id ( 'SiteTree' , $descID ) ) {
$descendant -> delete ();
$descendantsRemoved ++ ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
// delete the record
$record -> delete ();
}
Versioned :: reading_stage ( 'Stage' );
2007-07-27 07:26:00 +02:00
if ( isset ( $descendantsRemoved )) {
2007-07-19 12:40:05 +02:00
$descRemoved = " and $descendantsRemoved descendants " ;
2008-02-25 03:10:37 +01:00
$descRemoved = sprintf ( ' ' . _t ( 'CMSMain.DESCREMOVED' , 'and %s descendants' ), $descendantsRemoved );
2007-09-15 02:46:22 +02:00
} else {
$descRemoved = '' ;
2007-07-19 12:40:05 +02:00
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
FormResponse :: add ( $this -> deleteTreeNodeJS ( $record ));
2008-02-25 03:10:37 +01:00
FormResponse :: status_message ( sprintf ( _t ( 'CMSMain.REMOVED' , 'Deleted \'%s\'%s from live site' ), $record -> Title , $descRemoved ), 'good' );
2007-07-19 12:40:05 +02:00
return FormResponse :: respond ();
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
/**
* Actually perform the publication step
*/
public function performPublish ( $record ) {
2008-11-03 15:56:36 +01:00
if ( $record && ! $record -> canPublish ()) return Security :: permissionFailure ( $this );
2008-08-12 04:59:27 +02:00
$record -> doPublish ();
2007-07-19 12:40:05 +02:00
}
2009-01-05 07:17:59 +01:00
/**
* Reverts a page by publishing it to live .
* Use { @ link restorepage ()} if you want to restore a page
* which was deleted from draft without publishing .
*
* @ uses SiteTree -> doRevertToLive ()
*/
2007-07-19 12:40:05 +02:00
public function revert ( $urlParams , $form ) {
2008-12-17 23:41:07 +01:00
$id = ( int ) $_REQUEST [ 'ID' ];
2009-05-18 01:19:51 +02:00
$record = Versioned :: get_one_by_stage ( 'SiteTree' , 'Live' , " \" SiteTree_Live \" . \" ID \" = ' { $id } ' " );
2008-12-04 23:38:58 +01:00
2009-01-05 07:17:59 +01:00
// a user can restore a page without publication rights, as it just adds a new draft state
// (this action should just be available when page has been "deleted from draft")
2008-11-14 03:23:26 +01:00
if ( isset ( $record ) && $record && ! $record -> canEdit ()) return Security :: permissionFailure ( $this );
2009-01-05 07:17:59 +01:00
2008-11-18 02:48:50 +01:00
$record -> doRevertToLive ();
2007-07-19 12:40:05 +02:00
2008-11-18 02:48:50 +01:00
$title = Convert :: raw2js ( $record -> Title );
2007-07-19 12:40:05 +02:00
FormResponse :: get_page ( $id );
FormResponse :: add ( " $ ('sitetree').setNodeTitle( $id , ' $title '); " );
2007-09-15 22:21:13 +02:00
FormResponse :: status_message ( sprintf ( _t ( 'CMSMain.RESTORED' , " Restored '%s' successfully " , PR_MEDIUM , 'Param %s is a title' ), $title ), 'good' );
2007-07-19 12:40:05 +02:00
2007-09-15 23:54:24 +02:00
return FormResponse :: respond ();
2007-07-19 12:40:05 +02:00
}
2008-03-11 02:02:05 +01:00
/**
2008-12-17 23:41:07 +01:00
* Delete the current page from draft stage .
* @ see deletefromlive ()
2008-03-11 02:02:05 +01:00
*/
2009-09-10 01:47:56 +02:00
public function delete ( $data , $form ) {
$record = DataObject :: get_one (
" SiteTree " ,
sprintf ( " \" SiteTree \" . \" ID \" = %d " , Convert :: raw2sql ( $data [ 'ID' ]))
);
2008-11-03 15:56:36 +01:00
if ( $record && ! $record -> canDelete ()) return Security :: permissionFailure ();
2008-12-17 23:41:07 +01:00
// save ID and delete record
2008-03-11 02:02:05 +01:00
$recordID = $record -> ID ;
2007-07-19 12:40:05 +02:00
$record -> delete ();
2008-03-11 02:02:05 +01:00
if ( Director :: is_ajax ()) {
2008-12-17 23:41:07 +01:00
// need a valid ID value even if the record doesn't have one in the database
// (its still present in the live tables)
2009-03-03 22:43:47 +01:00
$liveRecord = Versioned :: get_one_by_stage ( 'SiteTree' , 'Live' , " \" SiteTree_Live \" . \" ID \" = $recordID " );
2008-12-17 23:41:07 +01:00
// if the page has never been published to live, we need to act the same way as in deletefromlive()
if ( $liveRecord ) {
// the form is readonly now, so we need to refresh the representation
FormResponse :: get_page ( $recordID );
return $this -> tellBrowserAboutPublicationChange ( $liveRecord , sprintf ( _t ( 'CMSMain.REMOVEDPAGEFROMDRAFT' , " Removed '%s' from the draft site " ), $record -> Title ));
} else {
FormResponse :: add ( $this -> deleteTreeNodeJS ( $record ));
FormResponse :: status_message ( sprintf ( _t ( 'CMSMain.REMOVEDPAGEFROMDRAFT' , " Removed '%s' from the draft site " ), $record -> Title ), 'good' );
return FormResponse :: respond ();
}
2008-03-11 02:02:05 +01:00
} else {
Director :: redirectBack ();
}
2007-07-19 12:40:05 +02:00
}
2007-09-15 23:54:24 +02:00
2009-02-03 03:50:25 +01:00
/*
2007-07-19 12:40:05 +02:00
* Return a dropdown for selecting reports
*/
function ReportSelector () {
$reports = ClassInfo :: subclassesFor ( " SideReport " );
2007-09-15 23:54:24 +02:00
2007-09-15 22:21:13 +02:00
$options [ " " ] = _t ( 'CMSMain.CHOOSEREPORT' , " (Choose a report) " );
2007-07-19 12:40:05 +02:00
foreach ( $reports as $report ) {
if ( $report != 'SideReport' ) $options [ $report ] = singleton ( $report ) -> title ();
}
2008-02-25 03:10:37 +01:00
return new DropdownField ( " ReportSelector " , _t ( 'CMSMain.REPORT' , 'Report' ), $options );
2007-07-19 12:40:05 +02:00
}
/**
* Get the content for a side report
*/
function sidereport () {
$reportClass = $this -> urlParams [ 'ID' ];
2008-10-08 03:49:49 +02:00
$report = ClassInfo :: exists ( $reportClass ) ? new $reportClass () : false ;
return $report ? $report -> getHTML () : false ;
2007-07-19 12:40:05 +02:00
}
/**
* Get the versions of the current page
*/
function versions () {
$pageID = $this -> urlParams [ 'ID' ];
$page = $this -> getRecord ( $pageID );
if ( $page ) {
2009-03-03 22:43:47 +01:00
$versions = $page -> allVersions ( $_REQUEST [ 'unpublished' ] ? " " : " \" SiteTree \" . \" WasPublished \" = 1 " );
2007-07-19 12:40:05 +02:00
return array (
'Versions' => $versions ,
2007-09-15 23:54:24 +02:00
);
2007-07-19 12:40:05 +02:00
} else {
2007-09-15 22:21:13 +02:00
return sprintf ( _t ( 'CMSMain.VERSIONSNOPAGE' , " Can't find page #%d " , PR_LOW ), $pageID );
2007-07-19 12:40:05 +02:00
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
/**
* Roll a page back to a previous version
*/
function rollback () {
2007-09-19 16:04:50 +02:00
if ( isset ( $_REQUEST [ 'Version' ]) && ( bool ) $_REQUEST [ 'Version' ]) {
2007-07-19 12:40:05 +02:00
$record = $this -> performRollback ( $_REQUEST [ 'ID' ], $_REQUEST [ 'Version' ]);
2007-09-16 18:32:30 +02:00
echo sprintf ( _t ( 'CMSMain.ROLLEDBACKVERSION' , " Rolled back to version #%d. New version number is #%d " ), $_REQUEST [ 'Version' ], $record -> Version );
2007-07-19 12:40:05 +02:00
} else {
$record = $this -> performRollback ( $_REQUEST [ 'ID' ], " Live " );
2007-09-15 22:21:13 +02:00
echo sprintf ( _t ( 'CMSMain.ROLLEDBACKPUB' , " Rolled back to published version. New version number is #%d " ), $record -> Version );
2007-07-19 12:40:05 +02:00
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function unpublish () {
$SQL_id = Convert :: raw2sql ( $_REQUEST [ 'ID' ]);
$page = DataObject :: get_by_id ( " SiteTree " , $SQL_id );
2008-11-03 15:56:36 +01:00
if ( $page && ! $page -> canPublish ()) return Security :: permissionFailure ( $this );
2008-10-16 05:21:49 +02:00
$page -> doUnpublish ();
2007-09-14 03:19:13 +02:00
return $this -> tellBrowserAboutPublicationChange ( $page , sprintf ( _t ( 'CMSMain.REMOVEDPAGE' , " Removed '%s' from the published site " ), $page -> Title ));
2007-07-19 12:40:05 +02:00
}
2008-03-11 02:02:05 +01:00
2007-07-19 12:40:05 +02:00
/**
* Return a few pieces of information about a change to a page
* - Send the new status message
* - Update the action buttons
* - Update the treenote
* - Send a status message
*/
function tellBrowserAboutPublicationChange ( $page , $statusMessage ) {
$JS_title = Convert :: raw2js ( $page -> TreeTitle ());
2007-09-15 23:54:24 +02:00
2008-12-17 23:41:07 +01:00
$JS_stageURL = $page -> IsDeletedFromStage ? '' : Convert :: raw2js ( $page -> AbsoluteLink ());
2008-11-23 23:58:18 +01:00
$liveRecord = Versioned :: get_one_by_stage ( 'SiteTree' , 'Live' , " \" SiteTree \" . \" ID \" = $page->ID " );
2009-01-08 00:01:47 +01:00
2008-03-11 02:20:24 +01:00
$JS_liveURL = $liveRecord ? Convert :: raw2js ( $liveRecord -> AbsoluteLink ()) : '' ;
2007-07-19 12:40:05 +02:00
FormResponse :: add ( $this -> getActionUpdateJS ( $page ));
FormResponse :: update_status ( $page -> Status );
2008-03-11 02:02:05 +01:00
if ( $JS_stageURL || $JS_liveURL ) {
2008-07-18 05:40:32 +02:00
FormResponse :: add ( " \$ ('sitetree').setNodeTitle( $page->ID , ' $JS_title '); " );
2008-03-11 02:02:05 +01:00
} else {
FormResponse :: add ( " var node = $ ('sitetree').getTreeNodeByIdx(' $page->ID '); " );
2008-11-18 02:48:50 +01:00
FormResponse :: add ( " if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node); " );
2008-03-11 02:02:05 +01:00
FormResponse :: add ( " $ ('Form_EditForm').reloadIfSetTo( $page->ID ); " );
}
2009-07-09 07:41:12 +02:00
if ( $statusMessage ) FormResponse :: status_message ( $statusMessage , 'good' );
2008-07-18 05:40:32 +02:00
FormResponse :: add ( " $ ('Form_EditForm').elements.StageURLSegment.value = ' $JS_stageURL '; " );
FormResponse :: add ( " $ ('Form_EditForm').elements.LiveURLSegment.value = ' $JS_liveURL '; " );
2007-07-19 12:40:05 +02:00
FormResponse :: add ( " $ ('Form_EditForm').notify('PagePublished', $ ('Form_EditForm').elements.ID.value); " );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
return FormResponse :: respond ();
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function performRollback ( $id , $version ) {
$record = DataObject :: get_by_id ( $this -> stat ( 'tree_class' ), $id );
2008-11-03 15:56:36 +01:00
if ( $record && ! $record -> canPublish ()) return Security :: permissionFailure ( $this );
2008-10-16 05:21:49 +02:00
$record -> doRollbackTo ( $version );
2007-07-19 12:40:05 +02:00
return $record ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function getversion () {
$id = $this -> urlParams [ 'ID' ];
2007-09-16 18:32:30 +02:00
$version = str_replace ( '&ajax=1' , '' , $this -> urlParams [ 'OtherID' ]);
2007-07-19 12:40:05 +02:00
$record = Versioned :: get_version ( " SiteTree " , $id , $version );
2009-09-04 03:18:07 +02:00
2007-07-19 12:40:05 +02:00
if ( $record ) {
2008-11-03 15:56:36 +01:00
if ( $record && ! $record -> canView ()) return Security :: permissionFailure ( $this );
2007-07-19 12:40:05 +02:00
$fields = $record -> getCMSFields ( $this );
$fields -> removeByName ( " Status " );
$fields -> push ( new HiddenField ( " ID " ));
$fields -> push ( new HiddenField ( " Version " ));
2009-09-04 03:18:07 +02:00
$versionAuthor = DataObject :: get_by_id ( 'Member' , $record -> AuthorID );
2009-01-05 07:17:59 +01:00
$fields -> insertBefore (
new LiteralField (
'YouAreViewingHeader' ,
'<p class="message notice">' .
sprintf (
_t (
'CMSMain.VIEWING' ,
" You are viewing version #%s, created %s by %s " ,
PR_MEDIUM ,
'Version number is a linked string, created is a relative time (e.g. 2 days ago), by a specific author'
),
2009-07-09 07:41:42 +02:00
" <a href= \" admin/getversion/ $record->ID / $version\ " title = \ " " . ( $versionAuthor ? $versionAuthor -> Title : '' ) . " \" > $version </a> " ,
2009-01-05 07:17:59 +01:00
$record -> obj ( 'LastEdited' ) -> Ago (),
2009-07-09 07:41:42 +02:00
( $versionAuthor ? $versionAuthor -> Title : '' )
2009-01-05 07:17:59 +01:00
) .
'</p>'
),
'Root'
);
2007-07-19 12:40:05 +02:00
$actions = new FieldSet (
2007-09-15 22:21:13 +02:00
new FormAction ( " email " , _t ( 'CMSMain.EMAIL' , " Email " )),
new FormAction ( " print " , _t ( 'CMSMain.PRINT' , " Print " )),
new FormAction ( " rollback " , _t ( 'CMSMain.ROLLBACK' , " Roll back to this version " ))
2007-07-19 12:40:05 +02:00
);
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
// encode the message to appear in the body of the email
2007-10-29 01:55:52 +01:00
$archiveURL = Director :: absoluteBaseURL () . $record -> URLSegment . '?archiveDate=' . $record -> obj ( 'LastEdited' ) -> URLDatetime ();
2009-05-06 08:37:45 +02:00
// Ensure that source file comments are disabled
SSViewer :: set_source_file_comments ( false );
2007-07-19 12:40:05 +02:00
$archiveEmailMessage = urlencode ( $this -> customise ( array ( 'ArchiveDate' => $record -> obj ( 'LastEdited' ), 'ArchiveURL' => $archiveURL ) ) -> renderWith ( 'ViewArchivedEmail' ) );
$archiveEmailMessage = preg_replace ( '/\+/' , '%20' , $archiveEmailMessage );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$fields -> push ( new HiddenField ( 'ArchiveEmailMessage' , '' , $archiveEmailMessage ) );
$fields -> push ( new HiddenField ( 'ArchiveEmailSubject' , '' , preg_replace ( '/\+/' , '%20' , urlencode ( 'Archived version of ' . $record -> Title ) ) ) );
$fields -> push ( new HiddenField ( 'ArchiveURL' , '' , $archiveURL ) );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$form = new Form ( $this , " EditForm " , $fields , $actions );
$form -> loadDataFrom ( $record );
$form -> loadDataFrom ( array (
" ID " => $id ,
" Version " => $version ,
));
2009-01-05 07:17:59 +01:00
// historical version shouldn't be editable
$readonlyFields = $form -> Fields () -> makeReadonly ();
$form -> setFields ( $readonlyFields );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$templateData = $this -> customise ( array (
" EditForm " => $form
));
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
SSViewer :: setOption ( 'rewriteHashlinks' , false );
2009-01-05 07:17:59 +01:00
if ( Director :: is_ajax ()) {
$result = $templateData -> renderWith ( $this -> class . '_right' );
$parts = split ( '</?form[^>]*>' , $result );
return $parts [ sizeof ( $parts ) - 2 ];
} else {
return $templateData -> renderWith ( 'LeftAndMain' );
}
2007-07-19 12:40:05 +02:00
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function compareversions () {
2009-01-05 07:17:59 +01:00
$id = ( int ) $this -> urlParams [ 'ID' ];
$version1 = ( int ) $_REQUEST [ 'From' ];
$version2 = ( int ) $_REQUEST [ 'To' ];
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
if ( $version1 > $version2 ) {
$toVersion = $version1 ;
$fromVersion = $version2 ;
} else {
$toVersion = $version2 ;
$fromVersion = $version1 ;
}
$page = DataObject :: get_by_id ( " SiteTree " , $id );
2008-11-03 15:56:36 +01:00
if ( $page && ! $page -> canView ()) return Security :: permissionFailure ( $this );
2007-07-19 12:40:05 +02:00
$record = $page -> compareVersions ( $fromVersion , $toVersion );
2009-01-05 07:17:59 +01:00
$fromVersionRecord = Versioned :: get_version ( 'SiteTree' , $id , $fromVersion );
$toVersionRecord = Versioned :: get_version ( 'SiteTree' , $id , $toVersion );
2009-05-23 05:30:57 +02:00
if ( ! $fromVersionRecord ) user_error ( " Can't find version $fromVersion of page $id " , E_USER_ERROR );
if ( ! $toVersionRecord ) user_error ( " Can't find version $toVersion of page $id " , E_USER_ERROR );
2009-01-05 07:17:59 +01:00
2007-07-19 12:40:05 +02:00
if ( $record ) {
2009-01-05 07:17:59 +01:00
$fromDateNice = $fromVersionRecord -> obj ( 'LastEdited' ) -> Ago ();
$toDateNice = $toVersionRecord -> obj ( 'LastEdited' ) -> Ago ();
$fromAuthor = DataObject :: get_by_id ( 'Member' , $fromVersionRecord -> AuthorID );
2009-05-23 05:30:57 +02:00
if ( ! $fromAuthor ) $fromAuthor = new ArrayData ( array ( 'Title' => 'Unknown author' ));
2009-01-05 07:17:59 +01:00
$toAuthor = DataObject :: get_by_id ( 'Member' , $toVersionRecord -> AuthorID );
2009-05-23 05:30:57 +02:00
if ( ! $toAuthor ) $toAuthor = new ArrayData ( array ( 'Title' => 'Unknown author' ));
2009-01-05 07:17:59 +01:00
2007-07-19 12:40:05 +02:00
$fields = $record -> getCMSFields ( $this );
$fields -> push ( new HiddenField ( " ID " ));
$fields -> push ( new HiddenField ( " Version " ));
2009-01-05 07:17:59 +01:00
$fields -> insertBefore (
new LiteralField (
'YouAreComparingHeader' ,
'<p class="message notice">' .
sprintf (
_t ( 'CMSMain.COMPARINGV' , " Comparing versions %s and %s " ),
" <a href= \" admin/getversion/ $id / $fromVersionRecord->Version\ " title = \ " $fromAuthor->Title\ " > $fromVersionRecord -> Version </ a > < small > ( $fromDateNice ) </ small > " ,
" <a href= \" admin/getversion/ $id / $toVersionRecord->Version\ " title = \ " $toAuthor->Title\ " > $toVersionRecord -> Version </ a > < small > ( $toDateNice ) </ small > "
) .
'</p>'
),
" Root "
);
2007-07-19 12:40:05 +02:00
$actions = new FieldSet ();
$form = new Form ( $this , " EditForm " , $fields , $actions );
$form -> loadDataFrom ( $record );
$form -> loadDataFrom ( array (
" ID " => $id ,
2008-02-25 03:10:37 +01:00
" Version " => $fromVersion ,
2007-07-19 12:40:05 +02:00
));
2009-01-05 07:17:59 +01:00
// comparison views shouldn't be editable
$readonlyFields = $form -> Fields () -> makeReadonly ();
$form -> setFields ( $readonlyFields );
2007-07-19 12:40:05 +02:00
foreach ( $form -> Fields () -> dataFields () as $field ) {
$field -> dontEscape = true ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
return $this -> sendFormToBrowser ( array (
" EditForm " => $form
));
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function sendFormToBrowser ( $templateData ) {
if ( Director :: is_ajax ()) {
SSViewer :: setOption ( 'rewriteHashlinks' , false );
$result = $this -> customise ( $templateData ) -> renderWith ( $this -> class . '_right' );
$parts = split ( '</?form[^>]*>' , $result );
return $parts [ sizeof ( $parts ) - 2 ];
} else {
return array (
" Right " => $this -> customise ( $templateData ) -> renderWith ( $this -> class . '_right' ),
);
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function dialog () {
Requirements :: clear ();
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$buttons = new DataObjectSet ;
if ( $_REQUEST [ 'Buttons' ]) foreach ( $_REQUEST [ 'Buttons' ] as $button ) {
list ( $name , $title ) = explode ( ',' , $button , 2 );
$buttons -> push ( new ArrayData ( array (
" Name " => $name ,
" Title " => $title ,
)));
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
return array (
" Message " => htmlentities ( $_REQUEST [ 'Message' ]),
" Buttons " => $buttons ,
" Modal " => $_REQUEST [ 'Modal' ] ? true : false ,
);
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function canceldraftchangesdialog () {
Requirements :: clear ();
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: css ( CMS_DIR . 'css/dialog.css' );
2008-09-29 20:49:35 +02:00
Requirements :: javascript ( THIRDPARTY_DIR . '/prototype.js' );
Requirements :: javascript ( THIRDPARTY_DIR . '/behaviour.js' );
Requirements :: javascript ( THIRDPARTY_DIR . '/prototype_improvements.js' );
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: javascript ( CMS_DIR . '/javascript/dialog.js' );
2007-09-15 23:54:24 +02:00
2007-09-15 22:21:13 +02:00
$message = _t ( 'CMSMain.COPYPUBTOSTAGE' , " Do you really want to copy the published content to the stage site? " );
$buttons = " <button name= \" OK \" > " . _t ( 'CMSMain.OK' , 'OK' ) . " </button><button name= \" Cancel \" > " . _t ( 'CMSMain.CANCEL' , " Cancel " ) . " </button> " ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
return $this -> customise ( array (
'Message' => $message ,
'Buttons' => $buttons ,
'DialogType' => 'alert'
)) -> renderWith ( 'Dialog' );
}
2009-05-14 08:11:18 +02:00
2007-09-16 17:04:09 +02:00
/**
2009-05-14 08:11:18 +02:00
* Batch Actions Handler
2007-09-16 17:04:09 +02:00
*/
2009-05-14 08:11:18 +02:00
function batchactions () {
return new CMSBatchActionHandler ( $this , 'batchactions' );
2007-09-16 17:04:09 +02:00
}
2009-01-06 03:18:33 +01:00
/**
* @ return Form
*/
public function PublishItemsForm () {
$form = new Form (
$this ,
'PublishItemsForm' ,
new FieldSet (
new HiddenField ( 'csvIDs' ),
new CheckboxField ( 'ShowDrafts' , _t ( 'CMSMain_left.ss.SHOWONLYCHANGED' , 'Show only changed pages' ))
),
new FieldSet (
new FormAction ( 'publishitems' , _t ( 'CMSMain_left.ss.PUBLISHCONFIRM' , 'Publish the selected pages' ))
)
);
$form -> addExtraClass ( 'actionparams' );
return $form ;
}
2007-09-16 17:04:09 +02:00
2007-07-19 12:40:05 +02:00
/**
2009-05-14 08:11:18 +02:00
* Returns a list of batch actions
2007-07-19 12:40:05 +02:00
*/
2009-05-14 08:11:18 +02:00
function BatchActionList () {
return $this -> batchactions () -> batchActionList ();
2007-07-19 12:40:05 +02:00
}
2009-01-06 03:18:33 +01:00
/**
* @ return Form
*/
function DeleteItemsForm () {
$form = new Form (
$this ,
'DeleteItemsForm' ,
new FieldSet (
new LiteralField ( 'SelectedPagesNote' ,
sprintf ( '<p>%s</p>' , _t ( 'CMSMain_left.ss.SELECTPAGESACTIONS' , 'Select the pages that you want to change & then click an action:' ))
),
new HiddenField ( 'csvIDs' )
),
new FieldSet (
new FormAction ( 'deleteitems' , _t ( 'CMSMain_left.ss.DELETECONFIRM' , 'Delete the selected pages' ))
)
);
$form -> addExtraClass ( 'actionparams' );
return $form ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function buildbrokenlinks () {
if ( $this -> urlParams [ 'ID' ]) {
$newPageSet [] = DataObject :: get_by_id ( " Page " , $this -> urlParams [ 'ID' ]);
} else {
$pages = DataObject :: get ( " Page " );
foreach ( $pages as $page ) $newPageSet [] = $page ;
$pages = null ;
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$content = new HtmlEditorField ( 'Content' );
$download = new HtmlEditorField ( 'Download' );
foreach ( $newPageSet as $i => $page ) {
$page -> HasBrokenLink = 0 ;
$page -> HasBrokenFile = 0 ;
$lastUsage = ( memory_get_usage () - $lastPoint );
$lastPoint = memory_get_usage ();
$content -> setValue ( $page -> Content );
$content -> saveInto ( $page );
$download -> setValue ( $page -> Download );
$download -> saveInto ( $page );
echo " <li> $page->Title (link: $page->HasBrokenLink , file: $page->HasBrokenFile ) " ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
$page -> writeWithoutVersion ();
$page -> destroy ();
$newPageSet [ $i ] = null ;
}
}
function AddPageOptionsForm () {
$pageTypes = array ();
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
foreach ( $this -> PageTypes () as $arrayData ) {
$pageTypes [ $arrayData -> getField ( 'ClassName' )] = $arrayData -> getField ( 'AddAction' );
}
2009-03-18 18:18:52 +01:00
$fields = new FieldSet (
2007-09-15 23:54:24 +02:00
new HiddenField ( " ParentID " ),
2009-05-14 08:06:34 +02:00
new HiddenField ( " Locale " , 'Locale' , Translatable :: get_current_locale ()),
2009-02-03 04:22:20 +01:00
new DropdownField ( " PageType " , " " , $pageTypes , 'Page' )
2009-03-18 18:18:52 +01:00
);
$actions = new FieldSet (
2007-09-15 22:21:13 +02:00
new FormAction ( " addpage " , _t ( 'CMSMain.GO' , " Go " ))
2009-03-18 18:18:52 +01:00
);
return new Form ( $this , " AddPageOptionsForm " , $fields , $actions );
2007-07-19 12:40:05 +02:00
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
/**
* Helper function to get page count
*/
function getpagecount () {
2008-11-10 06:06:08 +01:00
ini_set ( 'max_execution_time' , 0 );
2007-07-19 12:40:05 +02:00
$excludePages = split ( " *, * " , $_GET [ 'exclude' ]);
2007-09-15 23:54:24 +02:00
2008-11-24 10:30:41 +01:00
$pages = DataObject :: get ( " SiteTree " , " \" ParentID \" = 0 " );
2007-07-19 12:40:05 +02:00
foreach ( $pages as $page ) $pageArr [] = $page ;
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
while ( list ( $i , $page ) = each ( $pageArr )) {
if ( ! in_array ( $page -> URLSegment , $excludePages )) {
if ( $children = $page -> AllChildren ()) {
foreach ( $children as $child ) $pageArr [] = $child ;
}
if ( ! $_GET [ 'onlywithcontent' ] || strlen ( Convert :: xml2raw ( $page -> Content )) > 100 ) {
echo " <li> " . $page -> Breadcrumbs ( null , true ) . " </li> " ;
$count ++ ;
} else {
2007-09-15 22:21:13 +02:00
echo " <li style= \" color: #777 \" > " . $page -> Breadcrumbs ( null , true ) . " - " . _t ( 'CMSMain.NOCONTENT' , " no content " ) . " </li> " ;
2007-07-19 12:40:05 +02:00
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
}
}
2007-09-15 23:54:24 +02:00
2007-09-15 22:21:13 +02:00
echo '<p>' . _t ( 'CMSMain.TOTALPAGES' , " Total pages: " ) . " $count </p> " ;
2007-07-19 12:40:05 +02:00
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function publishall () {
2008-10-08 23:33:07 +02:00
ini_set ( " memory_limit " , - 1 );
2008-11-10 06:06:08 +01:00
ini_set ( 'max_execution_time' , 0 );
2008-08-12 04:59:27 +02:00
$response = " " ;
2007-09-15 23:54:24 +02:00
2008-08-12 04:59:27 +02:00
if ( isset ( $this -> requestParams [ 'confirm' ])) {
2008-02-25 03:10:37 +01:00
$start = 0 ;
$pages = DataObject :: get ( " SiteTree " , " " , " " , " " , " $start ,30 " );
2007-07-19 12:40:05 +02:00
$count = 0 ;
2009-09-14 00:25:41 +02:00
if ( $pages ){
while ( true ) {
foreach ( $pages as $page ) {
if ( $page && ! $page -> canPublish ()) return Security :: permissionFailure ( $this );
$page -> doPublish ();
$page -> destroy ();
unset ( $page );
$count ++ ;
$response .= " <li> $count </li> " ;
}
if ( $pages -> Count () > 29 ) {
$start += 30 ;
$pages = DataObject :: get ( " SiteTree " , " " , " " , " " , " $start ,30 " );
} else {
break ;
}
2008-02-25 03:10:37 +01:00
}
2007-07-19 12:40:05 +02:00
}
2008-08-12 04:59:27 +02:00
$response .= sprintf ( _t ( 'CMSMain.PUBPAGES' , " Done: Published %d pages " ), $count );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
} else {
2008-08-12 04:59:27 +02:00
$response .= '<h1>' . _t ( 'CMSMain.PUBALLFUN' , '"Publish All" functionality' ) . ' </ h1 >
2007-09-15 22:21:13 +02:00
< p > ' . _t(' CMSMain . PUBALLFUN2 ', ' Pressing this button will do the equivalent of going to every page and pressing " publish " . It\ ' s
2007-07-19 12:40:05 +02:00
intended to be used after there have been massive edits of the content , such as when the site was
2007-09-15 22:21:13 +02:00
first built . ') . ' </ p >
2007-07-19 12:40:05 +02:00
< form method = " post " action = " publishall " >
2007-09-15 23:54:24 +02:00
< input type = " submit " name = " confirm " value = " '
2007-09-15 22:21:13 +02:00
. _t ( 'CMSMain.PUBALLCONFIRM' , " Please publish every page in the site, copying content stage to live " , PR_LOW , 'Confirmation button' ) . ' " />
</ form > ' ;
2007-07-19 12:40:05 +02:00
}
2008-08-12 04:59:27 +02:00
return $response ;
2007-07-19 12:40:05 +02:00
}
2009-01-10 12:36:30 +01:00
2009-01-05 07:17:59 +01:00
/**
2009-05-01 00:47:28 +02:00
* Restore a completely deleted page from the SiteTree_versions table .
2009-01-05 07:17:59 +01:00
*/
2009-05-01 00:47:28 +02:00
function restore () {
if (( $id = $_REQUEST [ 'ID' ]) && is_numeric ( $id )) {
2007-07-19 12:40:05 +02:00
$restoredPage = Versioned :: get_latest_version ( " SiteTree " , $id );
2009-05-01 00:47:28 +02:00
if ( $restoredPage ) {
$restoredPage = $restoredPage -> doRestoreToStage ();
FormResponse :: get_page ( $id );
$title = Convert :: raw2js ( $restoredPage -> TreeTitle ());
FormResponse :: add ( " $ ('sitetree').setNodeTitle( $id , ' $title '); " );
FormResponse :: status_message ( sprintf ( _t ( 'CMSMain.RESTORED' , " Restored '%s' successfully " , PR_MEDIUM , 'Param %s is a title' ), $title ), 'good' );
return FormResponse :: respond ();
2009-01-05 07:17:59 +01:00
2009-05-01 00:47:28 +02:00
} else {
return new HTTPResponse ( " SiteTree # $id not found " , 400 );
2007-07-19 12:40:05 +02:00
}
2009-05-01 00:47:28 +02:00
} else {
return new HTTPResponse ( " Please pass an ID in the form content " , 400 );
2007-07-19 12:40:05 +02:00
}
}
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
function duplicate () {
if (( $id = $this -> urlParams [ 'ID' ]) && is_numeric ( $id )) {
$page = DataObject :: get_by_id ( " SiteTree " , $id );
2009-08-25 07:52:52 +02:00
if ( $page && ( ! $page -> canEdit () || ! $page -> canCreate ())) {
return Security :: permissionFailure ( $this );
}
2007-07-19 12:40:05 +02:00
$newPage = $page -> duplicate ();
2008-02-25 03:10:37 +01:00
// ParentID can be hard-set in the URL. This is useful for pages with multiple parents
if ( $_GET [ 'parentID' ] && is_numeric ( $_GET [ 'parentID' ])) {
$newPage -> ParentID = $_GET [ 'parentID' ];
$newPage -> write ();
}
return $this -> returnItemToUser ( $newPage );
} else {
user_error ( " CMSMain::duplicate() Bad ID: ' $id ' " , E_USER_WARNING );
}
}
function duplicatewithchildren () {
if (( $id = $this -> urlParams [ 'ID' ]) && is_numeric ( $id )) {
$page = DataObject :: get_by_id ( " SiteTree " , $id );
2009-08-25 07:52:52 +02:00
if ( $page && ( ! $page -> canEdit () || ! $page -> canCreate ())) {
return Security :: permissionFailure ( $this );
}
2008-02-25 03:10:37 +01:00
$newPage = $page -> duplicateWithChildren ();
2008-01-24 01:01:52 +01:00
return $this -> returnItemToUser ( $newPage );
} else {
user_error ( " CMSMain::duplicate() Bad ID: ' $id ' " , E_USER_WARNING );
}
}
2007-09-16 18:32:30 +02:00
2009-02-03 03:50:25 +01:00
2007-09-16 18:32:30 +02:00
/**
* Create a new translation from an existing item , switch to this language and reload the tree .
*/
function createtranslation () {
2009-03-18 18:18:52 +01:00
$langCode = Convert :: raw2sql ( $_REQUEST [ 'newlang' ]);
$originalLangID = ( int ) $_REQUEST [ 'ID' ];
2007-09-16 18:32:30 +02:00
$record = $this -> getRecord ( $originalLangID );
Merged, debugged and enhanced Translatable patches from branches/translatable at r64523, r64523, 64523, thanks wakeless!
API CHANGE Changed Translatable schema from auxilliary tables (SiteTree_lang, SiteTree_lang_Live) to automatically filtered records on the original table (SiteTree, SiteTree_Live), using $Lang and $OriginalID properties. Incompatible update to old schema, migration script is in the works.
API CHANGE Removed Translatable::get_one(), Translatable::write()
ENHANCEMENT Simplified Translatable tree generation by using getSiteTreeFor() in CMSMain->createtranslation()
ENHANCEMENT Added AllChildrenIncludingDeleted(), augmentNumChildrenCountQuery(), augmentAllChildrenIncludingDeleted(), augmentStageChildren() to Translatable class to allow for more stable tree generation.
ENHANCEMENT Moved definition of Translatable schema from augmentDatabase() to Translatable->extraStatics()
ENHANCEMENT Changes to the CMS language selection refresh the whole admin interface instead of the tree only. This way we can add a URL parameter ?lang=<lang> to /admin, which makes the specific language bookmarkable and reloadable. Changes to LangSelector.js
ENHANCEMENT Added fallback to ModelAsController->getNestedController() to fetch page with matching URLSegment but different language in case no page is found in the current language.
ENHANCEMENT Added helper methods to Translatable: getTranslation(), hasTranslation(), isTranslation(), findOriginalIDs()
ENHANCEMENT Getters and setters for Translatable->getOriginalPage() etc.
ENHANCEMENT Hooking Translatable into ModelAsController and ContentController initialization in order to call choose_site_lang()
ENHANCEMENT Simplified Translatable->augmentSQL(), augmentWrite() by not using auxilliary tables
ENHANCEMENT Showing clickable links for Translations in Translatable->updateCMSFields()
BUGFIX Modifying Hierarchy/SiteTree Children getters to accept optional "context" which can be used to set a language explicitly through the $Lang property, rather than implicitly reyling on the static Translatable::current_lang()
BUGFIX Fixed TranslatableTest to work with new datamodel
BUGFIX Temporarily disabled cookie/session selection in Translatable::choose_site_lang() until we have a good test suite for the side effects.
MINOR Added "untranslated" CSS styles to tree nodes and marking them as inactive/grey
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@69959 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-01-10 13:15:30 +01:00
2009-03-20 09:49:27 +01:00
$this -> Locale = $langCode ;
2009-05-17 07:36:51 +02:00
Translatable :: set_current_locale ( $langCode );
Merged, debugged and enhanced Translatable patches from branches/translatable at r64523, r64523, 64523, thanks wakeless!
API CHANGE Changed Translatable schema from auxilliary tables (SiteTree_lang, SiteTree_lang_Live) to automatically filtered records on the original table (SiteTree, SiteTree_Live), using $Lang and $OriginalID properties. Incompatible update to old schema, migration script is in the works.
API CHANGE Removed Translatable::get_one(), Translatable::write()
ENHANCEMENT Simplified Translatable tree generation by using getSiteTreeFor() in CMSMain->createtranslation()
ENHANCEMENT Added AllChildrenIncludingDeleted(), augmentNumChildrenCountQuery(), augmentAllChildrenIncludingDeleted(), augmentStageChildren() to Translatable class to allow for more stable tree generation.
ENHANCEMENT Moved definition of Translatable schema from augmentDatabase() to Translatable->extraStatics()
ENHANCEMENT Changes to the CMS language selection refresh the whole admin interface instead of the tree only. This way we can add a URL parameter ?lang=<lang> to /admin, which makes the specific language bookmarkable and reloadable. Changes to LangSelector.js
ENHANCEMENT Added fallback to ModelAsController->getNestedController() to fetch page with matching URLSegment but different language in case no page is found in the current language.
ENHANCEMENT Added helper methods to Translatable: getTranslation(), hasTranslation(), isTranslation(), findOriginalIDs()
ENHANCEMENT Getters and setters for Translatable->getOriginalPage() etc.
ENHANCEMENT Hooking Translatable into ModelAsController and ContentController initialization in order to call choose_site_lang()
ENHANCEMENT Simplified Translatable->augmentSQL(), augmentWrite() by not using auxilliary tables
ENHANCEMENT Showing clickable links for Translations in Translatable->updateCMSFields()
BUGFIX Modifying Hierarchy/SiteTree Children getters to accept optional "context" which can be used to set a language explicitly through the $Lang property, rather than implicitly reyling on the static Translatable::current_lang()
BUGFIX Fixed TranslatableTest to work with new datamodel
BUGFIX Temporarily disabled cookie/session selection in Translatable::choose_site_lang() until we have a good test suite for the side effects.
MINOR Added "untranslated" CSS styles to tree nodes and marking them as inactive/grey
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@69959 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-01-10 13:15:30 +01:00
2009-03-18 18:18:52 +01:00
// Create a new record in the database - this is different
// to the usual "create page" pattern of storing the record
// in-memory until a "save" is performed by the user, mainly
// to simplify things a bit.
// @todo Allow in-memory creation of translations that don't persist in the database before the user requests it
2009-01-16 05:16:19 +01:00
$translatedRecord = $record -> createTranslation ( $langCode );
2007-09-16 18:32:30 +02:00
2009-01-16 05:16:19 +01:00
$url = sprintf (
2009-03-20 09:49:27 +01:00
" %s/%d/?locale=%s " ,
2009-01-16 05:16:19 +01:00
$this -> Link ( 'show' ),
$translatedRecord -> ID ,
$langCode
);
FormResponse :: add ( sprintf ( 'window.location.href = "%s";' , $url ));
return FormResponse :: respond ();
2007-09-16 18:32:30 +02:00
}
2007-07-19 12:40:05 +02:00
/**
* Provide the permission codes used by LeftAndMain .
* Can 't put it on LeftAndMain since that' s an abstract base class .
*/
function providePermissions () {
$classes = ClassInfo :: subclassesFor ( 'LeftAndMain' );
2007-09-15 23:54:24 +02:00
2007-07-19 12:40:05 +02:00
foreach ( $classes as $class ) {
2009-01-05 07:17:59 +01:00
$title = _t ( " { $class } .MENUTITLE " , LeftAndMain :: menu_title_for_class ( $class ));
$perms [ " CMS_ACCESS_ " . $class ] = sprintf (
_t (
'CMSMain.ACCESS' ,
" Access to '%s' (%s) " ,
PR_MEDIUM ,
" Item in permission selection identifying the admin section, with title and classname. Example: Access to 'Files & Images' (AssetAdmin) "
),
$title ,
$class
);
2007-07-19 12:40:05 +02:00
}
2009-01-05 07:17:59 +01:00
$perms [ " CMS_ACCESS_LeftAndMain " ] = _t (
'CMSMain.ACCESSALLINTERFACES' ,
'Access to all CMS interfaces'
);
2007-07-19 12:40:05 +02:00
return $perms ;
}
2009-01-05 07:17:59 +01:00
2007-09-16 18:32:30 +02:00
/**
2009-03-18 18:18:52 +01:00
* Returns all languages with languages already used appearing first .
* Called by the SSViewer when rendering the template .
*/
function LangSelector () {
2009-10-05 22:41:54 +02:00
$member = Member :: currentUser ();
$dropdown = new LanguageDropdownField (
'LangSelector' ,
'Language' ,
array (),
'SiteTree' ,
'Locale-English' ,
singleton ( 'SiteTree' )
);
$dropdown -> setValue ( Translatable :: get_current_locale ());
return $dropdown ;
2009-03-18 18:18:52 +01:00
}
2007-09-16 18:32:30 +02:00
/**
2009-03-18 18:18:52 +01:00
* Determine if there are more than one languages in our site tree .
*
* @ return boolean
2007-09-16 18:32:30 +02:00
*/
function MultipleLanguages () {
2009-01-10 12:36:30 +01:00
$langs = Translatable :: get_existing_content_languages ( 'SiteTree' );
2007-09-16 22:53:31 +02:00
return ( count ( $langs ) > 1 );
2007-09-16 18:32:30 +02:00
}
2009-03-18 18:18:52 +01:00
/**
* @ return boolean
*/
function IsTranslatableEnabled () {
2009-05-13 08:02:31 +02:00
return Object :: has_extension ( 'SiteTree' , 'Translatable' );
2007-09-16 18:32:30 +02:00
}
2007-07-19 12:40:05 +02:00
}
2007-09-19 16:04:50 +02:00
2009-05-18 01:19:51 +02:00
class CMSMainMarkingFilter {
function __construct () {
$this -> ids = array ();
$this -> expanded = array ();
$where = array ();
// Match against URLSegment, Title, MenuTitle & Content
if ( isset ( $_REQUEST [ 'SiteTreeSearchTerm' ])) {
$term = Convert :: raw2sql ( $_REQUEST [ 'SiteTreeSearchTerm' ]);
$where [] = " \" URLSegment \" LIKE '% $term %' OR \" Title \" LIKE '% $term %' OR \" MenuTitle \" LIKE '% $term %' OR \" Content \" LIKE '% $term %' " ;
2007-11-15 23:46:52 +01:00
}
2009-05-18 01:19:51 +02:00
// Match against date
if ( isset ( $_REQUEST [ 'SiteTreeFilterDate' ])) {
$date = $_REQUEST [ 'SiteTreeFilterDate' ];
$date = (( int ) substr ( $date , 6 , 4 )) . '-' . (( int ) substr ( $date , 3 , 2 )) . '-' . (( int ) substr ( $date , 0 , 2 ));
$where [] = " \" LastEdited \" > ' $date ' " ;
2007-09-16 17:19:17 +02:00
}
2009-05-18 01:19:51 +02:00
// Match against exact ClassName
if ( isset ( $_REQUEST [ 'ClassName' ]) && $_REQUEST [ 'ClassName' ] != 'All' ) {
$klass = Convert :: raw2sql ( $_REQUEST [ 'ClassName' ]);
$where [] = " \" ClassName \" = ' $klass ' " ;
2007-09-16 17:19:17 +02:00
}
2007-11-15 23:46:52 +01:00
2009-05-18 01:19:51 +02:00
// Partial string match against a variety of fields
foreach ( CMSMain :: T_SiteTreeFilterOptions () as $key => $value ) {
if ( ! empty ( $_REQUEST [ $key ])) {
$match = Convert :: raw2sql ( $_REQUEST [ $key ]);
$where [] = " \" $key\ " LIKE '%$match%' " ;
2007-09-16 17:19:17 +02:00
}
}
2009-05-18 01:19:51 +02:00
$where = empty ( $where ) ? '' : 'WHERE (' . implode ( ') AND (' , $where ) . ')' ;
$parents = array ();
/* Do the actual search */
$res = DB :: query ( 'SELECT "ParentID", "ID" FROM "SiteTree" ' . $where );
if ( ! $res ) return ;
/* And keep a record of parents we don't need to get parents of themselves, as well as IDs to mark */
foreach ( $res as $row ) {
if ( $row [ 'ParentID' ]) $parents [ $row [ 'ParentID' ]] = true ;
$this -> ids [ $row [ 'ID' ]] = true ;
2007-09-16 17:19:17 +02:00
}
2007-11-15 23:46:52 +01:00
2009-05-18 01:19:51 +02:00
/* We need to recurse up the tree, finding ParentIDs for each ID until we run out of parents */
while ( ! empty ( $parents )) {
$res = DB :: query ( 'SELECT "ParentID", "ID" FROM "SiteTree" WHERE "ID" in (' . implode ( ',' , array_keys ( $parents )) . ')' );
$parents = array ();
foreach ( $res as $row ) {
if ( $row [ 'ParentID' ]) $parents [ $row [ 'ParentID' ]] = true ;
$this -> ids [ $row [ 'ID' ]] = true ;
$this -> expanded [ $row [ 'ID' ]] = true ;
}
}
}
function mark ( $node ) {
$id = $node -> ID ;
2009-05-26 06:06:33 +02:00
if ( array_key_exists (( int ) $id , $this -> expanded )) $node -> markOpened ();
return array_key_exists (( int ) $id , $this -> ids ) ? $this -> ids [ $id ] : false ;
2007-09-16 17:19:17 +02:00
}
}
2007-07-19 12:40:05 +02:00
2009-04-29 03:44:28 +02:00
?>