2007-07-19 12:40:28 +02:00
< ? php
/**
* The Versioned decorator allows your DataObjects to have several versions , allowing
* you to rollback changes and view history . An example of this is the pages used in the CMS .
2008-02-25 03:10:37 +01:00
* @ package sapphire
* @ subpackage model
2007-07-19 12:40:28 +02:00
*/
class Versioned extends DataObjectDecorator {
/**
* An array of possible stages .
* @ var array
*/
protected $stages ;
/**
* The 'default' stage .
* @ var string
*/
protected $defaultStage ;
/**
* The 'live' stage .
* @ var string
*/
protected $liveStage ;
/**
* A version that a DataObject should be when it is 'migrating' ,
* that is , when it is in the process of moving from one stage to another .
* @ var string
*/
public $migratingVersion ;
2009-01-07 07:02:12 +01:00
/**
* A cache used by get_versionnumber_by_stage () .
* Clear through { @ link flushCache ()} .
*
* @ var array
*/
protected static $cache_versionnumber ;
2007-07-19 12:40:28 +02:00
/**
* Construct a new Versioned object .
* @ var array $stages The different stages the versioned object can be .
* The first stage is consiedered the 'default' stage , the last stage is
* considered the 'live' stage .
*/
function __construct ( $stages ) {
parent :: __construct ();
if ( ! is_array ( $stages )) {
$stages = func_get_args ();
}
$this -> stages = $stages ;
$this -> defaultStage = reset ( $stages );
$this -> liveStage = array_pop ( $stages );
}
2008-11-02 01:36:57 +01:00
function extraStatics () {
2008-08-11 01:35:11 +02:00
return array (
'has_many' => array (
'Versions' => 'SiteTree' ,
)
);
}
2007-07-19 12:40:28 +02:00
function augmentSQL ( SQLQuery & $query ) {
// Get the content at a specific date
if ( $date = Versioned :: $reading_archived_date ) {
foreach ( $query -> from as $table => $dummy ) {
if ( ! isset ( $baseTable )) {
$baseTable = $table ;
}
$query -> renameTable ( $table , $table . '_versions' );
$query -> replaceText ( " .ID " , " .RecordID " );
$query -> select [] = " ` { $baseTable } _versions`.RecordID AS ID " ;
if ( $table != $baseTable ) {
$query -> from [ $table ] .= " AND ` { $table } _versions`.Version = ` { $baseTable } _versions`.Version " ;
}
}
// Link to the version archived on that date
$this -> requireArchiveTempTable ( $baseTable , $date );
$query -> from [ " _Archive $baseTable " ] = " INNER JOIN `_Archive $baseTable `
ON `_Archive$baseTable` . RecordID = `{$baseTable}_versions` . RecordID
AND `_Archive$baseTable` . Version = `{$baseTable}_versions` . Version " ;
// Get a specific stage
2007-09-16 18:15:47 +02:00
} else if ( Versioned :: $reading_stage && Versioned :: $reading_stage != $this -> defaultStage
&& array_search ( Versioned :: $reading_stage , $this -> stages ) !== false ) {
2007-07-19 12:40:28 +02:00
foreach ( $query -> from as $table => $dummy ) {
$query -> renameTable ( $table , $table . '_' . Versioned :: $reading_stage );
}
}
}
/**
* Create a temporary table mapping each database record to its version on the given date .
* This is used by the versioning system to return database content on that date .
* @ param string $baseTable The base table .
2009-04-30 07:38:48 +02:00
* @ param string $date The date . If omitted , then the latest version of each page will be returned .
2007-07-19 12:40:28 +02:00
*/
2009-04-30 07:38:48 +02:00
protected static function requireArchiveTempTable ( $baseTable , $date = null ) {
2009-05-01 06:34:11 +02:00
DB :: query ( " CREATE TEMPORARY TABLE IF NOT EXISTS _Archive $baseTable (
RecordID INT NOT NULL PRIMARY KEY ,
Version INT NOT NULL
) " );
if ( ! DB :: query ( " SELECT COUNT(*) FROM _Archive $baseTable " ) -> value ()) {
2009-04-30 07:38:48 +02:00
if ( $date ) $dateClause = " WHERE LastEdited <= ' $date ' " ;
else $dateClause = " " ;
2009-05-01 06:34:11 +02:00
2007-07-19 12:40:28 +02:00
DB :: query ( " INSERT INTO _Archive $baseTable
SELECT RecordID , max ( Version ) FROM { $baseTable } _versions
2009-04-30 07:38:48 +02:00
$dateClause
2007-07-19 12:40:28 +02:00
GROUP BY RecordID " );
}
}
2009-04-30 07:38:48 +02:00
2007-09-16 18:15:47 +02:00
/**
* An array of DataObject extensions that may require versioning for extra tables
2007-09-16 19:24:51 +02:00
* The array value is a set of suffixes to form these table names , assuming a preceding '_' .
* E . g . if Extension1 creates a new table 'Class_suffix1'
2007-09-16 18:15:47 +02:00
* and Extension2 the tables 'Class_suffix2' and 'Class_suffix3' :
*
* $versionableExtensions = array (
* 'Extension1' => 'suffix1' ,
* 'Extension2' => array ( 'suffix2' , 'suffix3' ),
* );
2007-09-16 19:24:51 +02:00
*
* Make sure your extension has a static $enabled - property that determines if it is
* processed by Versioned .
2007-09-16 18:15:47 +02:00
*
* @ var array
*/
protected static $versionableExtensions = array ( 'Translatable' => 'lang' );
2007-07-19 12:40:28 +02:00
function augmentDatabase () {
2007-09-16 18:15:47 +02:00
$classTable = $this -> owner -> class ;
// Build a list of suffixes whose tables need versioning
$allSuffixes = array ();
foreach ( Versioned :: $versionableExtensions as $versionableExtension => $suffixes ) {
2007-09-16 19:24:51 +02:00
if ( $this -> owner -> hasExtension ( $versionableExtension ) && singleton ( $versionableExtension ) -> stat ( 'enabled' )) {
2007-09-16 18:15:47 +02:00
$allSuffixes = array_merge ( $allSuffixes , ( array ) $suffixes );
foreach (( array ) $suffixes as $suffix ) {
$allSuffixes [ $suffix ] = $versionableExtension ;
}
}
}
2007-07-19 12:40:28 +02:00
2007-09-16 19:24:51 +02:00
// Add the default table with an empty suffix to the list (table name = class name)
2007-09-16 18:15:47 +02:00
array_push ( $allSuffixes , '' );
foreach ( $allSuffixes as $key => $suffix ) {
// check that this is a valid suffix
if ( ! is_int ( $key )) continue ;
if ( $suffix ) $table = " { $classTable } _ $suffix " ;
else $table = $classTable ;
2007-09-16 18:58:19 +02:00
if (( $fields = $this -> owner -> databaseFields ())) {
2007-09-16 19:24:51 +02:00
$indexes = $this -> owner -> databaseIndexes ();
if ( $this -> owner -> parentClass () == " DataObject " ) {
$rootTable = true ;
2007-09-16 18:15:47 +02:00
}
2008-02-25 03:10:37 +01:00
if ( $suffix && ( $ext = $this -> owner -> extInstance ( $allSuffixes [ $suffix ]))) {
2007-09-16 18:58:19 +02:00
if ( ! $ext -> isVersionedTable ( $table )) continue ;
$fields = $ext -> fieldsInExtraTables ( $suffix );
2007-09-16 18:15:47 +02:00
$indexes = $fields [ 'indexes' ];
$fields = $fields [ 'db' ];
2007-09-16 19:24:51 +02:00
}
2007-07-19 12:40:28 +02:00
2007-09-16 19:24:51 +02:00
// Create tables for other stages
foreach ( $this -> stages as $stage ) {
// Extra tables for _Live, etc.
if ( $stage != $this -> defaultStage ) {
DB :: requireTable ( " { $table } _ $stage " , $fields , $indexes );
/*
if ( ! DB :: query ( " SELECT * FROM { $table } _ $stage " ) -> value ()) {
$fieldList = implode ( " , " , array_keys ( $fields ));
DB :: query ( " INSERT INTO ` { $table } _ $stage ` (ID, $fieldList )
SELECT ID , $fieldList FROM `$table` " );
}
*/
}
// Version fields on each root table (including Stage)
if ( isset ( $rootTable )) {
$stageTable = ( $stage == $this -> defaultStage ) ? $table : " { $table } _ $stage " ;
DB :: requireField ( $stageTable , " Version " , " int(11) not null default '0' " );
2007-07-19 12:40:28 +02:00
}
}
2007-09-16 19:24:51 +02:00
// Create table for all versions
$versionFields = array_merge (
array (
" RecordID " => " Int " ,
" Version " => " Int " ,
" WasPublished " => " Boolean " ,
" AuthorID " => " Int " ,
" PublisherID " => " Int "
),
( array ) $fields
);
$versionIndexes = array_merge (
array (
'RecordID_Version' => '(RecordID, Version)' ,
'RecordID' => true ,
'Version' => true ,
2008-03-11 04:29:22 +01:00
'AuthorID' => true ,
'PublisherID' => true ,
2007-09-16 19:24:51 +02:00
),
( array ) $indexes
);
DB :: requireTable ( " { $table } _versions " , $versionFields , $versionIndexes );
/*
if ( ! DB :: query ( " SELECT * FROM { $table } _versions " ) -> value ()) {
$fieldList = implode ( " , " , array_keys ( $fields ));
DB :: query ( " INSERT INTO ` { $table } _versions` ( $fieldList , RecordID, Version)
SELECT $fieldList , ID AS RecordID , 1 AS Version FROM `$table` " );
}
*/
} else {
DB :: dontRequireTable ( " { $table } _versions " );
foreach ( $this -> stages as $stage ) {
if ( $stage != $this -> defaultStage ) DB :: dontrequireTable ( " { $table } _ $stage " );
2007-07-19 12:40:28 +02:00
}
2007-09-16 18:15:47 +02:00
}
2007-07-19 12:40:28 +02:00
}
}
/**
* Augment a write - record request .
* @ param SQLQuery $manipulation Query to augment .
*/
function augmentWrite ( & $manipulation ) {
$tables = array_keys ( $manipulation );
2007-09-16 18:15:47 +02:00
$version_table = array ();
2007-07-19 12:40:28 +02:00
foreach ( $tables as $table ) {
// Make sure that the augmented write is being applied to a table that can be versioned
2007-09-16 18:15:47 +02:00
if ( ! $this -> canBeVersioned ( $table ) ) {
2007-07-19 12:40:28 +02:00
// Debug::message( "$table doesn't exist or has no database fields" );
unset ( $manipulation [ $table ]);
continue ;
}
2007-09-16 18:15:47 +02:00
$id = $manipulation [ $table ][ 'id' ] ? $manipulation [ $table ][ 'id' ] : $manipulation [ $table ][ 'fields' ][ 'ID' ]; //echo 'id' .$id.' from '.$manipulation[$table]['id'].' and '.$manipulation[$table]['fields']['ID']."\n\n<br><br>";
if ( ! $id ) user_error ( " Couldn't find ID in " . var_export ( $manipulation [ $table ], true ), E_USER_ERROR );
2007-07-19 12:40:28 +02:00
2007-09-16 18:15:47 +02:00
$rid = isset ( $manipulation [ $table ][ 'RecordID' ]) ? $manipulation [ $table ][ 'RecordID' ] : $id ;
2007-07-19 12:40:28 +02:00
$newManipulation = array (
" command " => " insert " ,
" fields " => isset ( $manipulation [ $table ][ 'fields' ]) ? $manipulation [ $table ][ 'fields' ] : null
);
if ( $this -> migratingVersion ) {
$manipulation [ $table ][ 'fields' ][ 'Version' ] = $this -> migratingVersion ;
}
// If we haven't got a version #, then we're creating a new version. Otherwise, we're just
// copying a version to another table
if ( ! isset ( $manipulation [ $table ][ 'fields' ][ 'Version' ])) {
// Add any extra, unchanged fields to the version record.
2008-12-10 09:38:19 +01:00
$data = DB :: query ( " SELECT * FROM ` $table ` WHERE ID = $id " ) -> record ();
2007-07-19 12:40:28 +02:00
if ( $data ) foreach ( $data as $k => $v ) {
2007-09-16 18:58:19 +02:00
if ( ! isset ( $newManipulation [ 'fields' ][ $k ])) $newManipulation [ 'fields' ][ $k ] = " ' " . addslashes ( $v ) . " ' " ;
2007-07-19 12:40:28 +02:00
}
// Set up a new entry in (table)_versions
2007-09-16 18:15:47 +02:00
$newManipulation [ 'fields' ][ 'RecordID' ] = $rid ;
2007-07-19 12:40:28 +02:00
unset ( $newManipulation [ 'fields' ][ 'ID' ]);
// Create a new version #
2007-09-16 18:15:47 +02:00
if ( isset ( $version_table [ $table ])) $nextVersion = $version_table [ $table ];
else unset ( $nextVersion );
if ( $rid && ! isset ( $nextVersion )) $nextVersion = DB :: query ( " SELECT MAX(Version) + 1 FROM { $table } _versions WHERE RecordID = $rid " ) -> value ();
2007-07-19 12:40:28 +02:00
$newManipulation [ 'fields' ][ 'Version' ] = $nextVersion ? $nextVersion : 1 ;
$newManipulation [ 'fields' ][ 'AuthorID' ] = Member :: currentUserID () ? Member :: currentUserID () : 0 ;
$manipulation [ " { $table } _versions " ] = $newManipulation ;
// Add the version number to this data
$manipulation [ $table ][ 'fields' ][ 'Version' ] = $newManipulation [ 'fields' ][ 'Version' ];
2007-09-16 18:15:47 +02:00
$version_table [ $table ] = $nextVersion ;
2007-07-19 12:40:28 +02:00
}
// Putting a Version of -1 is a signal to leave the version table alone, despite their being no version
if ( $manipulation [ $table ][ 'fields' ][ 'Version' ] < 0 ) unset ( $manipulation [ $table ][ 'fields' ][ 'Version' ]);
2007-09-16 18:58:19 +02:00
if ( ! $this -> hasVersionField ( $table )) unset ( $manipulation [ $table ][ 'fields' ][ 'Version' ]);
2007-07-19 12:40:28 +02:00
// Grab a version number - it should be the same across all tables.
if ( isset ( $manipulation [ $table ][ 'fields' ][ 'Version' ])) $thisVersion = $manipulation [ $table ][ 'fields' ][ 'Version' ];
// If we're editing Live, then use (table)_Live instead of (table)
if ( Versioned :: $reading_stage && Versioned :: $reading_stage != $this -> defaultStage ) {
$newTable = $table . '_' . Versioned :: $reading_stage ;
$manipulation [ $newTable ] = $manipulation [ $table ];
unset ( $manipulation [ $table ]);
}
}
// Add the new version # back into the data object, for accessing after this write
2007-09-16 18:15:47 +02:00
if ( isset ( $thisVersion )) $this -> owner -> Version = str_replace ( " ' " , " " , $thisVersion );
}
2007-09-16 18:58:19 +02:00
/**
* Determine if a table is supporting the Versioned extensions ( e . g . $table_versions does exists )
*
* @ param string $table Table name
* @ return boolean
*/
2007-09-16 18:15:47 +02:00
function canBeVersioned ( $table ) {
Merging in refactored Translatable architecture from trunk, including related/required changesets like enhancements to Object static handling (see details below)
------------------------------------------------------------------------
r68900 | sminnee | 2008-12-15 14:30:41 +1300 (Mon, 15 Dec 2008) | 1 line
Static caching merges from dnc branch
------------------------------------------------------------------------
r68917 | sminnee | 2008-12-15 14:49:06 +1300 (Mon, 15 Dec 2008) | 1 line
Merged Requirements fix from nestedurls branch
------------------------------------------------------------------------
r70033 | aoneil | 2009-01-13 14:03:41 +1300 (Tue, 13 Jan 2009) | 2 lines
Add translation migration task
------------------------------------------------------------------------
r70072 | ischommer | 2009-01-13 17:34:27 +1300 (Tue, 13 Jan 2009) | 5 lines
API CHANGE Removed obsolete internal Translatable methods: hasOwnTranslatableFields(), allFieldsInTable()
ENHANCEMENT Removed $create flag in Translatable::getTranslation() and replaced with explit action createTranslation()
ENHANCEMENT Sorting return array of Translatable::getTranslatedLangs()
ENHANCEMENT Added a note about saving a page before creating a translation
MINOR Added phpdoc to Translatable
------------------------------------------------------------------------
r70073 | ischommer | 2009-01-13 17:34:45 +1300 (Tue, 13 Jan 2009) | 1 line
ENHANCEMENT Added basic unit tests to new Translatable API
------------------------------------------------------------------------
r70080 | aoneil | 2009-01-13 18:04:21 +1300 (Tue, 13 Jan 2009) | 3 lines
BUGFIX: Fix translatable migration regenerating URLSegments when it shouldn't
BUGFIX: Fix translatable migration not writing records to Live properly
------------------------------------------------------------------------
r70118 | ischommer | 2009-01-14 11:28:24 +1300 (Wed, 14 Jan 2009) | 3 lines
API CHANGE Removed obsolete Translatable::table_exists()
ENHANCEMENT Made Translatable constructor arguments optional, as by default all database fields are marked translatable
MINOR More unit tests for Translatable
------------------------------------------------------------------------
r70138 | ischommer | 2009-01-14 17:00:30 +1300 (Wed, 14 Jan 2009) | 1 line
BUGFIX Disabled assumption that SQLQuery->filtersOnID() should only kick in when exactly one WHERE clause is given - this is very fragile and hard to test. It would return TRUE on $where = "SiteTree.ID = 5", but not on $where = array("Lang = 'de'", "SiteTree.ID = 5")
------------------------------------------------------------------------
r70214 | ischommer | 2009-01-15 18:56:25 +1300 (Thu, 15 Jan 2009) | 3 lines
BUGFIX Falling back to Translatable::current_lang() if no $context object is given, in augmentAllChildrenIncludingDeleted() and AllChildrenIncludingDeleted()
MINOR phpdoc for Translatable
MINOR Added more Translatable unit tests
------------------------------------------------------------------------
r70306 | ischommer | 2009-01-16 17:14:34 +1300 (Fri, 16 Jan 2009) | 9 lines
ENHANCEMENT Recursively creating translations for parent pages to ensure that a translated page is still accessible by traversing the tree, e.g. in "cms translation mode" (in Translatable->onBeforeWrite())
ENHANCEMENT Simplified AllChildrenIncludingDeleted() to not require a special augmentAllChildrenIncludingDeleted() implementation: We don't combine untranslated/translated children any longer (which was used in CMS tree view), but rather just show translated records
ENHANCEMENT Ensuring uniqueness of URL segments by appending "-<langcode>" to new translations (in Translatable->onBeforeWrite())
ENHANCEMENT Added Translatable->alternateGetByUrl() as a hook into SiteTree::get_by_url()
ENHANCEMENT Adding link back to original page in CMS editform for translations
BUGFIX Excluding HiddenField instances from Translatable->updateCMSFields()
BUGFIX Don't require a record to be written (through exists()) when checking Translatable->isTranslation() or Translatable->hasTranslation()
MINOR Don't use createMethod() shortcut for Translatable->AllChildrenIncludingDeleted()
MINOR Added Translatable unit tests
------------------------------------------------------------------------
r70318 | ischommer | 2009-01-19 11:46:16 +1300 (Mon, 19 Jan 2009) | 1 line
BUGFIX Reverted special cases for Translatable in Versioned->canBeVersioned() (originally committed in r42119) - was checking for existence of underscores in table names as an indication of the "_lang" suffix, which is no longer needed. It was also a flawed assumption which tripped over classes like TranslatableTest_TestPage
------------------------------------------------------------------------
r70319 | ischommer | 2009-01-19 11:47:02 +1300 (Mon, 19 Jan 2009) | 1 line
ENHANCEMENT Disabled Translatab-e>augmentWrite() - was only needed for the blacklist fields implementation which is inactive for the moment
------------------------------------------------------------------------
r70326 | ischommer | 2009-01-19 14:25:23 +1300 (Mon, 19 Jan 2009) | 2 lines
ENHANCEMENT Making ErrorPage static HTML files translatable (#2233)
ENHANCEMENT Added ErrorPage::$static_filepath to flexibly set location of static error pages (defaults to /assets)
------------------------------------------------------------------------
r70327 | ischommer | 2009-01-19 15:18:41 +1300 (Mon, 19 Jan 2009) | 1 line
FEATURE Enabled specifying a language through a hidden field in SearchForm which limits the search to pages in this language (incl. unit tests)
------------------------------------------------------------------------
r71258 | sharvey | 2009-02-03 15:49:34 +1300 (Tue, 03 Feb 2009) | 2 lines
BUGFIX: Fix translatable being enabled when it shouldn't be
------------------------------------------------------------------------
r71340 | ischommer | 2009-02-04 14:36:12 +1300 (Wed, 04 Feb 2009) | 1 line
BUGFIX Including Hierarchy->children in flushCache() and renamed to _cache_children. This caused problems in TranslatableTest when re-using the same SiteTree->Children() method with different languages on the same object (even with calling flushCache() inbetween the calls)
------------------------------------------------------------------------
r71567 | gmunn | 2009-02-10 13:49:16 +1300 (Tue, 10 Feb 2009) | 1 line
'URLSegment' on line 484 and 494 now escaped
------------------------------------------------------------------------
r72054 | ischommer | 2009-02-23 10:30:41 +1300 (Mon, 23 Feb 2009) | 3 lines
BUGFIX Fixed finding a translated homepage without an explicit URLSegment (e.g. http://mysite.com/?lang=de) - see #3540
ENHANCEMENT Added Translatable::get_homepage_urlsegment_by_language()
ENHANCEMENT Added RootURLController::get_default_homepage_urlsegment()
------------------------------------------------------------------------
r72367 | ischommer | 2009-03-03 11:13:30 +1300 (Tue, 03 Mar 2009) | 2 lines
ENHANCEMENT Added i18n::get_lang_from_locale() and i18n::convert_rfc1766()
ENHANCEMENT Using IETF/HTTP compatible "long" language code in SiteTree->MetaTags(). This means the default <meta type="content-language..."> value will be "en-US" instead of "en". The locale can be either set through the Translatable content language, or through i18n::set_locale()
------------------------------------------------------------------------
r73036 | sminnee | 2009-03-14 13:16:32 +1300 (Sat, 14 Mar 2009) | 1 line
ENHANCEMENT #3032 ajshort: Use static methods for accessing static data
------------------------------------------------------------------------
r73059 | sminnee | 2009-03-15 14:09:59 +1300 (Sun, 15 Mar 2009) | 2 lines
ENHANCEMENT: Added Object::clearCache() to clear a cache
BUGFIX: Make object cache testing more robust
------------------------------------------------------------------------
r73338 | ischommer | 2009-03-19 05:13:40 +1300 (Thu, 19 Mar 2009) | 9 lines
API CHANGE Added concept of "translation groups" to Translatable- every page can belong to a group of related translations, rather than having an explicit "original", meaning you can have pages in "non-default" languages which have no representation in other language trees. This group is recorded in a new table "<classname>_translationgroups". Translatable->createTranslation() and Translatable->onBeforeWrite() will automatically associate records in this groups. Added Translatable->addTranslationGroup(), Translatable->removeTranslationGroup(), Translatable->getTranslationGroup()
API CHANGE Removed Translatable->isTranslation() - after the new "translation group" model, every page is potentially a translation
API CHANGE Translatable->findOriginalIDs(), Translatable->setOriginalPage(), Translatable->getOriginalPage()
ENHANCEMENT Translatable->getCMSFields() will now always show the "create translation" option, not only on default languages - meaning you can create translations based on other translations
ENHANCEMENT Translatable language dropdown in CMS will always show all available languages, rather than filtering by already existing translations
ENHANCEMENT Added check for an existing record in Translatable->createTranslation()
BUGFIX Removed Translatable->getLang() which overloaded the $db property - it was causing side effects during creation of SiteTree default records.
BUGFIX Added check in Translatable->augmentSQL() to avoid reapplying "Lang = ..." filter twice
BUGFIX Removed bypass in Translatable->AllChildrenIncludingDeleted()
------------------------------------------------------------------------
r73339 | ischommer | 2009-03-19 05:15:46 +1300 (Thu, 19 Mar 2009) | 1 line
BUGFIX Disabled "untranslated" CSS class for SiteTree elements - doesn't apply any longer with the new "translation groups" concept
------------------------------------------------------------------------
r73341 | ischommer | 2009-03-19 06:01:51 +1300 (Thu, 19 Mar 2009) | 1 line
BUGFIX Disabled auto-excluding of default language from the "available languages" array in LanguageDropdownField - due to the new "translation groups" its possible to have a translation from another language into the default language
------------------------------------------------------------------------
r73342 | ischommer | 2009-03-19 06:13:23 +1300 (Thu, 19 Mar 2009) | 4 lines
BUGFIX Setting ParentID of translated record if recursively creating parents in Translatable::onBeforeWrite()
BUGFIX Fixing inline form action for "create translation"
BUGFIX Removed link to "original page" for a translation - no longer valid
MINOR documentation for Translatable
------------------------------------------------------------------------
r73464 | ischommer | 2009-03-20 20:51:00 +1300 (Fri, 20 Mar 2009) | 1 line
MINOR documentation
------------------------------------------------------------------------
r73465 | ischommer | 2009-03-20 20:58:52 +1300 (Fri, 20 Mar 2009) | 1 line
BUGFIX Fixed Hierarchy->Children() testing in TranslatableTest - with the new datamodel you can't call Children() in a different language regardless of Translatable::set_reading_lang(), the Children() call has to be made from a parent in the same language
------------------------------------------------------------------------
r73466 | ischommer | 2009-03-20 21:36:40 +1300 (Fri, 20 Mar 2009) | 2 lines
ENHANCEMENT Added Translatable::get_locale_from_lang(), Translatable::get_common_locales(), $common_locales and $likely_subtags in preparation to switch Translatable from using short "lang" codes to proper long locales
API CHANGE Deprecated Translatable::set_default_lang(), Translatable::default_lang()
------------------------------------------------------------------------
r73467 | ischommer | 2009-03-20 21:38:57 +1300 (Fri, 20 Mar 2009) | 1 line
ENHANCEMENT Supporting "Locale-English" and "Locale-Native" as listing arguments in LanguageDropdownField
------------------------------------------------------------------------
r73468 | ischommer | 2009-03-20 21:47:06 +1300 (Fri, 20 Mar 2009) | 7 lines
ENHANCEMENT Adjusted SearchForm, Debug, ErrorPage, SiteTree to using locales instead of lang codes
API CHANGE Changed Translatable datamodel to use locales ("en_US") instead of lang values ("en).
API CHANGE Changed Translatable::$default_lang to $default_locale, Translatable::$reading_lang to $reading_locale
API CHANGE Using "locale" instead of "lang" in Translatable::choose_site_lang() to auto-detect language from cookies or GET parameters
API CHANGE Deprecated Translatable::is_default_lang(), set_default_lang(), get_default_lang(), current_lang(), set_reading_lang(), get_reading_lang(), get_by_lang(), get_one_by_lang()
API CHANGE Removed Translatable::get_original() - with the new "translation groups" concept there no longer is an original for a translation
BUGFIX Updated MigrateTranslatableTask to new Locale based datamodel
------------------------------------------------------------------------
r73470 | ischommer | 2009-03-20 21:56:57 +1300 (Fri, 20 Mar 2009) | 1 line
MINOR fixed typo
------------------------------------------------------------------------
r73472 | sminnee | 2009-03-21 17:30:04 +1300 (Sat, 21 Mar 2009) | 1 line
BUGFIX: Fixed translatable test execution by making protected methods public
------------------------------------------------------------------------
r73473 | sminnee | 2009-03-21 18:10:05 +1300 (Sat, 21 Mar 2009) | 1 line
ENHANCEMENT: Added Object::combined_static(), which gets all values of a static property from each class in the hierarchy
------------------------------------------------------------------------
r73883 | ischommer | 2009-04-01 08:32:19 +1300 (Wed, 01 Apr 2009) | 1 line
BUGFIX Making $_SINGLETONS a global instead of a static in Core.php so it can be re-used in other places
------------------------------------------------------------------------
r73951 | ischommer | 2009-04-02 05:35:32 +1300 (Thu, 02 Apr 2009) | 3 lines
API CHANGE Deprecated Translatable::enable() and i18n::enable()- use Object::add_extension('SiteTree','Translatable'), Deprecated Translatable::disable() and i18n::disable() - use Object::remove_extension('SiteTree','Translatable'), Deprecated Translatable::enabled() - use $myPage->hasExtension('Translatable')
API CHANGE Removed Translatable::creating_from() - doesn't apply any longer
ENHANCEMENT Translatable extension is no longer hooked up to SiteTree by default, which should improve performance and memory usage for sites not using Translatable. Please use Object::add_extension('SiteTree','Translatable') in your _config.php instead. Adjusted several classes (Image, ErrorPage, RootURLController) to the new behaviour.
------------------------------------------------------------------------
r73882 | ischommer | 2009-04-01 08:31:21 +1300 (Wed, 01 Apr 2009) | 1 line
ENHANCEMENT Added DataObjectDecorator->setOwner()
------------------------------------------------------------------------
r73884 | ischommer | 2009-04-01 08:32:51 +1300 (Wed, 01 Apr 2009) | 1 line
ENHANCEMENT Added Extension::get_classname_without_arguments()
------------------------------------------------------------------------
r73900 | ischommer | 2009-04-01 11:27:53 +1300 (Wed, 01 Apr 2009) | 7 lines
API CHANGE Deprecated Object->extInstance(), use getExtensionInstance() instead
ENHANCEMENT Added Object->getExtensionInstances()
ENHANCEMENT Added Object::get_extensions()
ENHANCEMENT Unsetting class caches when using Object::add_extension() to avoid problems with defineMethods etc.
BUGFIX Fixed extension comparison with case sensitivity and stripping arguments in Object::has_extension()
BUGFIX Unsetting all cached singletons in Object::remove_extension() to avoid outdated extension_instances
MINOR Documentation in Object
------------------------------------------------------------------------
r74017 | ischommer | 2009-04-03 10:49:40 +1300 (Fri, 03 Apr 2009) | 1 line
ENHANCEMENT Improved deprecated fallbacks in Translatable by auto-converting short language codes to long locales and vice versa through i18n::get_lang_from_locale()/i18n::get_locale_from_lang()
------------------------------------------------------------------------
r74030 | ischommer | 2009-04-03 11:41:26 +1300 (Fri, 03 Apr 2009) | 1 line
MINOR Re-added Translatable::default_lang() for more graceful fallback to Translatable::default_locale()
------------------------------------------------------------------------
r74065 | ischommer | 2009-04-04 05:38:51 +1300 (Sat, 04 Apr 2009) | 1 line
BUGFIX Re-added Translatable->isTranslation() for more friendly deprecation (originally removed in r73338)
------------------------------------------------------------------------
r74069 | ischommer | 2009-04-04 09:43:01 +1300 (Sat, 04 Apr 2009) | 1 line
BUGFIX Fixed legacy handling of Translatable::enable(),Translatable::disable() and Translatable::is_enabled() - applying extension to SiteTree instead of Page to avoid datamodel clashes
------------------------------------------------------------------------
r74070 | ischommer | 2009-04-04 10:23:51 +1300 (Sat, 04 Apr 2009) | 1 line
API CHANGE Deprecated Translatable::choose_site_lang(), use choose_site_locale()
------------------------------------------------------------------------
r74941 | ischommer | 2009-04-22 15:22:09 +1200 (Wed, 22 Apr 2009) | 2 lines
ENHANCEMENT Adding SapphireTest::set_up_once() and SapphireTest::tear_down_once() for better test performance with state that just needs to be initialized once per test case (not per test method). Added new SapphireTestSuite to support this through PHPUnit.
ENHANCEMENT Using set_up_once() in TranslatableTest and TranslatableSearchFormTest for better test run performance
------------------------------------------------------------------------
r74942 | ischommer | 2009-04-22 15:24:50 +1200 (Wed, 22 Apr 2009) | 1 line
BUGFIX Fixed TranslatableSearchFormTest->setUp() method
------------------------------------------------------------------------
r73509 | ischommer | 2009-03-23 11:59:14 +1300 (Mon, 23 Mar 2009) | 1 line
MINOR phpdoc documentation
------------------------------------------------------------------------
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/branches/2.3@74986 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-04-23 03:45:10 +02:00
$dbFields = singleton ( $table ) -> databaseFields ();
return ! ( ! ClassInfo :: exists ( $table ) || ! is_subclass_of ( $table , 'DataObject' ) || empty ( $dbFields ));
2007-09-16 18:15:47 +02:00
}
2007-09-16 18:58:19 +02:00
/**
* Check if a certain table has the 'Version' field
*
* @ param string $table Table name
* @ return boolean Returns false if the field isn ' t in the table , true otherwise
*/
function hasVersionField ( $table ) {
$tableParts = explode ( '_' , $table );
return ( 'DataObject' == get_parent_class ( $tableParts [ 0 ]));
}
2007-09-16 18:15:47 +02:00
function extendWithSuffix ( $table ) {
foreach ( Versioned :: $versionableExtensions as $versionableExtension => $suffixes ) {
if ( $this -> owner -> hasExtension ( $versionableExtension )) {
2008-02-25 03:10:37 +01:00
$table = $this -> owner -> extInstance ( $versionableExtension ) -> extendWithSuffix ( $table );
2007-09-16 18:15:47 +02:00
}
}
return $table ;
2007-07-19 12:40:28 +02:00
}
//-----------------------------------------------------------------------------------------------//
/**
* Get the latest published DataObject .
* @ return DataObject
*/
function latestPublished () {
// Get the root data object class - this will have the version field
$table1 = $this -> owner -> class ;
while ( ( $p = get_parent_class ( $table1 )) != " DataObject " ) $table1 = $p ;
$table2 = $table1 . " _ $this->liveStage " ;
return DB :: query ( " SELECT $table1 .Version = $table2 .Version FROM $table1 INNER JOIN $table2 ON $table1 .ID = $table2 .ID WHERE $table1 .ID = " . $this -> owner -> ID ) -> value ();
}
/**
* Move a database record from one stage to the other .
* @ param fromStage Place to copy from . Can be either a stage name or a version number .
* @ param toStage Place to copy to . Must be a stage name .
* @ param createNewVersion Set this to true to create a new version number . By default , the existing version number will be copied over .
*/
function publish ( $fromStage , $toStage , $createNewVersion = false ) {
$baseClass = $this -> owner -> class ;
while ( ( $p = get_parent_class ( $baseClass )) != " DataObject " ) $baseClass = $p ;
2007-09-16 18:15:47 +02:00
$extTable = $this -> extendWithSuffix ( $baseClass ); //die($extTable);
2007-07-19 12:40:28 +02:00
if ( is_numeric ( $fromStage )) {
$from = Versioned :: get_version ( $this -> owner -> class , $this -> owner -> ID , $fromStage );
} else {
$this -> owner -> flushCache ();
2007-08-16 08:38:15 +02:00
$from = Versioned :: get_one_by_stage ( $this -> owner -> class , $fromStage , " ` { $baseClass } `.`ID` = { $this -> owner -> ID } " );
2007-07-19 12:40:28 +02:00
}
2007-07-20 01:15:05 +02:00
$publisherID = isset ( Member :: currentUser () -> ID ) ? Member :: currentUser () -> ID : 0 ;
2007-07-19 12:40:28 +02:00
if ( $from ) {
$from -> forceChange ();
if ( ! $createNewVersion ) $from -> migrateVersion ( $from -> Version );
// Mark this version as having been published at some stage
2007-09-16 18:15:47 +02:00
DB :: query ( " UPDATE ` { $extTable } _versions` SET WasPublished = 1, PublisherID = $publisherID WHERE RecordID = $from->ID AND Version = $from->Version " );
2007-07-19 12:40:28 +02:00
$oldStage = Versioned :: $reading_stage ;
Versioned :: $reading_stage = $toStage ;
$from -> write ();
$from -> destroy ();
Versioned :: $reading_stage = $oldStage ;
} else {
user_error ( " Can't find { $this -> owner -> URLSegment } / { $this -> owner -> ID } in stage $fromStage " , E_USER_WARNING );
}
}
/**
* Set the migrating version .
* @ param string $version The version .
*/
function migrateVersion ( $version ) {
$this -> migratingVersion = $version ;
}
/**
* Compare two stages to see if they ' re different .
* Only checks the version numbers , not the actual content .
* @ param string $stage1 The first stage to check .
* @ param string $stage2
*/
function stagesDiffer ( $stage1 , $stage2 ) {
$table1 = $this -> baseTable ( $stage1 );
$table2 = $this -> baseTable ( $stage2 );
if ( ! is_numeric ( $this -> owner -> ID )) {
return true ;
}
// We test for equality - if one of the versions doesn't exist, this will be false
$stagesAreEqual = DB :: query ( " SELECT if(` $table1 `.Version=` $table2 `.Version,1,0) FROM ` $table1 ` INNER JOIN ` $table2 ` ON ` $table1 `.ID = ` $table2 `.ID AND ` $table1 `.ID = { $this -> owner -> ID } " ) -> value ();
return ! $stagesAreEqual ;
}
2008-08-11 01:35:11 +02:00
function Versions ( $filter = " " ) {
return $this -> allVersions ( $filter );
}
2007-07-19 12:40:28 +02:00
/**
* Return a list of all the versions available .
* @ param string $filter
*/
function allVersions ( $filter = " " ) {
2007-09-16 18:15:47 +02:00
$query = $this -> owner -> extendedSQL ( $filter , " " );
2007-07-19 12:40:28 +02:00
foreach ( $query -> from as $table => $join ) {
if ( $join [ 0 ] == '`' ) $baseTable = str_replace ( '`' , '' , $join );
2007-09-16 18:15:47 +02:00
else if ( substr ( $join , 0 , 5 ) != 'INNER' ) $query -> from [ $table ] = " LEFT JOIN ` $table ` ON ` $table `.RecordID = ` { $baseTable } _versions`.RecordID AND ` $table `.Version = ` { $baseTable } _versions`.Version " ;
2007-07-19 12:40:28 +02:00
$query -> renameTable ( $table , $table . '_versions' );
}
$query -> select [] = " ` { $baseTable } _versions`.AuthorID, ` { $baseTable } _versions`.Version, ` { $baseTable } _versions`.RecordID " ;
$query -> where [] = " ` { $baseTable } _versions`.RecordID = ' { $this -> owner -> ID } ' " ;
$query -> orderby = " ` { $baseTable } _versions`.LastEdited DESC, ` { $baseTable } _versions`.Version DESC " ;
$records = $query -> execute ();
$versions = new DataObjectSet ();
foreach ( $records as $record ) {
$versions -> push ( new Versioned_Version ( $record ));
}
return $versions ;
}
/**
* Compare two version , and return the diff between them .
* @ param string $from The version to compare from .
* @ param string $to The version to compare to .
* @ return DataObject
*/
function compareVersions ( $from , $to ) {
$fromRecord = Versioned :: get_version ( $this -> owner -> class , $this -> owner -> ID , $from );
$toRecord = Versioned :: get_version ( $this -> owner -> class , $this -> owner -> ID , $to );
2009-07-16 01:07:39 +02:00
$diff = new DataDifferencer ( $fromRecord , $toRecord );
return $diff -> diffedData ();
2007-07-19 12:40:28 +02:00
}
/**
* Return the base table - the class that directly extends DataObject .
* @ return string
*/
function baseTable ( $stage = null ) {
$tableClasses = ClassInfo :: dataClassesFor ( $this -> owner -> class );
$baseClass = array_shift ( $tableClasses );
return ( ! $stage || $stage == $this -> defaultStage ) ? $baseClass : $baseClass . " _ $stage " ;
}
//-----------------------------------------------------------------------------------------------//
/**
* Choose the stage the site is currently on .
* If $_GET [ 'stage' ] is set , then it will use that stage , and store it in the session .
* if $_GET [ 'archiveDate' ] is set , it will use that date , and store it in the session .
* If neither of these are set , it checks the session , otherwise the stage is set to 'Live' .
*/
static function choose_site_stage () {
if ( isset ( $_GET [ 'stage' ])) {
$_GET [ 'stage' ] = ucfirst ( strtolower ( $_GET [ 'stage' ]));
Session :: set ( 'currentStage' , $_GET [ 'stage' ]);
Session :: clear ( 'archiveDate' );
}
2007-11-09 04:40:05 +01:00
if ( isset ( $_GET [ 'archiveDate' ])) {
2007-07-19 12:40:28 +02:00
Session :: set ( 'archiveDate' , $_GET [ 'archiveDate' ]);
2007-11-09 04:40:05 +01:00
}
2007-07-19 12:40:28 +02:00
if ( Session :: get ( 'archiveDate' )) {
Versioned :: reading_archived_date ( Session :: get ( 'archiveDate' ));
} else if ( Session :: get ( 'currentStage' )) {
Versioned :: reading_stage ( Session :: get ( 'currentStage' ));
} else {
Versioned :: reading_stage ( " Live " );
}
}
/**
* Get the name of the 'live' stage .
* @ return string
*/
static function get_live_stage () {
return " Live " ;
}
/**
* Get the current reading stage .
* @ return string
*/
static function current_stage () {
return Versioned :: $reading_stage ;
}
/**
* Get the current archive date .
* @ return string
*/
static function current_archived_date () {
return Versioned :: $reading_archived_date ;
}
/**
* Set the reading stage .
* @ param string $stage New reading stage .
*/
static function reading_stage ( $stage ) {
Versioned :: $reading_stage = $stage ;
}
/**
* Set the reading archive date .
* @ param string $date New reading archived date .
*/
static function reading_archived_date ( $date ) {
Versioned :: $reading_archived_date = $date ;
}
/**
* Get a singleton instance of a class in the given stage .
2008-10-16 12:14:47 +02:00
*
2007-07-19 12:40:28 +02:00
* @ param string $class The name of the class .
* @ param string $stage The name of the stage .
* @ param string $filter A filter to be inserted into the WHERE clause .
2008-10-16 12:14:47 +02:00
* @ param boolean $cache Use caching .
* @ param string $orderby A sort expression to be inserted into the ORDER BY clause .
2007-07-19 12:40:28 +02:00
* @ return DataObject
*/
2008-10-16 12:14:47 +02:00
static function get_one_by_stage ( $class , $stage , $filter = '' , $cache = true , $orderby = '' ) {
2007-07-19 12:40:28 +02:00
$oldStage = Versioned :: $reading_stage ;
Versioned :: $reading_stage = $stage ;
singleton ( $class ) -> flushCache ();
2008-10-16 12:14:47 +02:00
$result = DataObject :: get_one ( $class , $filter , $cache , $orderby );
2007-07-19 12:40:28 +02:00
singleton ( $class ) -> flushCache ();
Versioned :: $reading_stage = $oldStage ;
return $result ;
}
2009-01-07 07:02:12 +01:00
/**
* Gets the current version number of a specific record .
*
* @ param string $class
* @ param string $stage
* @ param int $id
* @ param boolean $cache
* @ return int
*/
static function get_versionnumber_by_stage ( $class , $stage , $id , $cache = true ) {
$baseClass = ClassInfo :: baseDataClass ( $class );
$stageTable = ( $stage == 'Stage' ) ? $baseClass : " { $baseClass } _ { $stage } " ;
// cached call
if ( $cache && isset ( self :: $cache_versionnumber [ $baseClass ][ $stage ][ $id ])) {
return self :: $cache_versionnumber [ $baseClass ][ $stage ][ $id ];
}
// get version as performance-optimized SQL query (gets called for each page in the sitetree)
$version = DB :: query ( " SELECT Version FROM ` $stageTable ` WHERE ID = $id " ) -> value ();
// cache value (if required)
if ( $cache ) {
if ( ! isset ( self :: $cache_versionnumber [ $baseClass ])) self :: $cache_versionnumber [ $baseClass ] = array ();
if ( ! isset ( self :: $cache_versionnumber [ $baseClass ][ $stage ])) self :: $cache_versionnumber [ $baseClass ][ $stage ] = array ();
self :: $cache_versionnumber [ $baseClass ][ $stage ][ $id ] = $version ;
}
return $version ;
}
2009-01-12 03:45:14 +01:00
/**
* Pre - populate the cache for Versioned :: get_versionnumber_by_stage () for a list of record IDs ,
* for more efficient database querying . If $idList is null , then every page will be pre - cached .
*/
static function prepopulate_versionnumber_cache ( $class , $stage , $idList = null ) {
$filter = " " ;
if ( $idList ) {
// Validate the ID list
foreach ( $idList as $id ) if ( ! is_numeric ( $id )) user_error ( " Bad ID passed to Versioned::prepopulate_versionnumber_cache() in \$ idList: " . $id , E_USER_ERROR );
$filter = " WHERE ID IN( " . implode ( " , " , $idList ) . " ) " ;
}
$baseClass = ClassInfo :: baseDataClass ( $class );
$stageTable = ( $stage == 'Stage' ) ? $baseClass : " { $baseClass } _ { $stage } " ;
$versions = DB :: query ( " SELECT ID, Version FROM ` $stageTable ` $filter " ) -> map ();
foreach ( $versions as $id => $version ) {
self :: $cache_versionnumber [ $baseClass ][ $stage ][ $id ] = $version ;
}
}
2008-10-16 12:14:47 +02:00
/**
* Get a set of class instances by the given stage .
*
* @ param string $class The name of the class .
* @ param string $stage The name of the stage .
* @ param string $filter A filter to be inserted into the WHERE clause .
* @ param string $sort A sort expression to be inserted into the ORDER BY clause .
* @ param string $join A join expression , such as LEFT JOIN or INNER JOIN
* @ param int $limit A limit on the number of records returned from the database .
* @ param string $containerClass The container class for the result set ( default is DataObjectSet )
* @ return DataObjectSet
*/
static function get_by_stage ( $class , $stage , $filter = '' , $sort = '' , $join = '' , $limit = '' , $containerClass = 'DataObjectSet' ) {
2007-07-19 12:40:28 +02:00
$oldStage = Versioned :: $reading_stage ;
Versioned :: $reading_stage = $stage ;
2008-10-16 12:14:47 +02:00
$result = DataObject :: get ( $class , $filter , $sort , $join , $limit , $containerClass );
2007-07-19 12:40:28 +02:00
Versioned :: $reading_stage = $oldStage ;
return $result ;
}
function deleteFromStage ( $stage ) {
$oldStage = Versioned :: $reading_stage ;
Versioned :: $reading_stage = $stage ;
$result = $this -> owner -> delete ();
Versioned :: $reading_stage = $oldStage ;
return $result ;
}
function writeToStage ( $stage , $forceInsert = false ) {
$oldStage = Versioned :: $reading_stage ;
Versioned :: $reading_stage = $stage ;
$result = $this -> owner -> write ( false , $forceInsert );
Versioned :: $reading_stage = $oldStage ;
return $result ;
}
/**
* Build a SQL query to get data from the _version table .
* This function is similar in style to { @ link DataObject :: buildSQL }
*/
function buildVersionSQL ( $filter = " " , $sort = " " ) {
2007-09-16 18:15:47 +02:00
$query = $this -> owner -> extendedSQL ( $filter , $sort );
2007-07-19 12:40:28 +02:00
foreach ( $query -> from as $table => $join ) {
if ( $join [ 0 ] == '`' ) $baseTable = str_replace ( '`' , '' , $join );
else $query -> from [ $table ] = " LEFT JOIN ` $table ` ON ` $table `.RecordID = ` { $baseTable } _versions`.RecordID AND ` $table `.Version = ` { $baseTable } _versions`.Version " ;
$query -> renameTable ( $table , $table . '_versions' );
}
$query -> select [] = " ` { $baseTable } _versions`.AuthorID, ` { $baseTable } _versions`.Version, ` { $baseTable } _versions`.RecordID AS ID " ;
return $query ;
}
static function build_version_sql ( $className , $filter = " " , $sort = " " ) {
2007-09-16 18:15:47 +02:00
$query = singleton ( $className ) -> extendedSQL ( $filter , $sort );
2007-07-19 12:40:28 +02:00
foreach ( $query -> from as $table => $join ) {
if ( $join [ 0 ] == '`' ) $baseTable = str_replace ( '`' , '' , $join );
else $query -> from [ $table ] = " LEFT JOIN ` $table ` ON ` $table `.RecordID = ` { $baseTable } _versions`.RecordID AND ` $table `.Version = ` { $baseTable } _versions`.Version " ;
$query -> renameTable ( $table , $table . '_versions' );
}
$query -> select [] = " ` { $baseTable } _versions`.AuthorID, ` { $baseTable } _versions`.Version, ` { $baseTable } _versions`.RecordID AS ID " ;
return $query ;
}
/**
2009-01-07 07:02:12 +01:00
* Return the latest version of the given page .
*
* @ return DataObject
2007-07-19 12:40:28 +02:00
*/
static function get_latest_version ( $class , $id ) {
2008-02-25 03:10:37 +01:00
$oldStage = Versioned :: $reading_stage ;
Versioned :: $reading_stage = null ;
2007-07-19 12:40:28 +02:00
$baseTable = ClassInfo :: baseDataClass ( $class );
2007-09-16 18:15:47 +02:00
$query = singleton ( $class ) -> buildVersionSQL ( " ` { $baseTable } `.RecordID = $id " , " ` { $baseTable } `.Version DESC " );
2007-07-19 12:40:28 +02:00
$query -> limit = 1 ;
$record = $query -> execute () -> record ();
2009-05-12 03:56:37 +02:00
if ( ! $record ) return ;
2007-07-19 12:40:28 +02:00
$className = $record [ 'ClassName' ];
if ( ! $className ) {
Debug :: show ( $query -> sql ());
Debug :: show ( $record );
user_error ( " Versioned::get_version: Couldn't get $class . $id , version $version " , E_USER_ERROR );
}
2008-02-25 03:10:37 +01:00
Versioned :: $reading_stage = $oldStage ;
2007-07-19 12:40:28 +02:00
return new $className ( $record );
}
2009-04-30 07:38:48 +02:00
/**
* Return the equivalent of a DataObject :: get () call , querying the latest
* version of each page stored in the ( class ) _versions tables .
*
* In particular , this will query deleted records as well as active ones .
*/
static function get_including_deleted ( $class , $filter = " " , $sort = " " ) {
$oldStage = Versioned :: $reading_stage ;
Versioned :: $reading_stage = null ;
$SNG = singleton ( $class );
// Build query
$query = $SNG -> buildVersionSQL ( $filter , $sort );
$baseTable = ClassInfo :: baseDataClass ( $class );
self :: requireArchiveTempTable ( $baseTable );
$query -> from [ " _Archive $baseTable " ] = " INNER JOIN `_Archive $baseTable `
ON `_Archive$baseTable` . RecordID = `{$baseTable}_versions` . RecordID
AND `_Archive$baseTable` . Version = `{$baseTable}_versions` . Version " ;
// Process into a DataObjectSet
$result = $SNG -> buildDataObjectSet ( $query -> execute ());
Versioned :: $reading_stage = $oldStage ;
return $result ;
}
2007-07-19 12:40:28 +02:00
2009-01-07 07:02:12 +01:00
/**
* @ return DataObject
*/
2007-07-19 12:40:28 +02:00
static function get_version ( $class , $id , $version ) {
2008-02-25 03:10:37 +01:00
$oldStage = Versioned :: $reading_stage ;
Versioned :: $reading_stage = null ;
2007-07-19 12:40:28 +02:00
$baseTable = ClassInfo :: baseDataClass ( $class );
2007-09-16 18:15:47 +02:00
$query = singleton ( $class ) -> buildVersionSQL ( " ` { $baseTable } `.RecordID = $id AND ` { $baseTable } `.Version = $version " );
2007-07-19 12:40:28 +02:00
$record = $query -> execute () -> record ();
$className = $record [ 'ClassName' ];
if ( ! $className ) {
Debug :: show ( $query -> sql ());
Debug :: show ( $record );
user_error ( " Versioned::get_version: Couldn't get $class . $id , version $version " , E_USER_ERROR );
}
2008-02-25 03:10:37 +01:00
Versioned :: $reading_stage = $oldStage ;
2007-07-19 12:40:28 +02:00
return new $className ( $record );
}
2009-01-07 07:02:12 +01:00
/**
* @ return DataObject
*/
2007-07-19 12:40:28 +02:00
static function get_all_versions ( $class , $id , $version ) {
$baseTable = ClassInfo :: baseDataClass ( $class );
2007-09-16 18:15:47 +02:00
$query = singleton ( $class ) -> buildVersionSQL ( " ` { $baseTable } `.RecordID = $id AND ` { $baseTable } `.Version = $version " );
2007-07-19 12:40:28 +02:00
$record = $query -> execute () -> record ();
$className = $record [ ClassName ];
if ( ! $className ) {
Debug :: show ( $query -> sql ());
Debug :: show ( $record );
user_error ( " Versioned::get_version: Couldn't get $class . $id , version $version " , E_USER_ERROR );
}
return new $className ( $record );
}
2007-08-15 12:13:27 +02:00
function contentcontrollerInit ( $controller ) {
self :: choose_site_stage ();
}
function modelascontrollerInit ( $controller ) {
self :: choose_site_stage ();
}
2007-07-19 12:40:28 +02:00
protected static $reading_stage = null ;
protected static $reading_archived_date = null ;
2008-11-02 21:04:10 +01:00
function updateFieldLabels ( & $labels ) {
$labels [ 'Versions' ] = _t ( 'Versioned.has_many_Versions' , 'Versions' , PR_MEDIUM , 'Past Versions of this page' );
}
2009-01-07 07:02:12 +01:00
function flushCache () {
self :: $cache_versionnumber = array ();
}
2007-07-19 12:40:28 +02:00
}
/**
* Represents a single version of a record .
2008-02-25 03:10:37 +01:00
* @ package sapphire
* @ subpackage model
* @ see Versioned
2007-07-19 12:40:28 +02:00
*/
class Versioned_Version extends ViewableData {
protected $record ;
protected $object ;
function __construct ( $record ) {
$this -> record = $record ;
$record [ 'ID' ] = $record [ 'RecordID' ];
$className = $record [ 'ClassName' ];
$this -> object = new $className ( $record );
$this -> failover = $this -> object ;
parent :: __construct ();
}
function PublishedClass () {
return $this -> record [ 'WasPublished' ] ? 'published' : 'internal' ;
}
function Author () {
return DataObject :: get_by_id ( " Member " , $this -> record [ 'AuthorID' ]);
}
function Publisher () {
if ( ! $this -> record [ 'WasPublished' ] )
return null ;
return DataObject :: get_by_id ( " Member " , $this -> record [ 'PublisherID' ]);
}
function Published () {
return ! empty ( $this -> record [ 'WasPublished' ] );
}
}
2008-12-04 23:39:39 +01:00
?>