Source of file WorkflowRequest.php
Size: 32,967 Bytes - Last Modified: 2021-12-23T10:28:49+00:00
/var/www/docs.ssmods.com/process/src/code/WorkflowRequest.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938 | <?php /** * A "workflow request" represents a full review process for one set of changes to a single page. * Only one workflow request can be active for any given page; however, a page may have a number * of historical, closed workflow requests. * * The WorkflowRequest object shouldn't be directly edited. Instead, you call "workflow step" * methods on the object, that will update the object appropriately. * * To create or retrieve a WorkflowRequest object, call {@link SiteTreeCMSWorkflow::openOrNewWorkflowRequest()} * or {@link SiteTreeCMSWorkflow::openWorkflowRequest()} on the relevant {@link SiteTree} object. * * The following examples show how a workflow can be created. * * Request publication: * <code> * $wf = $page->openOrNewWorkflowRequest('WorkflowPublicationRequest') * $wf->request("Can you please publish this page"); * </code> * * Reject changes: * <code> * $wf = $page->openWorkflowRequest() * $wf->deny("It's not acceptable. Please correct the spelling."); * </code> * * Approve changes: * <code> * $wf = $page->openWorkflowRequest() * $wf->approve("Thanks, looks good now"); * </code> * * Make the changes 'go live' changes: * <code> * $wf = $page->openWorkflowRequest() * $wf->action(); * </code> * * {@link WorkflowRequest::Changes()} will provide a list of the changes that the workflow has gone through, * suitable for presentation as a discussion thread attached to the page. * * @package cmsworkflow */ class WorkflowRequest extends DataObject implements i18nEntityProvider { public static $db = array( // @todo AwaitingReview 'Status' => "Enum('AwaitingApproval,Approved,Scheduled,Completed,Denied,Cancelled,AwaitingEdit','AwaitingApproval')", 'EmbargoDate' => 'SS_Datetime' // actioned is true/false whether the change has actually happened on live ); public static $has_one = array( 'Author' => 'Member', 'Approver' => 'Member', 'Publisher' => 'Member', 'Page' => 'SiteTree' ); public static $has_many = array( 'Changes' => 'WorkflowRequestChange', ); public static $many_many = array( 'Approvers' => 'Member' ); public static $allow_deny = true; /** * Control who gets alerts for certain events * data structure is fairly self-explanitory * self::$alerts[CLASS][EVENT][USERROLE] = boolean * Not all event/role combinations are neccessairily * implemented by all ApprovalPaths. */ public static $alerts = null; public static $enable_all_alerts = false; protected $memberIdsEmailed = array(); /** * Factory method setting up a new WorkflowRequest with associated * state. Sets relations to publishers and authors, * * @param SiteTree $page * @param Member $member The user requesting publication * @param DataObjectSet $approvers Approvers assigned to this request. * @return boolean|WorkflowPublicationRequest */ public static function create_for_page($page, $author = null, $approvers = null) { user_error('WorkflowRequest::create_for_page() - Abstract method, please implement in subclass', E_USER_ERROR); } /** * Should we send an email to the following group under * these circumstances. Default to false. * */ public static function should_send_alert($class, $event, $group) { self::load_default_alerts(); if (self::$enable_all_alerts) { return true; } if (!isset(self::$alerts[$class])) { return false; } if (!isset(self::$alerts[$class][$event])) { return false; } if (!isset(self::$alerts[$class][$event][$group])) { return false; } return self::$alerts[$class][$event][$group]; } public static function set_alert($class, $event, $group, $notify) { self::load_default_alerts(); if (!isset(self::$alerts[$class])) { self::$alerts[$class] = array(); } if (!isset(self::$alerts[$class][$event])) { self::$alerts[$class][$event] = array(); } self::$alerts[$class][$event][$group] = $notify; } public static function load_default_alerts() { if (self::$alerts === null) { if (singleton('WorkflowRequest')->hasExtension('WorkflowTwoStepRequest')) { self::$alerts = WorkflowTwoStepRequest::$default_alerts; } if (singleton('WorkflowRequest')->hasExtension('WorkflowThreeStepRequest')) { self::$alerts = WorkflowThreeStepRequest::$default_alerts; } } } /** * Set this to true if publishers and admins can request new workflows. * This can be useful, for example for a publisher to modify * embargo and expiry in a workflow, they need to edit this in the workflow. * Or if they want to create a workflow for a change so it is tracked. */ protected static $publisher_can_create_wf_requests = true; public function set_publisher_can_create_wf_requests($val) { self::$publisher_can_create_wf_requests = $val; } /** * @ignore */ protected static $force_publishers_to_use_workflow = false; /** * Set this to true to force publishers to use the "Request publication" button, rather than * "Save & Publish". Workflow admins won't be affected by this change. */ public static function set_force_publishers_to_use_workflow($val) { self::$force_publishers_to_use_workflow = $val; } /** * Approve this request, notify interested parties * and close it. Used by {@link LeftAndMainCMSWorkflow} * and {@link SiteTreeCMSWorkflow}. * * @param Member $author * @return boolean */ public function request($comment, $member = null) { if (!$member) { $member = Member::currentUser(); } $this->Status = 'AwaitingApproval'; $this->write(); $this->addNewChange($comment, $this->Status, $member); $this->notifyAwaitingApproval($comment); return _t('SiteTreeCMSWorkflow.CHANGEREQUESTED', 'Requested this change. Emailed %s.'); } /** * Comment on a workflow item without changing the status */ public function comment($comment, $member = null, $notify = true) { if (!$member) { $member = Member::currentUser(); } // Switch to handle both 2 step & 3 step $page = $this->Page(); $isWorkflowParticipant = $page->canEdit($member) || $page->canPublish($member) || $page->canView($member); if ($page->hasMethod('canApprove')) { $isWorkflowParticipant = $isWorkflowParticipant || $page->canApprove($member); } // Don't let people who aren't workflow participants comment if (!$isWorkflowParticipant) { return false; } $this->addNewChange($comment, null, $member); if ($notify) { $this->notifyComment($comment); } return _t('SiteTreeCMSWorkflow.COMMENT_MESSAGE', 'Commented on this workflow request. Emailed %s.'); } /** * Request an edit to this page before it can be published. * * @param Member $author * @return boolean */ public function requestedit($comment, $member = null, $notify = true) { if (!$member) { $member = Member::currentUser(); } if (!$this->Page()->canRequestEdit($member)) { return false; } // "publisher" in this sense means "deny-author" $this->PublisherID = $member->ID; $this->write(); // open the request and notify interested parties $this->Status = 'AwaitingEdit'; $this->write(); $this->addNewChange($comment, $this->Status, $member); if ($notify) { $this->notifyAwaitingEdit($comment); } return _t('SiteTreeCMSWorkflow.CHANGEREQUESTED', 'Requested this change. Emailed %s.'); } /** * Deny this request, notify interested parties * and close it. Used by {@link LeftAndMainCMSWorkflow} * and {@link SiteTreeCMSWorkflow}. * * @param Member $author * @return boolean */ public function deny($comment, $member = null, $notify = true) { if (!self::$allow_deny) { return false; } if (!$member) { $member = Member::currentUser(); } if (!$this->Page()->canDenyRequests($member)) { return false; } // "publisher" in this sense means "deny-author" $this->ApproverID = $member->ID; $this->ActionerID = $member->ID; $this->Actioned = true; $this->write(); // open the request and notify interested parties $this->Status = 'Denied'; $this->write(); // revert page to live (which might undo independent changes by other authors) if (Versioned::get_one_by_stage('SiteTree', 'Live', "\"SiteTree_Live\".\"ID\" = ".$this->Page()->ID)) { $this->Page()->doRevertToLive(); } $this->addNewChange($comment, $this->Status, $member); if ($notify) { $this->notifyDenied($comment); } return _t('SiteTreeCMSWorkflow.DENYPUBLICATION_MESSAGE', 'Denied workflow request, and reset content. Emailed %s'); } /** * Cancel this request, notify interested parties * and close it. Used by {@link LeftAndMainCMSWorkflow} * and {@link SiteTreeCMSWorkflow}. * * @param Member $author * @return boolean */ public function cancel($comment, $member = null, $notify = true) { if (!$member) { $member = Member::currentUser(); } if (!$this->Page()->canEdit()) { return false; } // "publisher" in this sense means "deny-author" $this->ApproverID = $member->ID; $this->ActionerID = $member->ID; $this->Actioned = true; $this->write(); // open the request and notify interested parties $this->Status = 'Cancelled'; $this->write(); $this->addNewChange($comment, $this->Status, $member); if ($notify) { $this->notifyCancelled($comment); } return _t('SiteTreeCMSWorkflow.CANCELREQUEST_MESSAGE', 'Cancelled workflow request. Emailed %s'); } /** * Create a new {@link WorkflowRequestChange} with the current * page status and versions, and link it to this object. * * @return WorkflowRequestChange */ public function addNewChange($comment, $status, $member) { $bt = defined('DB::USE_ANSI_SQL') ? "\"" : "`"; $change = new WorkflowRequestChange(); $change->AuthorID = $member->ID; $change->Status = $status; $change->Comment = $comment; $page = $this->Page(); $draftPage = Versioned::get_one_by_stage('SiteTree', 'Draft', "{$bt}SiteTree{$bt}.{$bt}ID{$bt} = $page->ID", false, "\"Created\" DESC"); // draftpage might not exist for pages "deleted from stage" if ($draftPage) { $change->PageDraftVersion = $draftPage->Version; } $livePage = Versioned::get_one_by_stage('SiteTree', 'Live', "{$bt}SiteTree{$bt}.{$bt}ID{$bt} = $page->ID", false, "\"Created\" DESC"); // livepage might not exist for pages which have never been published if ($livePage) { $change->PageLiveVersion = $livePage->Version; } $change->write(); $this->Changes()->add($change); return $change; } public function getCMSFields() { $fields = parent::getCMSFields(); $diffLinkTitle = _t('SiteTreeCMSWorkflow.DIFFERENCESLINK', 'Show differences to live'); $tf = $fields->dataFieldByName('Changes'); $tf->setFieldList(array( 'Created' => $this->fieldLabel('Created'), 'Author.Title' => $this->fieldLabel('Author'), 'Comment' => $this->fieldLabel('Comment'), 'StatusDescription' => $this->fieldLabel('Status'), 'DiffLinkToLastPublished' => _t('SiteTreeCMSWorkflow.DIFFERENCESTOLIVECOLUMN', 'Differences to live'), 'DiffLinkContentToPrevious' => _t('SiteTreeCMSWorkflow.DIFFERENCESTHISCHANGECOLUMN', 'Differences in this change'), )); $tf->setFieldFormatting(array( "DiffLinkToLastPublished" => '<a href=\"$value\" target=\"_blank\" class=\"externallink\">Show</a>', // "DiffLinkToPrevious" => '<a href=\"$value\" target=\"_blank\" class=\"externallink\">Show</a>' )); $fields->replaceField( 'Status', new ReadonlyField('StatusDescription', $this->fieldLabel('Status'), $this->StatusDescription) ); return $fields; } public function ApprovalDate() { $bt = defined('DB::USE_ANSI_SQL') ? "\"" : "`"; $change = DataObject::get_one('WorkflowRequestChange', "{$bt}WorkflowRequestID{$bt} = {$this->ID} AND {$bt}Status{$bt} = 'Approved'", "{$bt}ID{$bt} DESC"); return $change ? $change->Created : null; } public function getCMSDetailFields() { $fields = $this->getFrontEndFields(); $fields->insertBefore( $titleField = new ReadonlyField( 'RequestTitleField', $this->fieldLabel('Title'), $this->getTitle() ), 'Status' ); $fields->push( $showDifferencesField = new ReadonlyField( 'ShowDifferencesLink', false, sprintf( '<a href="%s">%s</a>', $this->DiffLinkToLastPublished, _t('SiteTreeCMSWorkflow.DIFFERENCESTOLIVECOLUMN', 'Differences to live') ) ) ); $showDifferencesField->dontEscape = true; $fields->replaceField( 'Status', new ReadonlyField( 'StatusDescription', $this->fieldLabel('Status'), $this->StatusDescription ) ); return $fields; } /** * Return the field used for setting Embargo/Expiry date. * returns false if the field cant be used in this context */ public function EmbargoField() { $datetimeField = Object::create('DatetimeField', 'EmbargoDate', 'Embargo Date', $this->EmbargoDate); $datetimeField->getDateField()->setConfig('showcalendar', true); $datetimeField->getTimeField()->setConfig('showdropdown', true); $datetimeField->getDateField()->setConfig('dateformat', 'dd/MM/YYYY'); $datetimeField->getTimeField()->setConfig('timeformat', 'HH:mm'); return $datetimeField; } public function ExpiryField() { $datetimeField = Object::create('DatetimeField', 'ExpiryDate', 'Expiry Date', $this->ExpiryDate); $datetimeField->getDateField()->setConfig('showcalendar', true); $datetimeField->getTimeField()->setConfig('showdropdown', true); $datetimeField->getDateField()->setConfig('dateformat', 'dd/MM/YYYY'); $datetimeField->getTimeField()->setConfig('timeformat', 'HH:mm'); return $datetimeField; } public function getEmbargoDate() { return $this->getField('EmbargoDate') != '0000-00-00 00:00:00' && $this->getField('EmbargoDate') != null ? $this->getField('EmbargoDate') : null; } public function getExpiryDate() { return $this->ExpiryDate(); } public function ExpiryDate() { return $this->Page()->ExpiryDate != '0000-00-00 00:00:00' && $this->Page()->ExpiryDate != null ? $this->Page()->ExpiryDate : null; } public function WorkflowTimezone() { return date('T').', where is it currently '.date('r'); } /** * Return true/false whether we can currently change the PublishAt time */ public function CanChangeEmbargoExpiry() { return $this->Status == 'AwaitingApproval'; } public function notifyDenied($comment) { $emailsToSend = array(); $userWhoDenied = Member::currentUser(); if (WorkflowRequest::should_send_alert(get_class($this->owner), 'deny', 'publisher')) { $publishers = $this->owner->Page()->PublisherMembers(); foreach ($publishers as $publisher) { $emailsToSend[] = array($userWhoDenied, $publisher); } } if (WorkflowRequest::should_send_alert(get_class($this->owner), 'deny', 'approver') && $this->Page()->hasMethod('ApproverMembers')) { $approvers = $this->owner->Page()->ApproverMembers(); foreach ($approvers as $approver) { $emailsToSend[] = array($userWhoDenied, $approver); } } if (WorkflowRequest::should_send_alert(get_class($this->owner), 'deny', 'author')) { $emailsToSend[] = array($userWhoDenied, $this->owner->Author()); } if (count($emailsToSend)) { foreach ($emailsToSend as $email) { if ($email[1]->ID == Member::currentUserID()) { continue; } $this->owner->sendNotificationEmail( $email[0], // sender $email[1], // recipient $comment, 'denied the request' ); } } } public function notifyCancelled($comment) { $emailsToSend = array(); $userWhoCancelled = Member::currentUser(); if (WorkflowRequest::should_send_alert(get_class($this->owner), 'cancel', 'publisher')) { $publishers = $this->owner->Page()->PublisherMembers(); foreach ($publishers as $publisher) { $emailsToSend[] = array($userWhoCancelled, $publisher); } } if (WorkflowRequest::should_send_alert(get_class($this->owner), 'cancel', 'approver') && $this->Page()->hasMethod('ApproverMembers')) { $approvers = $this->owner->Page()->ApproverMembers(); foreach ($approvers as $approver) { $emailsToSend[] = array($userWhoCancelled, $approver); } } if (WorkflowRequest::should_send_alert(get_class($this->owner), 'cancel', 'author')) { $emailsToSend[] = array($userWhoCancelled, $this->owner->Author()); } if (count($emailsToSend)) { foreach ($emailsToSend as $email) { if ($email[1]->ID == Member::currentUserID()) { continue; } $this->owner->sendNotificationEmail( $email[0], // sender $email[1], // recipient $comment, 'cancelled changes' ); } } } public function notifyAwaitingEdit($comment) { $emailsToSend = array(); $userWhoRequestedEdits = Member::currentUser(); if (WorkflowRequest::should_send_alert(get_class($this->owner), 'requestedit', 'publisher')) { $publishers = $this->owner->Page()->PublisherMembers(); foreach ($publishers as $publisher) { $emailsToSend[] = array($userWhoRequestedEdits, $publisher); } } if (WorkflowRequest::should_send_alert(get_class($this->owner), 'requestedit', 'approver') && $this->Page()->hasMethod('ApproverMembers')) { $approvers = $this->owner->Page()->ApproverMembers(); foreach ($approvers as $approver) { $emailsToSend[] = array($userWhoRequestedEdits, $approver); } } if (WorkflowRequest::should_send_alert(get_class($this->owner), 'requestedit', 'author')) { $emailsToSend[] = array($userWhoRequestedEdits, $this->owner->Author()); } if (count($emailsToSend)) { foreach ($emailsToSend as $email) { if ($email[1]->ID == Member::currentUserID()) { continue; } $this->owner->sendNotificationEmail( $email[0], // sender $email[1], // recipient $comment, 'requested edit' ); } } } public function sendNotificationEmail($sender, $recipient, $comment, $requestedAction, $template = null) { if (!$recipient->Email) { return; } $this->addMemberEmailed($recipient); if (!$template) { $template = 'WorkflowGenericEmail'; } if (class_exists('Subsite')) { $subject = sprintf(_t('WorkflowRequest.EMAIL_SUBJECT_SITENAME', 'CMS Workflow: %s - Page: %s - Status: %s'), SiteConfig::current_site_config()->Title, $this->Page()->Title, self::get_status_description($this->Status)); } else { $subject = sprintf(_t('WorkflowRequest.EMAIL_SUBJECT', 'Website Workflow - Page: %s - Status: %s'), $this->Page()->Title, self::get_status_description($this->Status)); } $email = new Email(); $email->setTo($recipient->Email); $email->setFrom(($sender->Email) ? $sender->Email : Email::getAdminEmail()); $email->setTemplate($template); $email->setSubject($subject); $email->populateTemplate(array( "PageCMSLink" => "admin/show/".$this->Page()->ID, "Recipient" => $recipient, "Sender" => $sender, "Page" => $this->Page(), "StageSiteLink" => $this->Page()->Link()."?stage=stage", "LiveSiteLink" => $this->Page()->Link()."?stage=live", "Workflow" => $this, "Comment" => $comment, 'RequestedAction' => strtolower($requestedAction), "ActionOnPage" => $this->ActionOnPage() )); return $email->send(); } /** * Work out the phrase of what has happened to the page. This is sensitive * to the type of request, the person making the change and the action * they invoked. This allows us to send more descriptive emails. The cases * specifically handled: * - if an author has deleted a page => "deleted the page" * - if a publisher or approver has denied deletion of a page => * "undeleted the page" * - otherwise => "made changes to" * @todo Make the generation of this syntax use translatable. * @todo Get the generation out of here. The message that is displayed for * any given operation should be generated by the operation, not * centralised here. This logic assumes a certain syntax of the * sentence, which assumes a modification to the page. */ protected function ActionOnPage() { if ($this->ClassName == "WorkflowDeletionRequest") { if ($this->Status == "Denied") { return "undeleted the page"; } if ($this->Status == "AwaitingApproval") { return "deleted the page"; } } return "made changes to"; } /** * Add a member to the 'i've emailed them' list * * @param Member $member */ final public function addMemberEmailed(Member $member) { $this->memberIdsEmailed[] = (int)$member->ID; } /** * Get a list of people emails this http request * * @return DataObjectSet */ final public function getMembersEmailed() { $doSet = new DataObjectSet(); foreach (array_unique($this->memberIdsEmailed) as $id) { $doSet->push(DataObject::get_by_id('Member', $id)); } return $doSet; } /** * Clear the list of people emailed this http request * * @return void */ final public function clearMembersEmailed() { $this->memberIdsEmailed = array(); } /** * Returns a {@link DataDifferencer} object representing the changes. Has * some nasty logic to make it so that only changes that are made through * fields that are exposed by the CMS are tracked. */ public function Diff() { $diff = new DataDifferencer($this->fromRecord(), $this->toRecord()); //// This is commented out, pending a solution to infinite loop. //// Looping is called, as getCMSFields() calls updateCMSFields() which renders .ss template, which refers to this fn, $Diff. // $dataObjectFields = array_keys($this->fromRecord()->record); // asort($dataObjectFields); // $cmsFields = array(); // // foreach($this->fromRecord()->getCMSFields()->dataFields() as $f) { // if (!($f instanceof HiddenField)) $cmsFields[] = $f->Name(); // } // // $cmsFields[] = 'LastEdited'; // $cmsFields[] = 'Sort'; // $cmsFields[] = 'Created'; // $cmsFields[] = 'Status'; // $cmsFields[] = 'ProvideComments'; // // $diff->ignoreFields(array_diff($dataObjectFields, $cmsFields)); return $diff; } /** * Returns the old record that will be replaced by this publication. */ public function fromRecord() { $bt = defined('DB::USE_ANSI_SQL') ? "\"" : "`"; return Versioned::get_one_by_stage('SiteTree', 'Live', "{$bt}SiteTree_Live{$bt}.{$bt}ID{$bt} = {$this->PageID}", true, "\"Created\" DESC"); } /** * Returns the new record for which publication is being requested. */ public function toRecord() { return $this->Page(); } /** * Is the workflow request still pending. * Important for creation of new workflow requests * as there should be only one open request * per page at any given point in time. * * @return boolean */ public function isOpen() { return (!in_array($this->Status, array('Approved', 'Denied'))); } /** * Returns a CMS link to see differences made in the request * * @return string URL */ protected function getDiffLinkToLastPublished() { $bt = defined('DB::USE_ANSI_SQL') ? "\"" : "`"; // Get the completed request change and ask it $completedChange = DataObject::get_one('WorkflowRequestChange', "{$bt}WorkflowRequestID{$bt} = {$this->ID} AND {$bt}Status{$bt} = 'Completed'"); if (!$completedChange) { return false; } return $completedChange->getDiffLinkToLastPublished(); } /** * Determines if a request can be created by an author for a specific page. * Add custom authentication checks by subclassing this method. * * @param Member $member * @param SiteTree $page * @return boolean */ public static function can_create($member = null, $page) { if (!$member && $member !== false) { $member = Member::currentUser(); } return $page->canEdit($member); } /** * Get all publication requests by a specific author * * @param String $class The base class of the requests to fetch * @param Member $author The author who created the request * @return DataObjectSet */ public static function get_by_author($class, $author, $status = null) { $bt = defined('DB::USE_ANSI_SQL') ? "\"" : "`"; if ($status) { $statusStr = "'" . (is_array($status) ? implode("','", $status) : $status) . "'"; } $classes = (array)ClassInfo::subclassesFor($class); $classes[] = $class; $classesSQL = implode("','", $classes); // build filter $filter = "{$bt}Member{$bt}.{$bt}ID{$bt} = {$author->ID} AND {$bt}WorkflowRequest{$bt}.{$bt}ClassName{$bt} IN ('$classesSQL') "; if ($status) { $filter .= "AND {$bt}WorkflowRequest{$bt}.{$bt}Status{$bt} IN (" . $statusStr . ")"; } return DataObject::get( "SiteTree", $filter, "{$bt}SiteTree{$bt}.{$bt}LastEdited{$bt} DESC", "LEFT JOIN {$bt}WorkflowRequest{$bt} ON {$bt}WorkflowRequest{$bt}.{$bt}PageID{$bt} = {$bt}SiteTree{$bt}.{$bt}ID{$bt} " . "LEFT JOIN {$bt}Member{$bt} ON {$bt}Member{$bt}.{$bt}ID{$bt} = {$bt}WorkflowRequest{$bt}.{$bt}AuthorID{$bt}" ); } /** * Get publication requests from all users * @param string $class WorkflowRequest subclass * @param array $status One or more stati from the $Status property * @return DataObjectSet */ public static function get($class, $status = null) { $bt = defined('DB::USE_ANSI_SQL') ? "\"" : "`"; if ($status) { $statusStr = implode(',', $status); } $classes = (array)ClassInfo::subclassesFor($class); $classes[] = $class; $classesSQL = implode("','", $classes); // build filter $filter = "{$bt}WorkflowRequest{$bt}.{$bt}ClassName{$bt} IN ('$classesSQL')"; if ($status) { $filter .= "AND {$bt}WorkflowRequest{$bt}.{$bt}Status{$bt} IN ('" . Convert::raw2sql($statusStr) . "')"; } return DataObject::get( "SiteTree", $filter, "{$bt}SiteTree{$bt}.{$bt}LastEdited{$bt} DESC", "LEFT JOIN {$bt}WorkflowRequest{$bt} ON {$bt}WorkflowRequest{$bt}.{$bt}PageID{$bt} = {$bt}SiteTree{$bt}.{$bt}ID{$bt}" ); } /** * @return string */ public function getTitle() { $title = _t("{$this->class}.TITLE"); if (!$title) { $title = _t('WorkflowRequest.TITLE'); } return $title; } /** * @return string Translated $Status property */ public function getStatusDescription() { return self::get_status_description($this->Status); } public static function get_status_description($status) { switch ($status) { case 'Open': return _t('SiteTreeCMSWorkflow.STATUS_OPEN', 'Open'); case 'Approved': return _t('SiteTreeCMSWorkflow.STATUS_APPROVED', 'Approved'); case 'Scheduled': return _t('SiteTreeCMSWorkflow.STATUS_SCHEDULED', 'Scheduled for Publishing'); case 'Completed': return _t('SiteTreeCMSWorkflow.STATUS_COMPLETED', 'Completed'); case 'AwaitingApproval': return _t('SiteTreeCMSWorkflow.STATUS_AWAITINGAPPROVAL', 'Awaiting Approval'); case 'AwaitingEdit': return _t('SiteTreeCMSWorkflow.STATUS_AWAITINGEDIT', 'Awaiting Edit'); case 'Denied': return _t('SiteTreeCMSWorkflow.STATUS_DENIED', 'Denied'); case 'Cancelled': return _t('SiteTreeCMSWorkflow.STATUS_CANCELLED', 'Cancelled'); default: return _t('SiteTreeCMSWorkflow.STATUS_'.strtoupper($status), $status); } } public function fieldLabels() { $labels = parent::fieldLabels(); $labels['Status'] = _t('SiteTreeCMSWorkflow.FIELDLABEL_STATUS', "Status"); $labels['Author'] = _t('SiteTreeCMSWorkflow.FIELDLABEL_AUTHOR', "Author"); $labels['Publisher'] = _t('SiteTreeCMSWorkflow.FIELDLABEL_PUBLISHER', "Publisher"); $labels['Page'] = _t('SiteTreeCMSWorkflow.FIELDLABEL_PAGE', "Page"); $labels['Publishers'] = _t('SiteTreeCMSWorkflow.FIELDLABEL_PUBLISHERS', "Publishers"); return $labels; } // @codeCoverageIgnoreStart public function provideI18nEntities() { $entities = array(); $entities['WorkflowRequest.EMAIL_SUBJECT_GENERIC'] = array( "The workflow status of the \"%s\" page has changed", PR_MEDIUM, 'Email subject with page title' ); $entities['WorkflowRequest.TITLE'] = array( "Workflow Request", PR_MEDIUM, 'Title for this request, shown e.g. in the workflow status overview for a page' ); return $entities; } // @codeCoverageIgnoreEnd public function setSchedule() { if ($this->EmbargoDate) { $this->Status = 'Scheduled'; $this->write(); } } } |