Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sat, Feb 22, 12:08 AM

in-portal

Index: branches/5.2.x/core/units/helpers/page_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/page_helper.php (revision 16666)
+++ branches/5.2.x/core/units/helpers/page_helper.php (revision 16667)
@@ -1,487 +1,517 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class PageHelper extends kHelper {
/**
+ * Content block cache per page.
+ *
+ * @var array
+ */
+ protected $contentBlockCache = array();
+
+ /**
* Returns page info
*
* @param int $page_id
* @return Array
*/
function getPageInfo($page_id)
{
list ($user_id, $history_permission) = $this->getHistoryPermissionAndUser($page_id);
$users = $this->getEditors($page_id, $user_id);
return array(
'current_revision' => $this->getCurrentRevisionInfo(),
'editors' => $users,
'editors_warning' => $this->getEditorsWarning($users),
'revisions' => $history_permission ? $this->getPageRevisions($page_id) : array(),
);
}
/**
* Returns current admin user id (even, when called from front-end) and it's revision history view permission
*
* @param int $page_id
* @return Array
*/
protected function getHistoryPermissionAndUser($page_id)
{
/** @var kPermissionsHelper $perm_helper */
$perm_helper = $this->Application->recallObject('PermissionsHelper');
$user_id = (int)$this->Application->RecallVar($this->Application->isAdmin ? 'user_id' : 'admin_user_id');
$history_permission = $perm_helper->CheckUserPermission($user_id, 'CATEGORY.REVISION.HISTORY.VIEW', 0, $page_id);
return Array ($user_id, $history_permission);
}
/**
* Returns information about given page editors.
*
* @param integer $page_id Page, that is being edited.
* @param integer $user_id User, who is editing a page.
*
* @return array
*/
protected function getEditors($page_id, $user_id)
{
$where_clause = array(
'pr.PageId = ' . $page_id,
'pr.CreatedById <> ' . $user_id,
'pr.IsDraft = 1',
);
$sql = 'SELECT CASE pr.CreatedById WHEN ' . USER_ROOT . ' THEN "root" WHEN ' . USER_GUEST . ' THEN "Guest" ELSE IF(u.Username = "", u.Email, u.Username) END
FROM ' . $this->Application->getUnitOption('page-revision', 'TableName') . ' pr
LEFT JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = pr.CreatedById
WHERE (' . implode(') AND (', $where_clause) . ')';
return $this->Conn->GetCol($sql);
}
/**
* Returns information about current revision.
*
* @return array
*/
protected function getCurrentRevisionInfo()
{
/** @var kDBItem $revision */
$revision = $this->Application->recallObject('page-revision.current');
$status_label = $this->getRevisionStatusText($revision);
$draft = $revision->GetDBField('IsDraft');
$title = $this->getAdminPhrase($draft ? 'la_title_EditingDraft' : 'la_title_ViewingRevision');
$current_revision_info = array(
'title' => sprintf($title, $revision->GetDBField('RevisionNumber'), $status_label),
'status' => $revision->GetDBField('Status'),
'saved' => '',
'toolbar_state' => $this->getToolbarButtonsState($revision),
);
$auto_save_time = $revision->GetDBField('AutoSavedOn');
if ( $auto_save_time ) {
$phrase = $this->getAdminPhrase($draft ? 'la_DraftSavedAt' : 'la_SavedAt');
$current_revision_info['saved'] = sprintf($phrase, $revision->GetField('AutoSavedOn_time') . ' (' . $this->getAgoTime($auto_save_time) . ')');
}
return $current_revision_info;
}
/**
* Returns state of all CMS revision toolbar buttons.
*
* @param kDBItem $revision Page Revision.
*
* @return array
*/
public function getToolbarButtonsState(kDBItem $revision)
{
$ret = array();
foreach ( $this->getToolbarButtons() as $toolbar_button ) {
$ret[$toolbar_button] = $this->isToolbarButtonEnabled($toolbar_button, $revision);
}
return $ret;
}
/**
* Returns list of CMS revision toolbar buttons.
*
* @return array
*/
protected function getToolbarButtons()
{
return array('select', 'delete', 'approve', 'decline', 'preview', 'history');
}
/**
* Checks if given CMS revision toolbar button is enabled for given revision.
*
* @param string $button_name Toolbar button name.
* @param kDBItem $revision Revision to check against.
*
* @return boolean
*/
protected function isToolbarButtonEnabled($button_name, kDBItem $revision)
{
$is_draft = $revision->GetDBField('IsDraft');
if ( $button_name == 'select' || $button_name == 'delete' || $button_name == 'preview' ) {
return (bool)$is_draft;
}
if ( $button_name == 'approve' ) {
return $revision->GetDBField('Status') != STATUS_ACTIVE && !$is_draft;
}
if ( $button_name == 'decline' ) {
return $revision->GetDBField('Status') != STATUS_DISABLED && !$revision->GetDBField('IsLive') && !$is_draft;
}
return true;
}
/**
* Returns warning to be shown in case of parallel editing attempts.
*
* @param array $users Users, that are editing a page.
*
* @return string
*/
protected function getEditorsWarning(array $users)
{
/** @var kMultiLanguageHelper $ml_helper */
$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
$ret = $ml_helper->getPluralPhrase(
count($users),
array(
'phrase1' => 'la_PageCurrentlyEditing1',
'phrase2' => 'la_PageCurrentlyEditing2',
'phrase5' => 'la_PageCurrentlyEditing5',
),
false, true
);
return sprintf($ret, implode(', ', $users));
}
/**
* Returns information about given page revisions.
*
* @param integer $page_id Page, that is being edited.
*
* @return array
*/
protected function getPageRevisions($page_id)
{
$ret = Array ();
$tag_params = Array ('per_page' => -1, 'skip_parent_filter' => 1, 'requery' => 1, 'page_id' => $page_id);
/** @var kDBList $revisions */
$revisions = $this->Application->recallObject('page-revision.list', 'page-revision_List', $tag_params);
$revisions->Query();
$revisions->GoFirst();
while ( !$revisions->EOL() ) {
$ret[ 'r' . $revisions->GetDBField('RevisionNumber') ] = array(
'title' => $this->getRevisionTitle($revisions),
'status' => $revisions->GetDBField('Status'),
'status_label' => $this->getRevisionStatusText($revisions),
'datetime' => $revisions->GetField('CreatedOn'),
'author' => $this->getRevisionAuthor($revisions),
'draft' => (int)$revisions->GetDBField('IsDraft'),
);
$revisions->GoNext();
}
return $ret;
}
/**
* Returns title for given revision.
*
* @param kDBBase $revision Page Revision.
*
* @return string
*/
protected function getRevisionTitle(kDBBase $revision)
{
if ( $revision->GetDBField('IsDraft') ) {
return $this->getAdminPhrase('la_Draft');
}
$title = $this->getAdminPhrase('la_RevisionNumber');
return sprintf($title, $revision->GetDBField('RevisionNumber'));
}
/**
* Returns status text for given revision.
*
* @param kDBBase $revision Page Revision.
*
* @return string
*/
protected function getRevisionStatusText(kDBBase $revision)
{
$status = $revision->GetDBField('Status');
$options = $revision->GetFieldOptions('Status');
return mb_strtolower($this->getAdminPhrase($options['options'][$status]));
}
/**
* Returns author of given revision.
*
* @param kDBBase $revision Page Revision.
*
* @return string
*/
protected function getRevisionAuthor(kDBBase $revision)
{
$by_label = $this->getAdminPhrase('la_By');
return $by_label . ': ' . $revision->GetField('CreatedById');
}
/**
* Returns Admin's non-editable translation of given phrase.
*
* @param string $label Phrase label.
*
* @return string
*/
protected function getAdminPhrase($label)
{
return $this->Application->Phrase($label, false, true);
}
/**
* Returns time passed between 2 given dates in "X minutes Y seconds ago" format
*
* @param int $from_date
* @param int $to_date
* @param integer $max_levels
*
* @return string
*/
public function getAgoTime($from_date, $to_date = null, $max_levels = 1)
{
$blocks = Array (
Array ('name' => 'year', 'amount' => 60*60*24*365),
Array ('name' => 'month' ,'amount' => 60*60*24*31),
Array ('name' => 'week', 'amount' => 60*60*24*7),
Array ('name' => 'day', 'amount' => 60*60*24),
Array ('name' => 'hour', 'amount' => 60*60),
Array ('name' => 'minute', 'amount' => 60),
Array ('name' => 'second', 'amount' => 1),
);
if ( !isset($to_date) ) {
$to_date = adodb_mktime();
}
$diff = abs($to_date - $from_date);
if ( $diff == 0 ) {
return 'now';
}
$current_level = 1;
$result = Array ();
foreach ($blocks as $block) {
if ($current_level > $max_levels) {
break;
}
if ( $diff / $block['amount'] >= 1 ) {
$amount = floor($diff / $block['amount']);
$plural = $amount > 1 ? 's' : '';
$result[] = $amount . ' ' . $block['name'] . $plural;
$diff -= $amount * $block['amount'];
$current_level++;
}
}
return implode(' ', $result) . ' ago';
}
/**
* Returns where clause for loading correct revision for a given page
*
* @param int $page_id
* @param int $live_revision_number
* @param string $table_name
* @return string
*/
public function getRevsionWhereClause($page_id, $live_revision_number, $table_name = '')
{
$revision = (int)$this->Application->GetVar('revision');
list ($user_id, $has_permission) = $this->getHistoryPermissionAndUser($page_id);
if ( $has_permission && $revision ) {
$revision_clause = $table_name . 'RevisionNumber = ' . $revision . ' AND ' . $table_name . 'IsDraft = 0';
}
else {
$editing_mode = $this->Application->GetVar('editing_mode'); // not in a EDITING_MODE constant, while in admin console
$revision_clause = $table_name . 'RevisionNumber = ' . $live_revision_number . ' AND ' . $table_name . 'IsDraft = 0';
if ( $this->Application->ConfigValue('EnablePageContentRevisionControl') ) {
if ( $this->Application->GetVar('preview') || $editing_mode == EDITING_MODE_CONTENT ) {
$revision_clause = '(' . $table_name . 'CreatedById = ' . $user_id . ' AND ' . $table_name . 'IsDraft = 1) OR (' . $revision_clause . ')';
}
}
}
return $revision_clause;
}
/**
* Creates new content block in every revision that misses it. Plus creates first page revision
*
* @param int $page_id
* @param int $num
*/
public function createNewContentBlock($page_id, $num)
{
$sql = 'SELECT pc.PageContentId, pr.RevisionId
FROM ' . TABLE_PREFIX . 'PageRevisions pr
LEFT JOIN ' . TABLE_PREFIX . 'PageContent pc ON pc.RevisionId = pr.RevisionId AND pc.ContentNum = ' . $num . '
WHERE pr.PageId = ' . $page_id;
$revisions = $this->Conn->GetCol($sql, 'RevisionId');
if ( !$revisions ) {
// no revisions for a page -> create a live revision
/** @var kDBItem $revision */
$revision = $this->Application->recallObject('page-revision.live', null, Array ('skip_autoload' => true));
$revision->SetDBField('PageId', $page_id);
$revision->SetDBField('RevisionNumber', 1);
$revision->SetDBField('Status', STATUS_ACTIVE);
$revision->Create();
$revisions[ $revision->GetID() ] = NULL;
}
/** @var kDBItem $content_block */
$content_block = $this->Application->recallObject('content.new', null, Array ('skip_autoload' => true));
$content_block->SetDBField('PageId', $page_id);
$content_block->SetDBField('ContentNum', $num);
foreach ($revisions as $revision_id => $content_block_id) {
if ( is_numeric($content_block_id) ) {
continue;
}
$content_block->SetDBField('RevisionId', $revision_id);
$content_block->Create();
}
}
/**
* Loads content block by it's number
*
* @param kDBItem $content_block
* @param CategoriesItem $page
* @param int $num
*
* @return bool
*/
public function loadContentBlock(&$content_block, &$page, $num)
{
$page_id = $page->GetID();
+ // Load all content blocks at once during regular page visits.
if ( !EDITING_MODE && !$this->Application->GetVar('preview') ) {
- $revision_clause = 'pr.RevisionNumber = ' . $page->GetDBField('LiveRevisionNumber') . ' AND pr.IsDraft = 0';
- }
- else {
- $revision_clause = $this->getRevsionWhereClause($page_id, $page->GetDBField('LiveRevisionNumber'), 'pr.');
+ if ( !isset($this->contentBlockCache[$page_id]) ) {
+ $where_clause = array(
+ $content_block->TableName . '.PageId = ' . $page_id,
+ 'pr.RevisionNumber = ' . $page->GetDBField('LiveRevisionNumber'),
+ 'pr.IsDraft = 0',
+ );
+
+ $sql = $content_block->GetSelectSQL() . '
+ WHERE (' . implode(') AND (', $where_clause) . ')';
+ $this->contentBlockCache[$page_id] = $this->Conn->Query($sql, 'ContentNum');
+ }
+
+ if ( isset($this->contentBlockCache[$page_id][$num]) ) {
+ $content_block->LoadFromHash($this->contentBlockCache[$page_id][$num]);
+ }
+ else {
+ $content_block->Clear();
+ }
+
+ return $content_block->isLoaded();
}
+ // Load each content block individually with fallback to draft version, when editing content.
+ $where_clause = array(
+ $content_block->TableName . '.PageId = ' . $page_id,
+ $content_block->TableName . '.ContentNum = ' . $num,
+ $this->getRevsionWhereClause($page_id, $page->GetDBField('LiveRevisionNumber'), 'pr.'),
+ );
- $sql = $content_block->GetSelectSQL() . '
- WHERE (' . $content_block->TableName . '.PageId = ' . $page_id . ') AND (' . $content_block->TableName . '.ContentNum = ' . $num . ') AND (' . $revision_clause . ')
+ $sql = $content_block->GetSelectSQL() . '
+ WHERE (' . implode(') AND (', $where_clause) . ')
ORDER BY pr.IsDraft DESC, pr.RevisionNumber DESC';
$content_data = $this->Conn->GetRow($sql);
$content_block->LoadFromHash($content_data);
return $content_block->isLoaded();
}
/**
* Returns revision content
*
* @param integer $page_revision_id Page revision Id.
*
* @return array
*/
public function getRevisionContent($page_revision_id)
{
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'PageContent
WHERE RevisionId = ' . $page_revision_id;
$blocks = $this->Conn->GetIterator($sql);
/** @var kMultiLanguageHelper $ml_helper */
$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
$content = array();
foreach ( $ml_helper->getLanguages() as $lang_id ) {
$parts = array();
foreach ( $blocks as $block_data ) {
if ( (string)$block_data['l' . $lang_id . '_Content'] !== '' ) {
$parts[] = $this->makeSearchable($block_data['l' . $lang_id . '_Content']);
}
}
$content['l' . $lang_id . '_PageContent'] = implode(' ', $parts);
}
return $content;
}
/**
* Unescapes and removes tags
*
* @param string $content Content.
*
* @return string
*/
protected function makeSearchable($content)
{
return trim(strip_tags(html_entity_decode($content, ENT_QUOTES, 'UTF-8')));
}
}

Event Timeline