Вход Регистрация
Файл: cms/tasks/RemoveOrphanedPagesTask.php
Строк: 363
<?php
/**
 * Identify "orphaned" pages which point to a parent
 * that no longer exists in a specific stage.
 * Shows the pages to an administrator, who can then
 * decide which pages to remove by ticking a checkbox
 * and manually executing the removal.
 * 
 * Caution: Pages also count as orphans if they don't
 * have parents in this stage, even if the parent has a representation
 * in the other stage:
 * - A live child is orphaned if its parent was deleted from live, but still exists on stage
 * - A stage child is orphaned if its parent was deleted from stage, but still exists on live
 *
 * See {@link RemoveOrphanedPagesTaskTest} for an example sitetree
 * before and after orphan removal.
 *
 * @author Ingo Schommer (<firstname>@silverstripe.com), SilverStripe Ltd.
 * 
 * @package cms
 * @subpackage tasks
 */
//class RemoveOrphanedPagesTask extends BuildTask {
class RemoveOrphanedPagesTask extends Controller {
    
    private static 
$allowed_actions = array(
        
'index' => 'ADMIN',
        
'Form' => 'ADMIN',
        
'run' => 'ADMIN',
        
'handleAction' => 'ADMIN',
    );
    
    protected 
$title 'Removed orphaned pages without existing parents from both stage and live';
    
    protected 
$description "
<p>
Identify 'orphaned' pages which point to a parent
that no longer exists in a specific stage.
</p>
<p>
Caution: Pages also count as orphans if they don't
have parents in this stage, even if the parent has a representation
in the other stage:<br />
- A live child is orphaned if its parent was deleted from live, but still exists on stage<br />
- A stage child is orphaned if its parent was deleted from stage, but still exists on live
</p>
    "
;
    
    protected 
$orphanedSearchClass 'SiteTree';
    
    public function 
Link() {
        return 
$this->class;
    }
    
    public function 
init() {
        
parent::init();
        
        if(!
Permission::check('ADMIN')) {
            return 
Security::permissionFailure($this);
        }
    }
    
    public function 
index() {
        
Requirements::javascript(FRAMEWORK_DIR '/thirdparty/jquery/jquery.js');
        
Requirements::customCSS('#OrphanIDs .middleColumn {width: auto;}');
        
Requirements::customCSS('#OrphanIDs label {display: inline;}');
        
        return 
$this->renderWith('BlankPage');
    }
    
