Problem: In Extbase werden Datensätze im Preview manchmal nicht richtig angezeigt. Das betrifft Typo3-Datensätze, die in Relation (n-m) zum eigentlichen Haupt-Datensatz stehen und zusammen mit diesem im Frontend dargestellt werden sollen. Der Hauptdatensatz wird als Preview-Version angezeigt, die relationalen Datensätze werden aber aus dem Live-Workspace genommen.
Als Beispiel: Wenn ein (in Extbase selbst programmierter) Newsartikel zum seinem Thema verwandte Artikel als Teaser anzeigen soll, tritt dieses Problem auf. Der Newsartikel kommt aus dem Preview-Workspace, die Teaser der verwandten Artikel kommen aus dem Live-Workspace.
Wenn man im Preview jetzt aber alles so anzeigen möchte wie im Preview zugewiesen, hilft vielleicht dieser Workaround:
Die relationalen Datensätze werden über ihr eigenes Repository an das übergeordnete Model ausgeliefert. Deshalb könnte man innerhalb des Repositorys eine Funktion definieren, die die Objekte aus dem jeweiligen Preview-Workspace zurückliefert anstelle der Live-Daten. Ich hab also eine Klasse Baserepository geschrieben, von der alle meine anderen Repositories erben. In den Querys muss dann noch respectEnableFields auf false gesetzt werden.
<?php
/**
* Description of BaseRepository
*
* @author tim schenk http://www.tim-schenk.de
*/
class Tx_MyExtension_Domain_Repository_BaseRepository extends Tx_Extbase_Persistence_Repository
{
/**
* static table->uid array
* @var array array('Table'=>array('PlaceholderUid'=>'WorkspaceUid'),'nextTable'=>array(...),...);
*/
private static $idsInWorkspace = array();
/**
* table name for this repository
* @var string
*/
protected $table = "";
/**
* Gets the Workspace ID
* @return string Workspace ID (default 0 = Live)
*/
protected function getWsId()
{
//if both fails return zero
$wsId = 0;
//Backend
if (!empty($GLOBALS['BE_USER']->workspace))
{
$wsId = $GLOBALS['BE_USER']->workspace;
}
//Frontend
elseif (!empty($GLOBALS['TSFE']->sys_page->versioningWorkspaceId))
{
$wsId = $GLOBALS['TSFE']->sys_page->versioningWorkspaceId;
}
return $wsId;
}
/**
* If its a preview the integer should be greater zero
* @return integer Workspace ID (default 0 = Live)
*/
public function isPreview()
{
return $this->getWsId();
}
/**
* there might be a standard typo3 function for that
* @param string $table name of table
* @return string delete clause sql
*/
protected function getDeletedClause($table)
{
return "$table.deleted=0";
}
/**
* there might be a standard typo3 function for that
* @param string $table name of table
* @return string hidden clause sql
*/
protected function getHiddenClause($table)
{
$where = $this->getDeletedClause($table);
$where .= " AND $table.hidden=0";
if (!$this->isPreview())
{
$where .= " AND ( $table.starttime=0 OR $table.starttime<=" . time() . " )";
$where .= " AND ( $table.endtime=0 OR $table.endtime>=" . time() . " )";
}
return $where;
}
/**
* createQuery overrides parent function
* @return Tx_Extbase_Persistence_QueryInterface $q
*/
public function createQuery()
{
$q = parent::createQuery();
// show also hidden fields etc...
$q->getQuerySettings()->getRespectEnableFields(false);
return $q;
}
/**
* returns the sql string for the actual workspace
* @param string $table
* @return string workspace sql clause
*/
public function getWsClause($table)
{
//get workspace id
$wsId = $this->getWsId();
$where = "";
if ($wsId == 0)
{//Live workspace
$where .= " $table.pid<>-1 ";
$where .= " AND $table.t3ver_wsid=0 ";
if (TYPO3_MODE == 'FE')
{
//includes deleted and startime / endtime
$where .= " AND " . $this->getHiddenClause($table);
}
else
{
// dont return any deleted stuff
$where .= " AND $table.deleted=0";
}
}
else
{//preview workspace
$stageWhere = $this->getPrewiewStageClause($table);
if (!empty($stageWhere))
{
$where .= " $stageWhere";
}
else
{
$where .= " $table.pid<>-1";
}
// return both, workspace and preview items
$where .= " AND $table.t3ver_wsid IN (0,$wsId)";
$where .= " AND $table.deleted=0";
if (TYPO3_MODE == 'FE')
{
$where .= " AND $table.hidden=0";
}
}
return $where;
}
/**
* gets an array of the uid in actual workspace
* http://www.schmutt.de/303/eigene-extension-mit-workspace-versionierung/
* http://www.ausgebloggt.de/2011/02/10/typo3-extbase-workspace-vorschau/
* http://typo3.org/documentation/document-library/core-documentation/doc_core_api/4.1.0/view/3/2/
*
* @param string $table
* @param bool $returnPlaceholderUids default = false
* @return array of integers -> uids in workspace
* Array keys are the original uids
* Array Values are the workspace uids
*/
protected function getWorkspaceConstraint($table, $returnPlaceholderUids = false)
{
$queryString = array();
$wsId = $this->getWsId();
// do this search only one time per process
if (empty(self::$idsInWorkspace[$table]))
{//static
$ids = array();
//deleted,hidden,sichtbare version, workspace
$where = $this->getWsClause($table);
$queryResult = $GLOBALS['TYPO3_DB']->exec_SELECTquery("*", $table, $where);
while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($queryResult))
{
// deletes row if it is no valid version
if (TYPO3_MODE == 'BE')
{
t3lib_BEfunc::workspaceOL($table, $row);
}
else
{
$GLOBALS['TSFE']->sys_page->versionOL($table, $row, true);
}
if (is_array($row))
{ //get uid of workspace version
$ids[$row['uid']] = $row['uid'];
}
}
self::$idsInWorkspace[$table] = $ids;
}
$idArray = self::$idsInWorkspace[$table];
if (!$returnPlaceholderUids)
{
foreach ($idArray as $key => $value)
{
$idArray[$key] = $this->getWsUid($table, $value);
}
}
if (!count($idArray))
{
$idArray = array(0);
}
return $idArray;
}
/**
* returns uid of actual workspace
* @param string $table
* @param integer $uid
* @param string $mode BE or FE
* @return integer $uid
*/
public function getWsUid($table, $uid, $mode = 'FE')
{
if ($this->isPreview() && TYPO3_MODE == $mode)
{
return t3lib_BEfunc::wsMapId($table, $uid);
}
return $uid;
}
}
?>
Im erbenden Objekt können dann nach bedarf die entsprechenden uids geholt werden. Zum Beispiel:
function getMyrelation(){
$q = $this->createQuery();
$wsConstraint = $this->getWorkspaceConstraint('tx_myextension_domain_model_mymodelclass');
if(!empty($wsConstraint)){
$q->matching($q->in('uid',$wsConstraint));
}
return $q->execute();
}
Das sollte so gehen...
Als Beispiel: Wenn ein (in Extbase selbst programmierter) Newsartikel zum seinem Thema verwandte Artikel als Teaser anzeigen soll, tritt dieses Problem auf. Der Newsartikel kommt aus dem Preview-Workspace, die Teaser der verwandten Artikel kommen aus dem Live-Workspace.
Wenn man im Preview jetzt aber alles so anzeigen möchte wie im Preview zugewiesen, hilft vielleicht dieser Workaround:
Die relationalen Datensätze werden über ihr eigenes Repository an das übergeordnete Model ausgeliefert. Deshalb könnte man innerhalb des Repositorys eine Funktion definieren, die die Objekte aus dem jeweiligen Preview-Workspace zurückliefert anstelle der Live-Daten. Ich hab also eine Klasse Baserepository geschrieben, von der alle meine anderen Repositories erben. In den Querys muss dann noch respectEnableFields auf false gesetzt werden.
<?php
/**
* Description of BaseRepository
*
* @author tim schenk http://www.tim-schenk.de
*/
class Tx_MyExtension_Domain_Repository_BaseRepository extends Tx_Extbase_Persistence_Repository
{
/**
* static table->uid array
* @var array array('Table'=>array('PlaceholderUid'=>'WorkspaceUid'),'nextTable'=>array(...),...);
*/
private static $idsInWorkspace = array();
/**
* table name for this repository
* @var string
*/
protected $table = "";
/**
* Gets the Workspace ID
* @return string Workspace ID (default 0 = Live)
*/
protected function getWsId()
{
//if both fails return zero
$wsId = 0;
//Backend
if (!empty($GLOBALS['BE_USER']->workspace))
{
$wsId = $GLOBALS['BE_USER']->workspace;
}
//Frontend
elseif (!empty($GLOBALS['TSFE']->sys_page->versioningWorkspaceId))
{
$wsId = $GLOBALS['TSFE']->sys_page->versioningWorkspaceId;
}
return $wsId;
}
/**
* If its a preview the integer should be greater zero
* @return integer Workspace ID (default 0 = Live)
*/
public function isPreview()
{
return $this->getWsId();
}
/**
* there might be a standard typo3 function for that
* @param string $table name of table
* @return string delete clause sql
*/
protected function getDeletedClause($table)
{
return "$table.deleted=0";
}
/**
* there might be a standard typo3 function for that
* @param string $table name of table
* @return string hidden clause sql
*/
protected function getHiddenClause($table)
{
$where = $this->getDeletedClause($table);
$where .= " AND $table.hidden=0";
if (!$this->isPreview())
{
$where .= " AND ( $table.starttime=0 OR $table.starttime<=" . time() . " )";
$where .= " AND ( $table.endtime=0 OR $table.endtime>=" . time() . " )";
}
return $where;
}
/**
* createQuery overrides parent function
* @return Tx_Extbase_Persistence_QueryInterface $q
*/
public function createQuery()
{
$q = parent::createQuery();
// show also hidden fields etc...
$q->getQuerySettings()->getRespectEnableFields(false);
return $q;
}
/**
* returns the sql string for the actual workspace
* @param string $table
* @return string workspace sql clause
*/
public function getWsClause($table)
{
//get workspace id
$wsId = $this->getWsId();
$where = "";
if ($wsId == 0)
{//Live workspace
$where .= " $table.pid<>-1 ";
$where .= " AND $table.t3ver_wsid=0 ";
if (TYPO3_MODE == 'FE')
{
//includes deleted and startime / endtime
$where .= " AND " . $this->getHiddenClause($table);
}
else
{
// dont return any deleted stuff
$where .= " AND $table.deleted=0";
}
}
else
{//preview workspace
$stageWhere = $this->getPrewiewStageClause($table);
if (!empty($stageWhere))
{
$where .= " $stageWhere";
}
else
{
$where .= " $table.pid<>-1";
}
// return both, workspace and preview items
$where .= " AND $table.t3ver_wsid IN (0,$wsId)";
$where .= " AND $table.deleted=0";
if (TYPO3_MODE == 'FE')
{
$where .= " AND $table.hidden=0";
}
}
return $where;
}
/**
* gets an array of the uid in actual workspace
* http://www.schmutt.de/303/eigene-extension-mit-workspace-versionierung/
* http://www.ausgebloggt.de/2011/02/10/typo3-extbase-workspace-vorschau/
* http://typo3.org/documentation/document-library/core-documentation/doc_core_api/4.1.0/view/3/2/
*
* @param string $table
* @param bool $returnPlaceholderUids default = false
* @return array of integers -> uids in workspace
* Array keys are the original uids
* Array Values are the workspace uids
*/
protected function getWorkspaceConstraint($table, $returnPlaceholderUids = false)
{
$queryString = array();
$wsId = $this->getWsId();
// do this search only one time per process
if (empty(self::$idsInWorkspace[$table]))
{//static
$ids = array();
//deleted,hidden,sichtbare version, workspace
$where = $this->getWsClause($table);
$queryResult = $GLOBALS['TYPO3_DB']->exec_SELECTquery("*", $table, $where);
while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($queryResult))
{
// deletes row if it is no valid version
if (TYPO3_MODE == 'BE')
{
t3lib_BEfunc::workspaceOL($table, $row);
}
else
{
$GLOBALS['TSFE']->sys_page->versionOL($table, $row, true);
}
if (is_array($row))
{ //get uid of workspace version
$ids[$row['uid']] = $row['uid'];
}
}
self::$idsInWorkspace[$table] = $ids;
}
$idArray = self::$idsInWorkspace[$table];
if (!$returnPlaceholderUids)
{
foreach ($idArray as $key => $value)
{
$idArray[$key] = $this->getWsUid($table, $value);
}
}
if (!count($idArray))
{
$idArray = array(0);
}
return $idArray;
}
/**
* returns uid of actual workspace
* @param string $table
* @param integer $uid
* @param string $mode BE or FE
* @return integer $uid
*/
public function getWsUid($table, $uid, $mode = 'FE')
{
if ($this->isPreview() && TYPO3_MODE == $mode)
{
return t3lib_BEfunc::wsMapId($table, $uid);
}
return $uid;
}
}
?>
Im erbenden Objekt können dann nach bedarf die entsprechenden uids geholt werden. Zum Beispiel:
function getMyrelation(){
$q = $this->createQuery();
$wsConstraint = $this->getWorkspaceConstraint('tx_myextension_domain_model_mymodelclass');
if(!empty($wsConstraint)){
$q->matching($q->in('uid',$wsConstraint));
}
return $q->execute();
}
Das sollte so gehen...
Keine Kommentare:
Kommentar veröffentlichen