    public function 
Form() {
        
$fields = new FieldList();
        
$source = array();
        
        
$fields->push(new HeaderField(
            
'Header',
            
_t('RemoveOrphanedPagesTask.HEADER''Remove all orphaned pages task')
        ));
        
$fields->push(new LiteralField(
            
'Description',
            
$this->description
        
));
        
        
$orphans $this->getOrphanedPages($this->orphanedSearchClass);
        if(
$orphans) foreach($orphans as $orphan) {
            
$latestVersion Versioned::get_latest_version($this->orphanedSearchClass$orphan->ID);
            
$latestAuthor DataObject::get_by_id('Member'$latestVersion->AuthorID);
            
$orphanBaseClass ClassInfo::baseDataClass($this->orphanedSearchClass);
            
$stageRecord Versioned::get_one_by_stage(
                
$this->orphanedSearchClass
                
'Stage',
                array(
""$orphanBaseClass"."ID"" => $orphan->ID)
            );
            
$liveRecord Versioned::get_one_by_stage(
                
$this->orphanedSearchClass
                
'Live'
                array(
""$orphanBaseClass"."ID"" => $orphan->ID)
            );
            
$label sprintf(
                
'<a href="admin/pages/edit/show/%d">%s</a> <small>(#%d, Last Modified Date: %s, Last Modifier: %s, %s)</small>',
                
$orphan->ID,
                
$orphan->Title,
                
$orphan->ID,
                
Date::create($orphan->LastEdited)->Nice(),
                (
$latestAuthor) ? $latestAuthor->Title 'unknown',
                (
$liveRecord) ? 'is published' 'not published'
            
);
            
$source[$orphan->ID] = $label;
        }
        
        if(
$orphans && $orphans->Count()) {
            
$fields->push(new CheckboxSetField('OrphanIDs'false$source));
            
$fields->push(new LiteralField(
                
'SelectAllLiteral',
                
sprintf(
                    
'<p><a href="#" onclick="javascript:jQuery('#Form_Form_OrphanIDs :checkbox').attr('checked', 'checked'); return false;">%s</a>&nbsp;',
                    
_t('RemoveOrphanedPagesTask.SELECTALL''select all')
                )
            ));
            
$fields->push(new LiteralField(
                
'UnselectAllLiteral',
                
sprintf(
                    
'<a href="#" onclick="javascript:jQuery('#Form_Form_OrphanIDs :checkbox').attr('checked', ''); return false;">%s</a></p>',
                    
_t('RemoveOrphanedPagesTask.UNSELECTALL''unselect all')
                )
            ));
            
$fields->push(new OptionSetField(
                
'OrphanOperation'
                
_t('RemoveOrphanedPagesTask.CHOOSEOPERATION''Choose operation:'),
                array(
                    
'rebase' => _t(
                        
'RemoveOrphanedPagesTask.OPERATION_REBASE'
                        
sprintf(
                            
'Rebase selected to a new holder page "%s" and unpublish. None of these pages will show up for website visitors.',
                            
$this->rebaseHolderTitle()
                        )
                    ),
                    
'remove' => _t('RemoveOrphanedPagesTask.OPERATION_REMOVE''Remove selected from all stages (WARNING: Will destroy all selected pages from both stage and live)'),
                ),
                
'rebase'
            
));
            
$fields->push(new LiteralField(
                
'Warning',
                
sprintf('<p class="message">%s</p>',
                    
_t(
                        
'RemoveOrphanedPagesTask.DELETEWARNING'
                        
'Warning: These operations are not reversible. Please handle with care.'
                    
)
                )
            ));
        } else {
            
$fields->push(new LiteralField(
                
'NotFoundLabel',
                
sprintf(
                    
'<p class="message">%s</p>',
                    
_t('RemoveOrphanedPagesTask.NONEFOUND''No orphans found')
                )
            ));
        }
        
        
$form = new Form(
            
$this,
            
'Form',
            
$fields,
            new 
FieldList(
                new 
FormAction('doSubmit'_t('RemoveOrphanedPagesTask.BUTTONRUN''Run'))
            )
        );
        
        if(!
$orphans || !$orphans->Count()) {
            
$form->makeReadonly();
        }
        
        return 
$form;
    }
    
    public function 
run($request) {
        
// @todo Merge with BuildTask functionality
    
}
    
    public function 
doSubmit($data$form) {
        
set_time_limit(60*10); // 10 minutes
        
        
if(!isset($data['OrphanIDs']) || !isset($data['OrphanOperation'])) return false;
        
        switch(
$data['OrphanOperation']) {
            case 
'remove':
                
$successIDs $this->removeOrphans($data['OrphanIDs']);
                break;
            case 
'rebase':
                
$successIDs $this->rebaseOrphans($data['OrphanIDs']);
                break;
            default:
                
user_error(sprintf("Unknown operation: '%s'"$data['OrphanOperation']), E_USER_ERROR);
        }
        
        
$content '';
        if(
$successIDs) {
            
$content .= "<ul>";
            foreach(
$successIDs as $id => $label) {
                
$content .= sprintf('<li>%s</li>'$label);
            }
            
$content .= "</ul>";
        } else {
            
$content _t('RemoveOrphanedPagesTask.NONEREMOVED''None removed');
        }
        
        return 
$this->customise(array(
            
'Content' => $content,
            
'Form' => ' '
        
))->renderWith('BlankPage');
    }
    
    protected function 
removeOrphans($orphanIDs) {
        
$removedOrphans = array();
        
$orphanBaseClass ClassInfo::baseDataClass($this->orphanedSearchClass);
        foreach(
$orphanIDs as $id) {
            
$stageRecord Versioned::get_one_by_stage(
                
$this->orphanedSearchClass
                
'Stage'
                array(
""$orphanBaseClass"."ID"" => $id)
            );
            if(
$stageRecord) {
                
$removedOrphans[$stageRecord->ID] = sprintf('Removed %s (#%d) from Stage'$stageRecord->Title$stageRecord->ID);
                
$stageRecord->delete();
                
$stageRecord->destroy();
                unset(
$stageRecord);
            }
            
$liveRecord Versioned::get_one_by_stage(
                
$this->orphanedSearchClass
                
'Live'
                array(
""$orphanBaseClass"."ID"" => $id)
            );
            if(
$liveRecord) {
                
$removedOrphans[$liveRecord->ID] = sprintf('Removed %s (#%d) from Live'$liveRecord->Title$liveRecord->ID);
                
$liveRecord->doDeleteFromLive();
                
$liveRecord->destroy();
                unset(
$liveRecord);
            }
        }
        
        return 
$removedOrphans;
    }
    
    protected function 
rebaseHolderTitle() {
        return 
sprintf('Rebased Orphans (%s)'date('d/m/Y g:ia'time()));
    }
    
    protected function 
rebaseOrphans($orphanIDs) {
        
$holder = new SiteTree();
        
$holder->ShowInMenus 0;
        
$holder->ShowInSearch 0;
        
$holder->ParentID 0;
        
$holder->Title $this->rebaseHolderTitle();
        
$holder->write();
        
        
$removedOrphans = array();
        
$orphanBaseClass ClassInfo::baseDataClass($this->orphanedSearchClass);
        foreach(
$orphanIDs as $id) {
            
$stageRecord Versioned::get_one_by_stage(
                
$this->orphanedSearchClass
                
'Stage',
                array(
""$orphanBaseClass"."ID"" => $id)
            );
            if(
$stageRecord) {
                
$removedOrphans[$stageRecord->ID] = sprintf('Rebased %s (#%d)'$stageRecord->Title$stageRecord->ID);
                
$stageRecord->ParentID $holder->ID;
                
$stageRecord->ShowInMenus 0;
                
$stageRecord->ShowInSearch 0;
                
$stageRecord->write();
                
$stageRecord->doUnpublish();
                
$stageRecord->destroy();
                
//unset($stageRecord);
            
}
            
$liveRecord Versioned::get_one_by_stage(
                
$this->orphanedSearchClass
                
'Live',
                array(
""$orphanBaseClass"."ID"" => $id)
            );
            if(
$liveRecord) {
                
$removedOrphans[$liveRecord->ID] = sprintf('Rebased %s (#%d)'$liveRecord->Title$liveRecord->ID);
                
$liveRecord->ParentID $holder->ID;
                
$liveRecord->ShowInMenus 0;
                
$liveRecord->ShowInSearch 0;
                
$liveRecord->write();
                if(!
$stageRecord$liveRecord->doRestoreToStage();
                
$liveRecord->doUnpublish();
                
$liveRecord->destroy();
                unset(
$liveRecord);
            }
            if(
$stageRecord) {
                unset(
$stageRecord);
            }
        }
        
        return 
$removedOrphans;
    }
    
    
/**
     * Gets all orphans from "Stage" and "Live" stages.
     * 
     * @param string $class
     * @param array $filter
     * @param string $sort
     * @param string $join
     * @param int|array $limit
     * @return SS_List
     */
    
public function getOrphanedPages($class 'SiteTree'$filter = array(), $sort null$join null$limit null) {
        
// Alter condition
        
if(empty($filter)) $where = array();
        elseif(
is_array($filter)) $where $filter;
        else 
$where = array($filter);
        
$where[] = array(""$class"."ParentID" != ?" => 0);
        
$where[] = '"Parents"."ID" IS NULL';
        
        
$orphans = new ArrayList();
        foreach(array(
'Stage''Live') as $stage) {
            
$joinByStage $join;
            
$table $class;
            
$table .= ($stage == 'Live') ? '_Live' '';
            
$stageOrphans Versioned::get_by_stage(
                
$class,
                
$stage,
                
$where,
                
$sort,
                
null,
                
$limit
            
)->leftJoin($table""$table"."ParentID" = "Parents"."ID"""Parents");
            
$orphans->merge($stageOrphans);
        }
        
        
$orphans->removeDuplicates();
    
        return 
$orphans;
    }
}
Онлайн: 2
Реклама