Upload
jochen-rau
View
16.934
Download
2
Embed Size (px)
DESCRIPTION
A key feature of TYPO3 today is its extendability and flexibility. Writing extensions was never easier since the Kickstarter, and tslib_piBase. But, time doesn't stand still: new programming paradigms other innovative frameworks came up. It's time to take a next step to faster, cleaner extension coding. With the new Version 5 of TYPO3 and its basis FLOW3 the way to develop extensions will change fundamentally. With Extbase - the new framework for extension development introduced in TYPO3 4.3 - you are able to develop with the paradigms of FLOW3 today. During this talk, you get in touch with the features of the framework to understand how it supports your development process. We also address the users perspective by discussing best practices how to migrate to TYPO3 v5.
Citation preview
http://www.sxc.hu/photo/768249
Get into the FLOW with Extbase
Who is this?
Dipl.-Ing. Mechanical Engineering
infected with TYPO3 in 2OO1
Tübingen
6O% selfemployed6O% father
6O% selfemployed6O% father
----8O%
5 years: Fraunhofer-Gesellschaft
German Aerospace Center
5 years:high school
teacher
What is Extbase all about?
1997
v4
2OO9
v4
v4
2OO6
v4
v5
v4
v5
v4
v5
v4
v5Extbase
v4
v5
What is Extbase all about?
Extbase
FLOW 3
What is Extbase all about?
Extbase
Extbase
MVC
DDD
VfB
OOP Aggregate
Entity
Repository
View
Helper
Extbase
Entity
View Helper
Value
Value
enables and encourages the developer to write maintainable codeseparates di!erent responsibilitiesmodular architecture of the extension
relieves the developer in safety-critical and recurring tasksvalidation of argumentsinvoking the template mechanismpersistenceread out the settings from TypoScript and FlexForms
enables and encourages the developer to focus on solving the problem of the client saves primary and adapting development time (direct and indirect costs)
http://commons.wikimedia.org/wiki/File:Z%C3%BCrich_-_Seefeld_-_Heureka_IMG_1757.JPG
http://commons.wikimedia.org/wiki/File:Z%C3%BCrich_-_Seefeld_-_Heureka_IMG_1757.JPG
tx_ttnews 3397tx_pbsurvey_pi1 253Otx_ttproducts_pi1 1O9Otx_mmforum_pi1 6126tx_veguestbook_pi1 1156
<?php/**************************************************************** Copyright notice** (c) 1999-2004 Kasper Skårhøj ([email protected])* (c) 2004-2007 Rupert Germann ([email protected])* All rights reserved** This script is part of the TYPO3 project. The TYPO3 project is* free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** The GNU General Public License can be found at* http://www.gnu.org/copyleft/gpl.html.* A copy is found in the textfile GPL.txt and important notices to the license* from the author is found in LICENSE.txt distributed with these scripts.*** This script is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** This copyright notice MUST APPEAR in all copies of the script!***************************************************************//*** class.tx_ttnews.php** versatile news system for TYPO3.* $Id: class.tx_ttnews.php 8605 2008-03-15 20:03:19Z rupertgermann $** TypoScript setup:* @See static/ts_new/setup.txt* @See tt_news Manual: ! http://typo3.org/documentation/document-library/extension-manuals/tt_news/current/* @See TSref: ! ! ! http://typo3.org/documentation/document-library/references/doc_core_tsref/current/** @author Rupert Germann <[email protected]>* @co-author Ingo Renner <[email protected]>*//** * [CLASS/FUNCTION INDEX of SCRIPT] * * * * 112: class tx_ttnews extends tslib_pibase * 143: function main_news($content, $conf) * 219: function init($conf) * 373: function newsArchiveMenu() * 523: function displaySingle() * 606: function displayVersionPreview () * 659: function displayList($excludeUids = 0) * 1003: function getListContent($itemparts, $selectConf, $prefix_display) * 1172: function getSelectConf($where, $noPeriod = 0) * 1419: function generatePageArray() * 1440: function getItemMarkerArray ($row, $textRenderObj = 'displaySingle') * 1723: function insertPagebreaks($text,$firstPageWordCrop) * 1773: function makeMultiPageSView($bodytext,$lConf) * 1803: function makePageBrowser($showResultCount=1,$tableParams='',$pointerName='pointer') * 1885: function getCategories($uid, $getAll=false) * 1958: function getCategoryPath($categoryArray) * 2015: function getSubCategories($catlist, $cc = 0) * 2044: function displayCatMenu() * 2157: function getCatMenuContent($array_in,$lConf, $l=0) * 2209: function getSubCategoriesForMenu ($catlist, $fields, $addWhere, $cc = 0) * 2240: function getCatMarkerArray($markerArray, $row, $lConf) * 2380: function getImageMarkers($markerArray, $row, $lConf, $textRenderObj) * 2448: function getRelated($uid) * 2608: function userProcess($mConfKey, $passVar) * 2623: function spMarker($subpartMarker) * 2641: function searchWhere($sw) * 2652: function formatStr($str) * 2667: function getLayouts($templateCode, $alternatingLayouts, $marker) * 2685: function initLanguages () * 2705: function initCategoryVars() * 2775: function checkRecords($recordlist) * 2807: function initTemplate() * 2832: function initPidList () * 2857: function getXmlHeader() * 2958: function getW3cDate($datetime) * 2983: function main_xmlnewsfeed($content, $conf) * 2998: function getStoriesResult() * 3020: function cleanXML($str) * 3034: function convertDates() * 3073: function getHrDateSingle($tstamp) * 3086: function displayFEHelp() * 3107: function validateFields($fieldlist) * 3128: function getNewsSubpart($myTemplate, $myKey, $row = Array()) * * SECTION: DB Functions * 3149: function exec_getQuery($table, $conf) * 3167: function getQuery($table, $conf, $returnQueryArray=FALSE) * 3249: function getWhere($table,$conf, $returnQueryArray=FALSE) * * TOTAL FUNCTIONS: 45 * (This index is automatically created/updated by the extension "extdeveval") * */
require_once(PATH_t3lib . 'class.t3lib_xml.php');require_once(PATH_t3lib . 'class.t3lib_htmlmail.php');require_once(PATH_tslib . 'class.tslib_pibase.php');require_once(t3lib_extMgm::extPath('tt_news') . 'class.tx_ttnews_catmenu.php');
/** * Plugin 'news' for the 'tt_news' extension. * * @author Rupert Germann <[email protected]> * @package TYPO3 * @subpackage tt_news */class tx_ttnews extends tslib_pibase {! // Default plugin variables:! var $prefixId = 'tx_ttnews'; // Same as class name! var $scriptRelPath = 'pi/class.tx_ttnews.php'; // Path to this script relative to the extension dir.! var $extKey = 'tt_news'; // The extension key.! var $tt_news_uid; // the uid of the current news record in SINGLE view! var $config; // the processed TypoScript configuration array! var $langArr; // the languages found in the tt_news sysfolder! var $sys_language_mode;! var $alternatingLayouts;! var $allowCaching;! var $catExclusive;! var $arcExclusive;! var $searchFieldList = 'short,bodytext,author,keywords,links,imagecaption,title';! var $theCode = '';! var $rdfToc = '';! var $versioningEnabled = false; // is the extension 'version' loaded! var $vPrev = false; // do we display a versioning preview! var $categories = array(); // Is initialized with the categories of the news system! var $pageArray = array(); // Is initialized with an array of the pages in the pid-list
! /**! * Main news function: calls the init_news() function and decides by the given CODEs which of the! * functions to display news should by called.! *! * @param! string! ! $content : function output is added to this! * @param! array!! $conf : configuration array! * @return!string! ! $content: complete content generated by the tt_news plugin! */! function main_news($content, $conf) {! ! $this->local_cObj = t3lib_div::makeInstance('tslib_cObj'); // Local cObj.! ! $this->init($conf);
! ! if ($this->conf['displayCurrentRecord']) {! ! ! $this->config['code'] = $this->conf['defaultCode']?trim($this->conf['defaultCode']):'SINGLE';! ! ! $this->tt_news_uid = $this->cObj->data['uid'];! ! }
! ! // get codes and decide which function is used to process the content! ! $codes = t3lib_div::trimExplode(',', $this->config['code']?$this->config['code']:$this->conf['defaultCode'], 1);! ! if (!count($codes)) { // no code at all! ! ! $codes = array();! ! ! $noCode = true;! ! }
! ! while (list(, $theCode) = each($codes)) {! ! ! $theCode = (string)strtoupper(trim($theCode));! ! ! $this->theCode = $theCode;! ! ! switch ($theCode) {! ! ! ! case 'SINGLE':! ! ! ! $content .= $this->displaySingle();! ! ! ! break;! ! ! ! case 'VERSION_PREVIEW':! ! ! ! $content .= $this->displayVersionPreview();! ! ! ! break;! ! ! ! case 'LATEST':! ! ! ! case 'LIST':! ! ! ! case 'SEARCH':! ! ! ! case 'XML':! ! ! ! $content .= $this->displayList();! ! ! ! break;! ! ! ! case 'AMENU':! ! ! ! $content .= $this->newsArchiveMenu();! ! ! ! break;! ! ! ! case 'CATMENU':! ! ! ! $content .= $this->displayCatMenu();! ! ! ! break;! ! ! ! default:! ! ! ! // Adds hook for processing of extra codes! ! ! ! if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['tt_news']['extraCodesHook'])) {! ! ! ! ! foreach($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['tt_news']['extraCodesHook'] as $_classRef) {! ! ! ! ! ! $_procObj = & t3lib_div::getUserObj($_classRef);! ! ! ! ! ! $content .= $_procObj->extraCodesProcessor($this);! ! ! ! ! }! ! ! ! } else {! ! ! ! ! $langKey = strtoupper($GLOBALS['TSFE']->config['config']['language']);! ! ! ! ! $helpTemplate = $this->cObj->fileResource('EXT:tt_news/pi/news_help.tmpl');! ! ! ! ! // Get language version of the help-template! ! ! ! ! $helpTemplate_lang = '';! ! ! ! ! if ($langKey) {! ! ! ! ! ! $helpTemplate_lang = $this->getNewsSubpart($helpTemplate, "###TEMPLATE_" . $langKey . '###');! ! ! ! ! }! ! ! ! ! $helpTemplate = $helpTemplate_lang ? $helpTemplate_lang :! ! ! ! ! $this->getNewsSubpart($helpTemplate, '###TEMPLATE_DEFAULT###');! ! ! ! ! // Markers and substitution:! ! ! ! ! $markerArray['###CODE###'] = $this->theCode;! ! ! ! ! $markerArray['###EXTPATH###'] = $GLOBALS['TYPO3_LOADED_EXT']['tt_news']['siteRelPath'];! ! ! ! ! $content .= $this->displayFEHelp();! ! ! ! }! ! ! ! break;! ! ! }! ! }! ! if($noCode) {! ! ! $content .= $this->displayFEHelp();! ! }! ! return $content;! }
! /**! * Init Function: here all the needed configuration values are stored in class variables..! *! * @param! array!! $conf : configuration array from TS! * @return!void! */! function init($conf) {! ! $this->conf = $conf; //store configuration! ! $this->pi_loadLL(); // Loading language-labels! ! $this->pi_setPiVarDefaults(); // Set default piVars from TS! ! $this->pi_initPIflexForm(); // Init FlexForm configuration for plugin! ! $this->enableFields = $this->cObj->enableFields('tt_news');! ! $this->tt_news_uid = intval($this->piVars['tt_news']); // Get the submitted uid of a news (if any)
! ! if (!isset($this->conf['compatVersion']) || !preg_match('/^\d+\.\d+\.\d+$/', $this->conf['compatVersion'])) {! ! ! $this->conf['compatVersion'] = $this->getCurrentVersion();! ! }
! ! if (t3lib_extMgm::isLoaded('version')) {! ! ! $this->versioningEnabled = true;! ! }! ! // load available syslanguages! ! $this->initLanguages();! ! // sys_language_mode defines what to do if the requested translation is not found! ! $this->sys_language_mode = $this->conf['sys_language_mode']?$this->conf['sys_language_mode'] : $GLOBALS['TSFE']->sys_language_mode;
! ! // "CODE" decides what is rendered: codes can be set by TS or FF with priority on FF! ! $code = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'what_to_display', 'sDEF');! ! $this->config['code'] = $code ? $code : $this->cObj->stdWrap($this->conf['code'], $this->conf['code.']);
! ! // initialize category vars! ! $this->initCategoryVars();
! ! ! // get fieldnames from the tt_news db-table! ! $this->fieldNames = array_keys($GLOBALS['TYPO3_DB']->admin_get_fields('tt_news'));
! ! if ($this->conf['searchFieldList']) {! ! ! $searchFieldList = $this->validateFields($this->conf['searchFieldList']);! ! ! if ($searchFieldList) {! ! ! ! $this->searchFieldList = $searchFieldList;! ! ! }! ! }! ! ! // Archive:! ! $this->config['archiveMode'] = trim($this->conf['archiveMode']) ; // month, quarter or year listing in AMENU! ! $this->config['archiveMode'] = $this->config['archiveMode']?$this->config['archiveMode']:'month';
! ! // arcExclusive : -1=only non-archived; 0=don't care; 1=only archived! ! $arcExclusive = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'archive', 'sDEF');! ! $this->arcExclusive = $arcExclusive?$arcExclusive:$this->conf['archive'];
! ! $this->config['datetimeDaysToArchive'] = intval($this->conf['datetimeDaysToArchive']);! ! $this->config['datetimeHoursToArchive'] = intval($this->conf['datetimeHoursToArchive']);! ! $this->config['datetimeMinutesToArchive'] = intval($this->conf['datetimeMinutesToArchive']);
! ! if ($this->conf['useHRDates']) {! ! ! $this->convertDates();! ! }
! ! // list of pages where news records will be taken from! ! if (!$this->conf['dontUsePidList']) {! ! ! $this->initPidList();! ! }
! ! // itemLinkTarget is only used for categoryLinkMode 3 (catselector) in framesets! ! $this->config['itemLinkTarget'] = trim($this->conf['itemLinkTarget']);! ! // id of the page where the search results should be displayed! ! $this->config['searchPid'] = intval($this->conf['searchPid']);
! ! // pages in Single view will be divided by this token! ! $this->config['pageBreakToken'] = trim($this->conf['pageBreakToken'])?trim($this->conf['pageBreakToken']):'<---newpage--->';
! ! $this->config['singleViewPointerName'] = trim($this->conf['singleViewPointerName'])?trim($this->conf['singleViewPointerName']):'sViewPointer';
! ! $maxWordsInSingleView = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'maxWordsInSingleView', 's_misc'));! ! $maxWordsInSingleView = $maxWordsInSingleView?$maxWordsInSingleView:intval($this->conf['maxWordsInSingleView']);! ! $this->config['maxWordsInSingleView'] = $maxWordsInSingleView?$maxWordsInSingleView:0;! ! $this->config['useMultiPageSingleView'] = $maxWordsInSingleView>1?1:$this->conf['useMultiPageSingleView'];
! ! // pid of the page with the single view. the old var PIDitemDisplay is still processed if no other value is found! ! $singlePid = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'PIDitemDisplay', 's_misc');! ! $singlePid = $singlePid?$singlePid:intval($this->cObj->stdWrap($this->conf['singlePid'],$this->conf['singlePid.']));! ! $this->config['singlePid'] = $singlePid ? $singlePid:intval($this->conf['PIDitemDisplay']);
! ! // pid to return to when leaving single view! ! $backPid = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'backPid', 's_misc'));! ! $backPid = $backPid?$backPid:intval($this->conf['backPid']);! ! $backPid = $backPid?$backPid:intval($this->piVars['backPid']);! ! $backPid = $backPid?$backPid:$GLOBALS['TSFE']->id ;! ! $this->config['backPid'] = $backPid;
! ! // max items per page! ! $FFlimit = t3lib_div::intInRange($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listLimit', 's_misc'), 0, 1000);
! ! $limit = t3lib_div::intInRange($this->cObj->stdWrap($this->conf['limit'],$this->conf['limit.']), 0, 1000);! ! $limit = $limit?$limit:! 50;! ! $this->config['limit'] = $FFlimit?$FFlimit:!$limit;
! ! $latestLimit = t3lib_div::intInRange($this->cObj->stdWrap($this->conf['latestLimit'],$this->conf['latestLimit.']), 0, 1000);! ! $latestLimit = $latestLimit?$latestLimit:10;! ! $this->config['latestLimit'] = $FFlimit?$FFlimit:$latestLimit;
! ! // orderBy and groupBy statements for the list Query! ! $orderBy = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listOrderBy', 'sDEF');! ! $orderByTS = trim($this->conf['listOrderBy']);! ! $orderBy = $orderBy?$orderBy:$orderByTS;! ! $this->config['orderBy'] = $orderBy;
! ! if ($orderBy) {! ! ! $ascDesc = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'ascDesc', 'sDEF');! ! ! $this->config['ascDesc'] = $ascDesc;! ! ! if ($this->config['ascDesc']) {! ! ! ! // remove ASC/DESC from 'orderBy' if it is already set from TS! ! ! ! $this->config['orderBy'] = preg_replace('/( DESC| ASC)\b/i','',$this->config['orderBy']);! ! ! }! ! }! ! $this->config['groupBy'] = trim($this->conf['listGroupBy']);
! ! // if this is set, the first image is handled as preview image, which is only shown in list view! ! $fImgPreview = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'firstImageIsPreview', 's_misc');! ! $this->config['firstImageIsPreview'] = $fImgPreview?$fImgPreview : $this->conf['firstImageIsPreview'];! ! $forcefImgPreview = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'forceFirstImageIsPreview', 's_misc');! ! $this->config['forceFirstImageIsPreview'] = $forcefImgPreview?$fImgPreview : $this->conf['forceFirstImageIsPreview'];
! ! // List start id! ! $listStartId = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listStartId', 's_misc'));! ! $this->config['listStartId'] = $listStartId?$listStartId:intval($this->conf['listStartId']);! ! // supress pagebrowser! ! $noPageBrowser = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'noPageBrowser', 's_misc');! ! $this->config['noPageBrowser'] = $noPageBrowser?$noPageBrowser:! $this->conf['noPageBrowser'];
! ! // image sizes given from FlexForms! ! $this->config['FFimgH'] = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'imageMaxHeight', 's_template'));! ! $this->config['FFimgW'] = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'imageMaxWidth', 's_template'));
! ! // Get number of alternative Layouts (loop layout in LATEST and LIST view) default is 2:! ! $altLayouts = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'alternatingLayouts', 's_template'));! ! $altLayouts = $altLayouts?$altLayouts:intval($this->conf['alternatingLayouts']);! ! $this->alternatingLayouts = $altLayouts?$altLayouts:2;
! ! // Get cropping lenght! ! $this->config['croppingLenght'] = trim($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'croppingLenght', 's_template'));
! ! $this->initTemplate();
! ! // Configure caching! ! $this->allowCaching = $this->conf['allowCaching']?1:0;! ! if (!$this->allowCaching) {! ! ! $GLOBALS['TSFE']->set_no_cache();! ! }
! ! // get siteUrl for links in rss feeds. the 'dontInsert' option seems to be needed in some configurations depending on the baseUrl setting! ! if (!$this->conf['displayXML.']['dontInsertSiteUrl']) {! ! ! $this->config['siteUrl'] = t3lib_div::getIndpEnv('TYPO3_SITE_URL');! ! }! }
! /**! * generates the News archive menu! *! * @return!string! ! html code of the archive menu! */! function newsArchiveMenu() {
! ! $this->arcExclusive = 1;! ! $selectConf = $this->getSelectConf('', 1);! ! // Finding maximum and minimum values:! ! $selectConf['selectFields'] = 'max(tt_news.datetime) as maxval, min(tt_news.datetime) as minval';
! ! $res = $this->exec_getQuery('tt_news', $selectConf);
! ! $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);! ! if ($row['minval'] || $row['maxval']) {! ! ! // if ($row['minval']) {! ! ! $dateArr = array();! ! ! $arcMode = $this->config['archiveMode'];! ! ! $c = 0;! ! ! do {! ! ! ! switch ($arcMode) {! ! ! ! ! case 'month':! ! ! ! ! $theDate = mktime (0, 0, 0, date('m', $row['minval']) + $c, 1, date('Y', $row['minval']));! ! ! ! ! break;! ! ! ! ! case 'quarter':! ! ! ! ! $theDate = mktime (0, 0, 0, floor(date('m', $row['minval']) / 3) + 1 + (3 * $c), 1, date('Y', $row['minval']));! ! ! ! ! break;! ! ! ! ! case 'year':! ! ! ! ! $theDate = mktime (0, 0, 0, 1, 1, date('Y', $row['minval']) + $c);! ! ! ! ! break;! ! ! ! }! ! ! ! $dateArr[] = $theDate;! ! ! ! $c++;! ! ! ! if ($c > 1000) break;! ! ! }! ! ! while ($theDate < $GLOBALS['SIM_EXEC_TIME']);
! ! ! reset($dateArr);! ! ! $periodAccum = array();
! ! ! $selectConf2['where'] = $selectConf['where'];! ! ! while (list($k, $v) = each($dateArr)) {! ! ! ! if (!isset($dateArr[$k + 1])) {! ! ! ! ! break;! ! ! ! }
! ! ! ! $periodInfo = array();! ! ! ! $periodInfo['start'] = $dateArr[$k];! ! ! ! $periodInfo['stop'] = $dateArr[$k + 1]-1;! ! ! ! $periodInfo['HRstart'] = date('d-m-Y', $periodInfo['start']);! ! ! ! $periodInfo['HRstop'] = date('d-m-Y', $periodInfo['stop']);! ! ! ! $periodInfo['quarter'] = floor(date('m', $dateArr[$k]) / 3) + 1;! ! ! ! // execute a query to count the archive periods! ! ! ! $selectConf['selectFields'] = 'count(distinct(tt_news.uid))';! ! ! ! $selectConf['where'] = $selectConf2['where'] . ' AND tt_news.datetime>=' . $periodInfo['start'] . ' AND tt_news.datetime<' . $periodInfo['stop'];
! ! ! ! $res = $this->exec_getQuery('tt_news', $selectConf);
! ! ! ! $row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);! ! ! ! $periodInfo['count'] = $row[0];
! ! ! ! if (!$this->conf['archiveMenuNoEmpty'] || $periodInfo['count']) {! ! ! ! ! $periodAccum[] = $periodInfo;! ! ! ! }! ! ! }
! ! ! // get template subpart! ! ! $t['total'] = $this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_ARCHIVE###'));! ! ! $t['item'] = $this->getLayouts($t['total'], $this->alternatingLayouts, 'MENUITEM');! ! ! $cc = 0;
! ! ! $veryLocal_cObj = t3lib_div::makeInstance('tslib_cObj');! ! ! // reverse amenu order if 'reverseAMenu' is given! ! ! if ($this->conf['reverseAMenu']) {! ! ! ! arsort($periodAccum);! ! ! }
! ! ! $archiveLink = $this->conf['archiveTypoLink.']['parameter'];! ! ! $this->conf['parent.']['addParams'] = $this->conf['archiveTypoLink.']['addParams'];! ! ! reset($periodAccum);! ! ! $itemsOutArr = array();! ! ! while (list(, $pArr) = each($periodAccum)) {! ! ! ! // Print Item Title! ! ! ! $wrappedSubpartArray = array();
! ! ! ! if (!$this->conf['disableCategoriesInAmenuLinks']) {! ! ! ! ! if ($this->config['catSelection'] && $this->config['amenuWithCatSelector']) {! ! ! ! ! ! // use the catSelection from GPvars only if 'amenuWithCatSelector' is given.! ! ! ! ! ! $amenuLinkCat = $this->config['catSelection'];! ! ! ! ! } else {! ! ! ! ! ! $amenuLinkCat = $this->catExclusive;! ! ! ! ! }! ! ! ! }
! ! ! ! if ($this->conf['useHRDates']) {! ! ! ! ! $year = date('Y',$pArr['start']);! ! ! ! ! $month = date('m',$pArr['start']);! ! ! ! ! if ($arcMode == 'year') {! ! ! ! ! ! $archLinkArr = $this->pi_linkTP_keepPIvars('|', array('cat' => ($amenuLinkCat?$amenuLinkCat:null), 'year' => $year), $this->allowCaching, 1, ($archiveLink?$archiveLink:$GLOBALS['TSFE']->id));! ! ! ! ! } else {! ! ! ! ! ! $archLinkArr = $this->pi_linkTP_keepPIvars('|', array('cat' => ($amenuLinkCat?$amenuLinkCat:null), 'year' => $year, 'month' => $month), $this->allowCaching, 1, ($archiveLink?$archiveLink:$GLOBALS['TSFE']->id));! ! ! ! ! }! ! ! ! ! $wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $archLinkArr);! ! ! ! } else {! ! ! ! ! $wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $this->pi_linkTP_keepPIvars('|', array('cat' => ($amenuLinkCat?$amenuLinkCat:null), 'pS' => $pArr['start'], 'pL' => ($pArr['stop'] - $pArr['start']), 'arc' => 1), $this->allowCaching, 1, ($archiveLink?$archiveLink:$GLOBALS['TSFE']->id)));! ! ! ! }
! ! ! ! $markerArray = array();! ! ! ! $veryLocal_cObj->start($pArr, '');! ! ! ! $markerArray['###ARCHIVE_TITLE###'] = $veryLocal_cObj->cObjGetSingle($this->conf['archiveTitleCObject'], $this->conf['archiveTitleCObject.'], 'archiveTitle');! ! ! ! $markerArray['###ARCHIVE_COUNT###'] = $pArr['count'];! ! ! ! $markerArray['###ARCHIVE_ITEMS###'] = $this->pi_getLL('archiveItems');
! ! ! ! // fill the generated data to an array to pass it to a userfuction as a single variable! ! ! ! $itemsOutArr[] = array('html' => $this->cObj->substituteMarkerArrayCached($t['item'][($cc % count($t['item']))], $markerArray, array(), $wrappedSubpartArray), 'data' => $pArr);! ! ! ! $cc++;! ! ! }! ! ! // Pass to user defined function! ! ! if ($this->conf['newsAmenuUserFunc']) {! ! ! ! $itemsOutArr = $this->userProcess('newsAmenuUserFunc', $itemsOutArr);! ! ! }
! ! ! foreach ($itemsOutArr as $itemHtml) {! ! ! ! $tmpItemsArr[] = $itemHtml['html'];! ! ! }
! ! ! if (is_array($tmpItemsArr)) {! ! ! ! $itemsOut = implode('', $tmpItemsArr);! ! ! }
! ! ! // Reset:! ! ! $subpartArray = array();! ! ! $wrappedSubpartArray = array();! ! ! $markerArray = array();! ! ! $markerArray['###ARCHIVE_HEADER###'] = $this->local_cObj->stdWrap($this->pi_getLL('archiveHeader'), $this->conf['archiveHeader_stdWrap.']);! ! ! // Set content! ! ! $subpartArray['###CONTENT###'] = $itemsOut;! ! ! $content = $this->cObj->substituteMarkerArrayCached($t['total'], $markerArray, $subpartArray, $wrappedSubpartArray);! ! } else {! ! ! // if nothing is found in the archive display the TEMPLATE_ARCHIVE_NOITEMS message! ! ! $markerArray['###ARCHIVE_HEADER###'] = $this->local_cObj->stdWrap($this->pi_getLL('archiveHeader'), $this->conf['archiveHeader_stdWrap.']);! ! ! $markerArray['###ARCHIVE_EMPTY_MSG###'] = $this->local_cObj->stdWrap($this->pi_getLL('archiveEmptyMsg'), $this->conf['archiveEmptyMsg_stdWrap.']);! ! ! $noItemsMsg = $this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_ARCHIVE_NOITEMS###'));! ! ! $content = $this->cObj->substituteMarkerArrayCached($noItemsMsg, $markerArray);! ! }
! ! return $content;! }
! /**! * Displays the "single view" of a news article. Is also used when displaying single news records with the "insert records" content element.! *! * @return!string! ! html-code for the "single view"! */! function displaySingle() {! ! $singleWhere = 'tt_news.uid=' . intval($this->tt_news_uid);! ! $singleWhere .= ' AND type NOT IN(1,2)' . $this->enableFields; // only real news -> type=0
! ! $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(! ! ! '*',! ! ! 'tt_news',! ! ! $singleWhere);
! ! $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);! ! // get the translated record if the content language is not the default language! ! if ($GLOBALS['TSFE']->sys_language_content) {! ! ! $OLmode = ($this->sys_language_mode == 'strict'?'hideNonTranslated':'');! ! ! $row = $GLOBALS['TSFE']->sys_page->getRecordOverlay('tt_news', $row, $GLOBALS['TSFE']->sys_language_content, $OLmode);! ! }! ! if ($this->versioningEnabled) {! ! ! // get workspaces Overlay! ! ! $GLOBALS['TSFE']->sys_page->versionOL('tt_news',$row);! ! ! // fix pid for record from workspace! ! ! $GLOBALS['TSFE']->sys_page->fixVersioningPid('tt_news',$row);! ! }! ! $GLOBALS['TSFE']->displayedNews[]=$row['uid'];
! ! if (is_array($row) && ($row['pid'] > 0 || $this->vPrev)) { // never display versions of a news record (having pid=-1) for normal website users! ! ! ! // Get the subpart code! ! ! if ($this->conf['displayCurrentRecord']) {! ! ! ! $item = trim($this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_SINGLE_RECORDINSERT###'), $row));! ! ! }! ! ! if (!$item) {! ! ! ! $item = $this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_SINGLE###'), $row);! ! ! }! ! ! ! // reset marker array! ! ! $wrappedSubpartArray = array();! ! ! ! // build the backToList link! ! ! if ($this->conf['useHRDates']) {! ! ! ! $pointerName = 'pointer';! ! ! ! $wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $this->pi_linkTP_keepPIvars('|', array(! ! ! ! ! 'tt_news' => null,! ! ! ! ! 'backPid' => null,! ! ! ! ! $this->config['singleViewPointerName'] => null,! ! ! ! ! 'pS' => null,! ! ! ! ! 'pL' => null), $this->allowCaching, ($this->conf['dontUseBackPid']?1:0), $this->config['backPid']));! ! ! } else {! ! ! ! $wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $this->pi_linkTP_keepPIvars('|', array(! ! ! ! ! 'tt_news' => null,! ! ! ! ! 'backPid' => null,! ! ! ! ! $this->config['singleViewPointerName'] => null), $this->allowCaching, ($this->conf['dontUseBackPid']?1:0), $this->config['backPid']));! ! ! }! ! ! ! // set the title of the single view page to the title of the news record! ! ! if ($this->conf['substitutePagetitle']) {! ! ! ! $GLOBALS['TSFE']->page['title'] = $row['title'];! ! ! ! // set pagetitle for indexed search to news title! ! ! ! $GLOBALS['TSFE']->indexedDocTitle = $row['title'];! ! ! }! ! ! if ($this->conf['displaySingle.']['catOrderBy']) {! ! ! ! $this->config['catOrderBy'] = $this->conf['displaySingle.']['catOrderBy'];! ! ! }! ! ! $markerArray = $this->getItemMarkerArray($row, 'displaySingle');! ! ! // Substitute! ! ! $content = $this->cObj->substituteMarkerArrayCached($item, $markerArray, array(), $wrappedSubpartArray);! ! } elseif ($this->sys_language_mode == 'strict' && $this->tt_news_uid && $GLOBALS['TSFE']->sys_language_content) { // not existing translation! ! ! $noTranslMsg = $this->local_cObj->stdWrap($this->pi_getLL('noTranslMsg'), $this->conf['noNewsIdMsg_stdWrap.']);! ! ! $content = $noTranslMsg;! ! } elseif ($row['pid'] < 0) { // a non-public version of a record was requested! ! ! $nonPlublicVersion = $this->local_cObj->stdWrap($this->pi_getLL('nonPlublicVersionMsg'), $this->conf['nonPlublicVersionMsg_stdWrap.']);! ! ! $content = $nonPlublicVersion;! ! } else { // if singleview is shown with no tt_news uid given from GETvars (&tx_ttnews[tt_news]=) an error message is displayed.! ! ! $noNewsIdMsg = $this->local_cObj->stdWrap($this->pi_getLL('noNewsIdMsg'), $this->conf['noNewsIdMsg_stdWrap.']);! ! ! $content = $noNewsIdMsg;! ! }! ! return $content;! }
! /**! * Displays the "versioning preview".! * The functions checks:! * - if the extension "version" is loaded! * - if a BE_user is logged in! * - the plausibility of the requested "version preview".! * If this is all OK, "displaySingle()" is executed to display the "versioning preview".! *! * @return!string! ! html code for the "versioning preview"! */! function displayVersionPreview () {! ! if ($this->versioningEnabled) {! ! ! $vPrev = t3lib_div::_GP('ADMCMD_vPrev');! ! ! if ($this->piVars['ADMCMD_vPrev']) {! ! ! ! $piADMCMD = unserialize(rawurldecode($this->piVars['ADMCMD_vPrev']));! ! ! }! ! ! if ((is_array($vPrev) || is_array($piADMCMD)) && is_object($GLOBALS['BE_USER'])) { // check if ADMCMD_vPrev is set and if a BE_user is logged in. $this->piVars['ADMCMD_vPrev'] is needed for previewing a "single view with pagebrowser"! ! ! ! if (!is_array($vPrev)) { $vPrev = $piADMCMD; }! ! ! ! list($table,$t3ver_oid) = explode(':',key($vPrev));! ! ! ! if ($table == 'tt_news') {! ! ! ! ! if ($testrec = $this->pi_getRecord('tt_news', intval($vPrev[key($vPrev)]))) { // check if record exists before doing anything! ! ! ! ! ! if ($testrec['t3ver_oid'] == intval($t3ver_oid) && $testrec['pid']==-1) { // check if requested t3ver_oid is the t3ver_oid of the requested tt_news record, and if the pid of the record is -1 (=non-plublic version)! ! ! ! ! ! ! $GLOBALS['TSFE']->set_no_cache(); // version preview will never be cached! ! ! ! ! ! ! ! // make version preview message with a link to the public version of hte record which is previewed! ! ! ! ! ! ! $vPrevHeader = $this->local_cObj->stdWrap(! ! ! ! ! ! ! ! $this->pi_getLL('versionPreviewMessage').! ! ! ! ! ! ! ! ! $this->local_cObj->typolink(! ! ! ! ! ! ! ! ! ! $this->local_cObj->stdWrap(! ! ! ! ! ! ! ! ! ! ! $this->pi_getLL('versionPreviewMessageLinkToOriginal'),$this->conf['versionPreviewMessageLinkToOriginal_stdWrap.']! ! ! ! ! ! ! ! ! ! ),! ! ! ! ! ! ! ! ! ! array(! ! ! ! ! ! ! ! ! ! ! 'parameter' => $this->config['singlePid'].' _blank',! ! ! ! ! ! ! ! ! ! ! 'additionalParams' => '&tx_ttnews[tt_news]='.$t3ver_oid,! ! ! ! ! ! ! ! ! ! ! 'no_cache' => 1! ! ! ! ! ! ! ! ! ! )! ! ! ! ! ! ! ! ! ),! ! ! ! ! ! ! ! $this->conf['versionPreviewMessage_stdWrap.']! ! ! ! ! ! ! );! ! ! ! ! ! ! $this->tt_news_uid = intval($vPrev[key($vPrev)]);! ! ! ! ! ! ! $this->piVars['tt_news'] = $this->tt_news_uid;! ! ! ! ! ! ! $this->piVars['ADMCMD_vPrev'] = rawurlencode(serialize(array($table.':'.$t3ver_oid => $this->tt_news_uid)));! ! ! ! ! ! ! $this->theCode = 'SINGLE';! ! ! ! ! ! ! $this->vPrev = true;! ! ! ! ! ! ! $content = $vPrevHeader.$this->displaySingle();! ! ! ! ! ! } else { // error: t3ver_oid mismatch! ! ! ! ! ! ! $GLOBALS['TT']->setTSlogMessage('tt_news: ERROR! The "t3ver_oid" of requested tt_news record and the "t3ver_oid" from GPvars doesn\'t match.');! ! ! ! ! ! }! ! ! ! ! }! ! ! ! }! ! ! }! ! }! ! return $content;! }
<?php/**************************************************************** Copyright notice** (c) 1999-2004 Kasper Skårhøj ([email protected])* (c) 2004-2007 Rupert Germann ([email protected])* All rights reserved** This script is part of the TYPO3 project. The TYPO3 project is* free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** The GNU General Public License can be found at* http://www.gnu.org/copyleft/gpl.html.* A copy is found in the textfile GPL.txt and important notices to the license* from the author is found in LICENSE.txt distributed with these scripts.*** This script is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** This copyright notice MUST APPEAR in all copies of the script!***************************************************************//*** class.tx_ttnews.php** versatile news system for TYPO3.* $Id: class.tx_ttnews.php 8605 2008-03-15 20:03:19Z rupertgermann $** TypoScript setup:* @See static/ts_new/setup.txt* @See tt_news Manual: ! http://typo3.org/documentation/document-library/extension-manuals/tt_news/current/* @See TSref: ! ! ! http://typo3.org/documentation/document-library/references/doc_core_tsref/current/** @author Rupert Germann <[email protected]>* @co-author Ingo Renner <[email protected]>*//** * [CLASS/FUNCTION INDEX of SCRIPT] * * * * 112: class tx_ttnews extends tslib_pibase * 143: function main_news($content, $conf) * 219: function init($conf) * 373: function newsArchiveMenu() * 523: function displaySingle() * 606: function displayVersionPreview () * 659: function displayList($excludeUids = 0) * 1003: function getListContent($itemparts, $selectConf, $prefix_display) * 1172: function getSelectConf($where, $noPeriod = 0) * 1419: function generatePageArray() * 1440: function getItemMarkerArray ($row, $textRenderObj = 'displaySingle') * 1723: function insertPagebreaks($text,$firstPageWordCrop) * 1773: function makeMultiPageSView($bodytext,$lConf) * 1803: function makePageBrowser($showResultCount=1,$tableParams='',$pointerName='pointer') * 1885: function getCategories($uid, $getAll=false) * 1958: function getCategoryPath($categoryArray) * 2015: function getSubCategories($catlist, $cc = 0) * 2044: function displayCatMenu() * 2157: function getCatMenuContent($array_in,$lConf, $l=0) * 2209: function getSubCategoriesForMenu ($catlist, $fields, $addWhere, $cc = 0) * 2240: function getCatMarkerArray($markerArray, $row, $lConf) * 2380: function getImageMarkers($markerArray, $row, $lConf, $textRenderObj) * 2448: function getRelated($uid) * 2608: function userProcess($mConfKey, $passVar) * 2623: function spMarker($subpartMarker) * 2641: function searchWhere($sw) * 2652: function formatStr($str) * 2667: function getLayouts($templateCode, $alternatingLayouts, $marker) * 2685: function initLanguages () * 2705: function initCategoryVars() * 2775: function checkRecords($recordlist) * 2807: function initTemplate() * 2832: function initPidList () * 2857: function getXmlHeader() * 2958: function getW3cDate($datetime) * 2983: function main_xmlnewsfeed($content, $conf) * 2998: function getStoriesResult() * 3020: function cleanXML($str) * 3034: function convertDates() * 3073: function getHrDateSingle($tstamp) * 3086: function displayFEHelp() * 3107: function validateFields($fieldlist) * 3128: function getNewsSubpart($myTemplate, $myKey, $row = Array()) * * SECTION: DB Functions * 3149: function exec_getQuery($table, $conf) * 3167: function getQuery($table, $conf, $returnQueryArray=FALSE) * 3249: function getWhere($table,$conf, $returnQueryArray=FALSE) * * TOTAL FUNCTIONS: 45 * (This index is automatically created/updated by the extension "extdeveval") * */
require_once(PATH_t3lib . 'class.t3lib_xml.php');require_once(PATH_t3lib . 'class.t3lib_htmlmail.php');require_once(PATH_tslib . 'class.tslib_pibase.php');require_once(t3lib_extMgm::extPath('tt_news') . 'class.tx_ttnews_catmenu.php');
/** * Plugin 'news' for the 'tt_news' extension. * * @author Rupert Germann <[email protected]> * @package TYPO3 * @subpackage tt_news */class tx_ttnews extends tslib_pibase {! // Default plugin variables:! var $prefixId = 'tx_ttnews'; // Same as class name! var $scriptRelPath = 'pi/class.tx_ttnews.php'; // Path to this script relative to the extension dir.! var $extKey = 'tt_news'; // The extension key.! var $tt_news_uid; // the uid of the current news record in SINGLE view! var $config; // the processed TypoScript configuration array! var $langArr; // the languages found in the tt_news sysfolder! var $sys_language_mode;! var $alternatingLayouts;! var $allowCaching;! var $catExclusive;! var $arcExclusive;! var $searchFieldList = 'short,bodytext,author,keywords,links,imagecaption,title';! var $theCode = '';! var $rdfToc = '';! var $versioningEnabled = false; // is the extension 'version' loaded! var $vPrev = false; // do we display a versioning preview! var $categories = array(); // Is initialized with the categories of the news system! var $pageArray = array(); // Is initialized with an array of the pages in the pid-list
! /**! * Main news function: calls the init_news() function and decides by the given CODEs which of the! * functions to display news should by called.! *! * @param! string! ! $content : function output is added to this! * @param! array!! $conf : configuration array! * @return!string! ! $content: complete content generated by the tt_news plugin! */! function main_news($content, $conf) {! ! $this->local_cObj = t3lib_div::makeInstance('tslib_cObj'); // Local cObj.! ! $this->init($conf);
! ! if ($this->conf['displayCurrentRecord']) {! ! ! $this->config['code'] = $this->conf['defaultCode']?trim($this->conf['defaultCode']):'SINGLE';! ! ! $this->tt_news_uid = $this->cObj->data['uid'];! ! }
! ! // get codes and decide which function is used to process the content! ! $codes = t3lib_div::trimExplode(',', $this->config['code']?$this->config['code']:$this->conf['defaultCode'], 1);! ! if (!count($codes)) { // no code at all! ! ! $codes = array();! ! ! $noCode = true;! ! }
! ! while (list(, $theCode) = each($codes)) {! ! ! $theCode = (string)strtoupper(trim($theCode));! ! ! $this->theCode = $theCode;! ! ! switch ($theCode) {! ! ! ! case 'SINGLE':! ! ! ! $content .= $this->displaySingle();! ! ! ! break;! ! ! ! case 'VERSION_PREVIEW':! ! ! ! $content .= $this->displayVersionPreview();! ! ! ! break;! ! ! ! case 'LATEST':! ! ! ! case 'LIST':! ! ! ! case 'SEARCH':! ! ! ! case 'XML':! ! ! ! $content .= $this->displayList();! ! ! ! break;! ! ! ! case 'AMENU':! ! ! ! $content .= $this->newsArchiveMenu();! ! ! ! break;! ! ! ! case 'CATMENU':! ! ! ! $content .= $this->displayCatMenu();! ! ! ! break;! ! ! ! default:! ! ! ! // Adds hook for processing of extra codes! ! ! ! if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['tt_news']['extraCodesHook'])) {! ! ! ! ! foreach($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['tt_news']['extraCodesHook'] as $_classRef) {! ! ! ! ! ! $_procObj = & t3lib_div::getUserObj($_classRef);! ! ! ! ! ! $content .= $_procObj->extraCodesProcessor($this);! ! ! ! ! }! ! ! ! } else {! ! ! ! ! $langKey = strtoupper($GLOBALS['TSFE']->config['config']['language']);! ! ! ! ! $helpTemplate = $this->cObj->fileResource('EXT:tt_news/pi/news_help.tmpl');! ! ! ! ! // Get language version of the help-template! ! ! ! ! $helpTemplate_lang = '';! ! ! ! ! if ($langKey) {! ! ! ! ! ! $helpTemplate_lang = $this->getNewsSubpart($helpTemplate, "###TEMPLATE_" . $langKey . '###');! ! ! ! ! }! ! ! ! ! $helpTemplate = $helpTemplate_lang ? $helpTemplate_lang :! ! ! ! ! $this->getNewsSubpart($helpTemplate, '###TEMPLATE_DEFAULT###');! ! ! ! ! // Markers and substitution:! ! ! ! ! $markerArray['###CODE###'] = $this->theCode;! ! ! ! ! $markerArray['###EXTPATH###'] = $GLOBALS['TYPO3_LOADED_EXT']['tt_news']['siteRelPath'];! ! ! ! ! $content .= $this->displayFEHelp();! ! ! ! }! ! ! ! break;! ! ! }! ! }! ! if($noCode) {! ! ! $content .= $this->displayFEHelp();! ! }! ! return $content;! }
! /**! * Init Function: here all the needed configuration values are stored in class variables..! *! * @param! array!! $conf : configuration array from TS! * @return!void! */! function init($conf) {! ! $this->conf = $conf; //store configuration! ! $this->pi_loadLL(); // Loading language-labels! ! $this->pi_setPiVarDefaults(); // Set default piVars from TS! ! $this->pi_initPIflexForm(); // Init FlexForm configuration for plugin! ! $this->enableFields = $this->cObj->enableFields('tt_news');! ! $this->tt_news_uid = intval($this->piVars['tt_news']); // Get the submitted uid of a news (if any)
! ! if (!isset($this->conf['compatVersion']) || !preg_match('/^\d+\.\d+\.\d+$/', $this->conf['compatVersion'])) {! ! ! $this->conf['compatVersion'] = $this->getCurrentVersion();! ! }
! ! if (t3lib_extMgm::isLoaded('version')) {! ! ! $this->versioningEnabled = true;! ! }! ! // load available syslanguages! ! $this->initLanguages();! ! // sys_language_mode defines what to do if the requested translation is not found! ! $this->sys_language_mode = $this->conf['sys_language_mode']?$this->conf['sys_language_mode'] : $GLOBALS['TSFE']->sys_language_mode;
! ! // "CODE" decides what is rendered: codes can be set by TS or FF with priority on FF! ! $code = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'what_to_display', 'sDEF');! ! $this->config['code'] = $code ? $code : $this->cObj->stdWrap($this->conf['code'], $this->conf['code.']);
! ! // initialize category vars! ! $this->initCategoryVars();
! ! ! // get fieldnames from the tt_news db-table! ! $this->fieldNames = array_keys($GLOBALS['TYPO3_DB']->admin_get_fields('tt_news'));
! ! if ($this->conf['searchFieldList']) {! ! ! $searchFieldList = $this->validateFields($this->conf['searchFieldList']);! ! ! if ($searchFieldList) {! ! ! ! $this->searchFieldList = $searchFieldList;! ! ! }! ! }! ! ! // Archive:! ! $this->config['archiveMode'] = trim($this->conf['archiveMode']) ; // month, quarter or year listing in AMENU! ! $this->config['archiveMode'] = $this->config['archiveMode']?$this->config['archiveMode']:'month';
! ! // arcExclusive : -1=only non-archived; 0=don't care; 1=only archived! ! $arcExclusive = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'archive', 'sDEF');! ! $this->arcExclusive = $arcExclusive?$arcExclusive:$this->conf['archive'];
! ! $this->config['datetimeDaysToArchive'] = intval($this->conf['datetimeDaysToArchive']);! ! $this->config['datetimeHoursToArchive'] = intval($this->conf['datetimeHoursToArchive']);! ! $this->config['datetimeMinutesToArchive'] = intval($this->conf['datetimeMinutesToArchive']);
! ! if ($this->conf['useHRDates']) {! ! ! $this->convertDates();! ! }
! ! // list of pages where news records will be taken from! ! if (!$this->conf['dontUsePidList']) {! ! ! $this->initPidList();! ! }
! ! // itemLinkTarget is only used for categoryLinkMode 3 (catselector) in framesets! ! $this->config['itemLinkTarget'] = trim($this->conf['itemLinkTarget']);! ! // id of the page where the search results should be displayed! ! $this->config['searchPid'] = intval($this->conf['searchPid']);
! ! // pages in Single view will be divided by this token! ! $this->config['pageBreakToken'] = trim($this->conf['pageBreakToken'])?trim($this->conf['pageBreakToken']):'<---newpage--->';
! ! $this->config['singleViewPointerName'] = trim($this->conf['singleViewPointerName'])?trim($this->conf['singleViewPointerName']):'sViewPointer';
! ! $maxWordsInSingleView = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'maxWordsInSingleView', 's_misc'));! ! $maxWordsInSingleView = $maxWordsInSingleView?$maxWordsInSingleView:intval($this->conf['maxWordsInSingleView']);! ! $this->config['maxWordsInSingleView'] = $maxWordsInSingleView?$maxWordsInSingleView:0;! ! $this->config['useMultiPageSingleView'] = $maxWordsInSingleView>1?1:$this->conf['useMultiPageSingleView'];
! ! // pid of the page with the single view. the old var PIDitemDisplay is still processed if no other value is found! ! $singlePid = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'PIDitemDisplay', 's_misc');! ! $singlePid = $singlePid?$singlePid:intval($this->cObj->stdWrap($this->conf['singlePid'],$this->conf['singlePid.']));! ! $this->config['singlePid'] = $singlePid ? $singlePid:intval($this->conf['PIDitemDisplay']);
! ! // pid to return to when leaving single view! ! $backPid = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'backPid', 's_misc'));! ! $backPid = $backPid?$backPid:intval($this->conf['backPid']);! ! $backPid = $backPid?$backPid:intval($this->piVars['backPid']);! ! $backPid = $backPid?$backPid:$GLOBALS['TSFE']->id ;! ! $this->config['backPid'] = $backPid;
! ! // max items per page! ! $FFlimit = t3lib_div::intInRange($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listLimit', 's_misc'), 0, 1000);
! ! $limit = t3lib_div::intInRange($this->cObj->stdWrap($this->conf['limit'],$this->conf['limit.']), 0, 1000);! ! $limit = $limit?$limit:! 50;! ! $this->config['limit'] = $FFlimit?$FFlimit:!$limit;
! ! $latestLimit = t3lib_div::intInRange($this->cObj->stdWrap($this->conf['latestLimit'],$this->conf['latestLimit.']), 0, 1000);! ! $latestLimit = $latestLimit?$latestLimit:10;! ! $this->config['latestLimit'] = $FFlimit?$FFlimit:$latestLimit;
! ! // orderBy and groupBy statements for the list Query! ! $orderBy = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listOrderBy', 'sDEF');! ! $orderByTS = trim($this->conf['listOrderBy']);! ! $orderBy = $orderBy?$orderBy:$orderByTS;! ! $this->config['orderBy'] = $orderBy;
! ! if ($orderBy) {! ! ! $ascDesc = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'ascDesc', 'sDEF');! ! ! $this->config['ascDesc'] = $ascDesc;! ! ! if ($this->config['ascDesc']) {! ! ! ! // remove ASC/DESC from 'orderBy' if it is already set from TS! ! ! ! $this->config['orderBy'] = preg_replace('/( DESC| ASC)\b/i','',$this->config['orderBy']);! ! ! }! ! }! ! $this->config['groupBy'] = trim($this->conf['listGroupBy']);
! ! // if this is set, the first image is handled as preview image, which is only shown in list view! ! $fImgPreview = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'firstImageIsPreview', 's_misc');! ! $this->config['firstImageIsPreview'] = $fImgPreview?$fImgPreview : $this->conf['firstImageIsPreview'];! ! $forcefImgPreview = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'forceFirstImageIsPreview', 's_misc');! ! $this->config['forceFirstImageIsPreview'] = $forcefImgPreview?$fImgPreview : $this->conf['forceFirstImageIsPreview'];
! ! // List start id! ! $listStartId = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listStartId', 's_misc'));! ! $this->config['listStartId'] = $listStartId?$listStartId:intval($this->conf['listStartId']);! ! // supress pagebrowser! ! $noPageBrowser = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'noPageBrowser', 's_misc');! ! $this->config['noPageBrowser'] = $noPageBrowser?$noPageBrowser:! $this->conf['noPageBrowser'];
! ! // image sizes given from FlexForms! ! $this->config['FFimgH'] = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'imageMaxHeight', 's_template'));! ! $this->config['FFimgW'] = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'imageMaxWidth', 's_template'));
! ! // Get number of alternative Layouts (loop layout in LATEST and LIST view) default is 2:! ! $altLayouts = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'alternatingLayouts', 's_template'));! ! $altLayouts = $altLayouts?$altLayouts:intval($this->conf['alternatingLayouts']);! ! $this->alternatingLayouts = $altLayouts?$altLayouts:2;
! ! // Get cropping lenght! ! $this->config['croppingLenght'] = trim($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'croppingLenght', 's_template'));
! ! $this->initTemplate();
! ! // Configure caching! ! $this->allowCaching = $this->conf['allowCaching']?1:0;! ! if (!$this->allowCaching) {! ! ! $GLOBALS['TSFE']->set_no_cache();! ! }
! ! // get siteUrl for links in rss feeds. the 'dontInsert' option seems to be needed in some configurations depending on the baseUrl setting! ! if (!$this->conf['displayXML.']['dontInsertSiteUrl']) {! ! ! $this->config['siteUrl'] = t3lib_div::getIndpEnv('TYPO3_SITE_URL');! ! }! }
! /**! * generates the News archive menu! *! * @return!string! ! html code of the archive menu! */! function newsArchiveMenu() {
! ! $this->arcExclusive = 1;! ! $selectConf = $this->getSelectConf('', 1);! ! // Finding maximum and minimum values:! ! $selectConf['selectFields'] = 'max(tt_news.datetime) as maxval, min(tt_news.datetime) as minval';
! ! $res = $this->exec_getQuery('tt_news', $selectConf);
! ! $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);! ! if ($row['minval'] || $row['maxval']) {! ! ! // if ($row['minval']) {! ! ! $dateArr = array();! ! ! $arcMode = $this->config['archiveMode'];! ! ! $c = 0;! ! ! do {! ! ! ! switch ($arcMode) {! ! ! ! ! case 'month':! ! ! ! ! $theDate = mktime (0, 0, 0, date('m', $row['minval']) + $c, 1, date('Y', $row['minval']));! ! ! ! ! break;! ! ! ! ! case 'quarter':! ! ! ! ! $theDate = mktime (0, 0, 0, floor(date('m', $row['minval']) / 3) + 1 + (3 * $c), 1, date('Y', $row['minval']));! ! ! ! ! break;! ! ! ! ! case 'year':! ! ! ! ! $theDate = mktime (0, 0, 0, 1, 1, date('Y', $row['minval']) + $c);! ! ! ! ! break;! ! ! ! }! ! ! ! $dateArr[] = $theDate;! ! ! ! $c++;! ! ! ! if ($c > 1000) break;! ! ! }! ! ! while ($theDate < $GLOBALS['SIM_EXEC_TIME']);
! ! ! reset($dateArr);! ! ! $periodAccum = array();
! ! ! $selectConf2['where'] = $selectConf['where'];! ! ! while (list($k, $v) = each($dateArr)) {! ! ! ! if (!isset($dateArr[$k + 1])) {! ! ! ! ! break;! ! ! ! }
! ! ! ! $periodInfo = array();! ! ! ! $periodInfo['start'] = $dateArr[$k];! ! ! ! $periodInfo['stop'] = $dateArr[$k + 1]-1;! ! ! ! $periodInfo['HRstart'] = date('d-m-Y', $periodInfo['start']);! ! ! ! $periodInfo['HRstop'] = date('d-m-Y', $periodInfo['stop']);! ! ! ! $periodInfo['quarter'] = floor(date('m', $dateArr[$k]) / 3) + 1;! ! ! ! // execute a query to count the archive periods! ! ! ! $selectConf['selectFields'] = 'count(distinct(tt_news.uid))';! ! ! ! $selectConf['where'] = $selectConf2['where'] . ' AND tt_news.datetime>=' . $periodInfo['start'] . ' AND tt_news.datetime<' . $periodInfo['stop'];
! ! ! ! $res = $this->exec_getQuery('tt_news', $selectConf);
! ! ! ! $row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);! ! ! ! $periodInfo['count'] = $row[0];
! ! ! ! if (!$this->conf['archiveMenuNoEmpty'] || $periodInfo['count']) {! ! ! ! ! $periodAccum[] = $periodInfo;! ! ! ! }! ! ! }
! ! ! // get template subpart! ! ! $t['total'] = $this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_ARCHIVE###'));! ! ! $t['item'] = $this->getLayouts($t['total'], $this->alternatingLayouts, 'MENUITEM');! ! ! $cc = 0;
! ! ! $veryLocal_cObj = t3lib_div::makeInstance('tslib_cObj');! ! ! // reverse amenu order if 'reverseAMenu' is given! ! ! if ($this->conf['reverseAMenu']) {! ! ! ! arsort($periodAccum);! ! ! }
! ! ! $archiveLink = $this->conf['archiveTypoLink.']['parameter'];! ! ! $this->conf['parent.']['addParams'] = $this->conf['archiveTypoLink.']['addParams'];! ! ! reset($periodAccum);! ! ! $itemsOutArr = array();! ! ! while (list(, $pArr) = each($periodAccum)) {! ! ! ! // Print Item Title! ! ! ! $wrappedSubpartArray = array();
! ! ! ! if (!$this->conf['disableCategoriesInAmenuLinks']) {! ! ! ! ! if ($this->config['catSelection'] && $this->config['amenuWithCatSelector']) {! ! ! ! ! ! // use the catSelection from GPvars only if 'amenuWithCatSelector' is given.! ! ! ! ! ! $amenuLinkCat = $this->config['catSelection'];! ! ! ! ! } else {! ! ! ! ! ! $amenuLinkCat = $this->catExclusive;! ! ! ! ! }! ! ! ! }
! ! ! ! if ($this->conf['useHRDates']) {! ! ! ! ! $year = date('Y',$pArr['start']);! ! ! ! ! $month = date('m',$pArr['start']);! ! ! ! ! if ($arcMode == 'year') {! ! ! ! ! ! $archLinkArr = $this->pi_linkTP_keepPIvars('|', array('cat' => ($amenuLinkCat?$amenuLinkCat:null), 'year' => $year), $this->allowCaching, 1, ($archiveLink?$archiveLink:$GLOBALS['TSFE']->id));! ! ! ! ! } else {! ! ! ! ! ! $archLinkArr = $this->pi_linkTP_keepPIvars('|', array('cat' => ($amenuLinkCat?$amenuLinkCat:null), 'year' => $year, 'month' => $month), $this->allowCaching, 1, ($archiveLink?$archiveLink:$GLOBALS['TSFE']->id));! ! ! ! ! }! ! ! ! ! $wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $archLinkArr);! ! ! ! } else {! ! ! ! ! $wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $this->pi_linkTP_keepPIvars('|', array('cat' => ($amenuLinkCat?$amenuLinkCat:null), 'pS' => $pArr['start'], 'pL' => ($pArr['stop'] - $pArr['start']), 'arc' => 1), $this->allowCaching, 1, ($archiveLink?$archiveLink:$GLOBALS['TSFE']->id)));! ! ! ! }
! ! ! ! $markerArray = array();! ! ! ! $veryLocal_cObj->start($pArr, '');! ! ! ! $markerArray['###ARCHIVE_TITLE###'] = $veryLocal_cObj->cObjGetSingle($this->conf['archiveTitleCObject'], $this->conf['archiveTitleCObject.'], 'archiveTitle');! ! ! ! $markerArray['###ARCHIVE_COUNT###'] = $pArr['count'];! ! ! ! $markerArray['###ARCHIVE_ITEMS###'] = $this->pi_getLL('archiveItems');
! ! ! ! // fill the generated data to an array to pass it to a userfuction as a single variable! ! ! ! $itemsOutArr[] = array('html' => $this->cObj->substituteMarkerArrayCached($t['item'][($cc % count($t['item']))], $markerArray, array(), $wrappedSubpartArray), 'data' => $pArr);! ! ! ! $cc++;! ! ! }! ! ! // Pass to user defined function! ! ! if ($this->conf['newsAmenuUserFunc']) {! ! ! ! $itemsOutArr = $this->userProcess('newsAmenuUserFunc', $itemsOutArr);! ! ! }
! ! ! foreach ($itemsOutArr as $itemHtml) {! ! ! ! $tmpItemsArr[] = $itemHtml['html'];! ! ! }
! ! ! if (is_array($tmpItemsArr)) {! ! ! ! $itemsOut = implode('', $tmpItemsArr);! ! ! }
! ! ! // Reset:! ! ! $subpartArray = array();! ! ! $wrappedSubpartArray = array();! ! ! $markerArray = array();! ! ! $markerArray['###ARCHIVE_HEADER###'] = $this->local_cObj->stdWrap($this->pi_getLL('archiveHeader'), $this->conf['archiveHeader_stdWrap.']);! ! ! // Set content! ! ! $subpartArray['###CONTENT###'] = $itemsOut;! ! ! $content = $this->cObj->substituteMarkerArrayCached($t['total'], $markerArray, $subpartArray, $wrappedSubpartArray);! ! } else {! ! ! // if nothing is found in the archive display the TEMPLATE_ARCHIVE_NOITEMS message! ! ! $markerArray['###ARCHIVE_HEADER###'] = $this->local_cObj->stdWrap($this->pi_getLL('archiveHeader'), $this->conf['archiveHeader_stdWrap.']);! ! ! $markerArray['###ARCHIVE_EMPTY_MSG###'] = $this->local_cObj->stdWrap($this->pi_getLL('archiveEmptyMsg'), $this->conf['archiveEmptyMsg_stdWrap.']);! ! ! $noItemsMsg = $this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_ARCHIVE_NOITEMS###'));! ! ! $content = $this->cObj->substituteMarkerArrayCached($noItemsMsg, $markerArray);! ! }
! ! return $content;! }
! /**! * Displays the "single view" of a news article. Is also used when displaying single news records with the "insert records" content element.! *! * @return!string! ! html-code for the "single view"! */! function displaySingle() {! ! $singleWhere = 'tt_news.uid=' . intval($this->tt_news_uid);! ! $singleWhere .= ' AND type NOT IN(1,2)' . $this->enableFields; // only real news -> type=0
! ! $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(! ! ! '*',! ! ! 'tt_news',! ! ! $singleWhere);
! ! $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);! ! // get the translated record if the content language is not the default language! ! if ($GLOBALS['TSFE']->sys_language_content) {! ! ! $OLmode = ($this->sys_language_mode == 'strict'?'hideNonTranslated':'');! ! ! $row = $GLOBALS['TSFE']->sys_page->getRecordOverlay('tt_news', $row, $GLOBALS['TSFE']->sys_language_content, $OLmode);! ! }! ! if ($this->versioningEnabled) {! ! ! // get workspaces Overlay! ! ! $GLOBALS['TSFE']->sys_page->versionOL('tt_news',$row);! ! ! // fix pid for record from workspace! ! ! $GLOBALS['TSFE']->sys_page->fixVersioningPid('tt_news',$row);! ! }! ! $GLOBALS['TSFE']->displayedNews[]=$row['uid'];
! ! if (is_array($row) && ($row['pid'] > 0 || $this->vPrev)) { // never display versions of a news record (having pid=-1) for normal website users! ! ! ! // Get the subpart code! ! ! if ($this->conf['displayCurrentRecord']) {! ! ! ! $item = trim($this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_SINGLE_RECORDINSERT###'), $row));! ! ! }! ! ! if (!$item) {! ! ! ! $item = $this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_SINGLE###'), $row);! ! ! }! ! ! ! // reset marker array! ! ! $wrappedSubpartArray = array();! ! ! ! // build the backToList link! ! ! if ($this->conf['useHRDates']) {! ! ! ! $pointerName = 'pointer';! ! ! ! $wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $this->pi_linkTP_keepPIvars('|', array(! ! ! ! ! 'tt_news' => null,! ! ! ! ! 'backPid' => null,! ! ! ! ! $this->config['singleViewPointerName'] => null,! ! ! ! ! 'pS' => null,! ! ! ! ! 'pL' => null), $this->allowCaching, ($this->conf['dontUseBackPid']?1:0), $this->config['backPid']));! ! ! } else {! ! ! ! $wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $this->pi_linkTP_keepPIvars('|', array(! ! ! ! ! 'tt_news' => null,! ! ! ! ! 'backPid' => null,! ! ! ! ! $this->config['singleViewPointerName'] => null), $this->allowCaching, ($this->conf['dontUseBackPid']?1:0), $this->config['backPid']));! ! ! }! ! ! ! // set the title of the single view page to the title of the news record! ! ! if ($this->conf['substitutePagetitle']) {! ! ! ! $GLOBALS['TSFE']->page['title'] = $row['title'];! ! ! ! // set pagetitle for indexed search to news title! ! ! ! $GLOBALS['TSFE']->indexedDocTitle = $row['title'];! ! ! }! ! ! if ($this->conf['displaySingle.']['catOrderBy']) {! ! ! ! $this->config['catOrderBy'] = $this->conf['displaySingle.']['catOrderBy'];! ! ! }! ! ! $markerArray = $this->getItemMarkerArray($row, 'displaySingle');! ! ! // Substitute! ! ! $content = $this->cObj->substituteMarkerArrayCached($item, $markerArray, array(), $wrappedSubpartArray);! ! } elseif ($this->sys_language_mode == 'strict' && $this->tt_news_uid && $GLOBALS['TSFE']->sys_language_content) { // not existing translation! ! ! $noTranslMsg = $this->local_cObj->stdWrap($this->pi_getLL('noTranslMsg'), $this->conf['noNewsIdMsg_stdWrap.']);! ! ! $content = $noTranslMsg;! ! } elseif ($row['pid'] < 0) { // a non-public version of a record was requested! ! ! $nonPlublicVersion = $this->local_cObj->stdWrap($this->pi_getLL('nonPlublicVersionMsg'), $this->conf['nonPlublicVersionMsg_stdWrap.']);! ! ! $content = $nonPlublicVersion;! ! } else { // if singleview is shown with no tt_news uid given from GETvars (&tx_ttnews[tt_news]=) an error message is displayed.! ! ! $noNewsIdMsg = $this->local_cObj->stdWrap($this->pi_getLL('noNewsIdMsg'), $this->conf['noNewsIdMsg_stdWrap.']);! ! ! $content = $noNewsIdMsg;! ! }! ! return $content;! }
! /**! * Displays the "versioning preview".! * The functions checks:! * - if the extension "version" is loaded! * - if a BE_user is logged in! * - the plausibility of the requested "version preview".! * If this is all OK, "displaySingle()" is executed to display the "versioning preview".! *! * @return!string! ! html code for the "versioning preview"! */! function displayVersionPreview () {! ! if ($this->versioningEnabled) {! ! ! $vPrev = t3lib_div::_GP('ADMCMD_vPrev');! ! ! if ($this->piVars['ADMCMD_vPrev']) {! ! ! ! $piADMCMD = unserialize(rawurldecode($this->piVars['ADMCMD_vPrev']));! ! ! }! ! ! if ((is_array($vPrev) || is_array($piADMCMD)) && is_object($GLOBALS['BE_USER'])) { // check if ADMCMD_vPrev is set and if a BE_user is logged in. $this->piVars['ADMCMD_vPrev'] is needed for previewing a "single view with pagebrowser"! ! ! ! if (!is_array($vPrev)) { $vPrev = $piADMCMD; }! ! ! ! list($table,$t3ver_oid) = explode(':',key($vPrev));! ! ! ! if ($table == 'tt_news') {! ! ! ! ! if ($testrec = $this->pi_getRecord('tt_news', intval($vPrev[key($vPrev)]))) { // check if record exists before doing anything! ! ! ! ! ! if ($testrec['t3ver_oid'] == intval($t3ver_oid) && $testrec['pid']==-1) { // check if requested t3ver_oid is the t3ver_oid of the requested tt_news record, and if the pid of the record is -1 (=non-plublic version)! ! ! ! ! ! ! $GLOBALS['TSFE']->set_no_cache(); // version preview will never be cached! ! ! ! ! ! ! ! // make version preview message with a link to the public version of hte record which is previewed! ! ! ! ! ! ! $vPrevHeader = $this->local_cObj->stdWrap(! ! ! ! ! ! ! ! $this->pi_getLL('versionPreviewMessage').! ! ! ! ! ! ! ! ! $this->local_cObj->typolink(! ! ! ! ! ! ! ! ! ! $this->local_cObj->stdWrap(! ! ! ! ! ! ! ! ! ! ! $this->pi_getLL('versionPreviewMessageLinkToOriginal'),$this->conf['versionPreviewMessageLinkToOriginal_stdWrap.']! ! ! ! ! ! ! ! ! ! ),! ! ! ! ! ! ! ! ! ! array(! ! ! ! ! ! ! ! ! ! ! 'parameter' => $this->config['singlePid'].' _blank',! ! ! ! ! ! ! ! ! ! ! 'additionalParams' => '&tx_ttnews[tt_news]='.$t3ver_oid,! ! ! ! ! ! ! ! ! ! ! 'no_cache' => 1! ! ! ! ! ! ! ! ! ! )! ! ! ! ! ! ! ! ! ),! ! ! ! ! ! ! ! $this->conf['versionPreviewMessage_stdWrap.']! ! ! ! ! ! ! );! ! ! ! ! ! ! $this->tt_news_uid = intval($vPrev[key($vPrev)]);! ! ! ! ! ! ! $this->piVars['tt_news'] = $this->tt_news_uid;! ! ! ! ! ! ! $this->piVars['ADMCMD_vPrev'] = rawurlencode(serialize(array($table.':'.$t3ver_oid => $this->tt_news_uid)));! ! ! ! ! ! ! $this->theCode = 'SINGLE';! ! ! ! ! ! ! $this->vPrev = true;! ! ! ! ! ! ! $content = $vPrevHeader.$this->displaySingle();! ! ! ! ! ! } else { // error: t3ver_oid mismatch! ! ! ! ! ! ! $GLOBALS['TT']->setTSlogMessage('tt_news: ERROR! The "t3ver_oid" of requested tt_news record and the "t3ver_oid" from GPvars doesn\'t match.');! ! ! ! ! ! }! ! ! ! ! }! ! ! ! }! ! ! }! ! }! ! return $content;! }
<?php/**************************************************************** Copyright notice** (c) 1999-2004 Kasper Skårhøj ([email protected])* (c) 2004-2007 Rupert Germann ([email protected])* All rights reserved** This script is part of the TYPO3 project. The TYPO3 project is* free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** The GNU General Public License can be found at* http://www.gnu.org/copyleft/gpl.html.* A copy is found in the textfile GPL.txt and important notices to the license* from the author is found in LICENSE.txt distributed with these scripts.*** This script is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** This copyright notice MUST APPEAR in all copies of the script!***************************************************************//*** class.tx_ttnews.php** versatile news system for TYPO3.* $Id: class.tx_ttnews.php 8605 2008-03-15 20:03:19Z rupertgermann $** TypoScript setup:* @See static/ts_new/setup.txt* @See tt_news Manual: !
http://typo3.org/documentation/document-library/extension-manuals/tt_news/current/* @See TSref: ! !
!
http://typo3.org/documentation/document-library/references/doc_core_tsref/current/** @author Rupert Germann <[email protected]>* @co-author Ingo Renner <[email protected]>*//** * [CLASS/FUNCTION INDEX of SCRIPT] * * * * 112: class tx_ttnews extends tslib_pibase * 143: function main_news($content, $conf) * 219: function init($conf) * 373: function newsArchiveMenu() * 523: function displaySingle() * 606: function displayVersionPreview () * 659: function displayList($excludeUids = 0) * 1003: function getListContent($itemparts, $selectConf, $prefix_display) * 1172: function getSelectConf($where, $noPeriod = 0) * 1419: function generatePageArray() * 1440: function getItemMarkerArray ($row, $textRenderObj = 'displaySingle') * 1723: function insertPagebreaks($text,$firstPageWordCrop) * 1773: function makeMultiPageSView($bodytext,$lConf) * 1803: function makePageBrowser($showResultCount=1,$tableParams='',$pointerName='pointer') * 1885: function getCategories($uid, $getAll=false) * 1958: function getCategoryPath($categoryArray) * 2015: function getSubCategories($catlist, $cc = 0) * 2044: function displayCatMenu() * 2157: function getCatMenuContent($array_in,$lConf, $l=0) * 2209: function getSubCategoriesForMenu ($catlist, $fields, $addWhere, $cc = 0) * 2240: function getCatMarkerArray($markerArray, $row, $lConf) * 2380: function getImageMarkers($markerArray, $row, $lConf, $textRenderObj) * 2448: function getRelated($uid) * 2608: function userProcess($mConfKey, $passVar) * 2623: function spMarker($subpartMarker) * 2641: function searchWhere($sw) * 2652: function formatStr($str) * 2667: function getLayouts($templateCode, $alternatingLayouts, $marker) * 2685: function initLanguages () * 2705: function initCategoryVars() * 2775: function checkRecords($recordlist) * 2807: function initTemplate() * 2832: function initPidList () * 2857: function getXmlHeader() * 2958: function getW3cDate($datetime) * 2983: function main_xmlnewsfeed($content, $conf) * 2998: function getStoriesResult() * 3020: function cleanXML($str) * 3034: function convertDates() * 3073: function getHrDateSingle($tstamp) * 3086: function displayFEHelp() * 3107: function validateFields($fieldlist) * 3128: function getNewsSubpart($myTemplate, $myKey, $row = Array()) * * SECTION: DB Functions * 3149: function exec_getQuery($table, $conf) * 3167: function getQuery($table, $conf, $returnQueryArray=FALSE) * 3249: function getWhere($table,$conf, $returnQueryArray=FALSE) * * TOTAL FUNCTIONS: 45 * (This index is automatically created/updated by the extension "extdeveval") * */
require_once(PATH_t3lib . 'class.t3lib_xml.php');require_once(PATH_t3lib . 'class.t3lib_htmlmail.php');require_once(PATH_tslib . 'class.tslib_pibase.php');require_once(t3lib_extMgm::extPath('tt_news') . 'class.tx_ttnews_catmenu.php');
/** * Plugin 'news' for the 'tt_news' extension. * * @author Rupert Germann <[email protected]> * @package TYPO3 * @subpackage tt_news */class tx_ttnews extends tslib_pibase {!
// Default plugin variables:!
var $prefixId = 'tx_ttnews'; // Same as class name!
var $scriptRelPath = 'pi/class.tx_ttnews.php'; // Path to this script relative to the extension dir.!
var $extKey = 'tt_news'; // The extension key.!
var $tt_news_uid; // the uid of the current news record in SINGLE view!
var $config; // the processed TypoScript configuration array!
var $langArr; // the languages found in the tt_news sysfolder!
var $sys_language_mode;!
var $alternatingLayouts;!
var $allowCaching;!
var $catExclusive;!
var $arcExclusive;!
var $searchFieldList = 'short,bodytext,author,keywords,links,imagecaption,title';!
var $theCode = '';!
var $rdfToc = '';!
var $versioningEnabled = false; // is the extension 'version' loaded!
var $vPrev = false; // do we display a versioning preview!
var $categories = array(); // Is initialized with the categories of the news system!
var $pageArray = array(); // Is initialized with an array of the pages in the pid-list
!
/**! * Main news function: calls the init_news() function and decides by the given CODEs which of the! * functions to display news should by called.! *! * @param!
string! !
$content : function output is added to this! * @param!
array! !
$conf : configuration array! * @return!
string! !
$content: complete content generated by the tt_news plugin! */!
function main_news($content, $conf) {! !
$this->local_cObj = t3lib_div::makeInstance('tslib_cObj'); // Local cObj.! !
$this->init($conf);
! !
if ($this->conf['displayCurrentRecord']) {! !
!
$this->config['code'] = $this->conf['defaultCode']?trim($this->conf['defaultCode']):'SINGLE';! !
!
$this->tt_news_uid = $this->cObj->data['uid'];! !
}
! !
// get codes and decide which function is used to process the content! !
$codes = t3lib_div::trimExplode(',', $this->config['code']?$this->config['code']:$this->conf['defaultCode'], 1);! !
if (!count($codes)) { // no code at all! !
!
$codes = array();! !
!
$noCode = true;! !
}
! !
while (list(, $theCode) = each($codes)) {! !
!
$theCode = (string)strtoupper(trim($theCode));! !
!
$this->theCode = $theCode;! !
!
switch ($theCode) {! !
! !
case 'SINGLE':! !
! !
$content .= $this->displaySingle();! !
! !
break;! !
! !
case 'VERSION_PREVIEW':! !
! !
$content .= $this->displayVersionPreview();! !
! !
break;! !
! !
case 'LATEST':! !
! !
case 'LIST':! !
! !
case 'SEARCH':! !
! !
case 'XML':! !
! !
$content .= $this->displayList();! !
! !
break;! !
! !
case 'AMENU':! !
! !
$content .= $this->newsArchiveMenu();! !
! !
break;! !
! !
case 'CATMENU':! !
! !
$content .= $this->displayCatMenu();! !
! !
break;! !
! !
default:! !
! !
// Adds hook for processing of extra codes! !
! !
if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['tt_news']['extraCodesHook'])) {! !
! !
!
foreach($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['tt_news']['extraCodesHook'] as $_classRef) {! !
! !
! !
$_procObj = & t3lib_div::getUserObj($_classRef);! !
! !
! !
$content .= $_procObj->extraCodesProcessor($this);! !
! !
!
}! !
! !
} else {! !
! !
!
$langKey = strtoupper($GLOBALS['TSFE']->config['config']['language']);! !
! !
!
$helpTemplate = $this->cObj->fileResource('EXT:tt_news/pi/news_help.tmpl');! !
! !
!
// Get language version of the help-template! !
! !
!
$helpTemplate_lang = '';! !
! !
!
if ($langKey) {! !
! !
! !
$helpTemplate_lang = $this->getNewsSubpart($helpTemplate, "###TEMPLATE_" . $langKey . '###');! !
! !
!
}! !
! !
!
$helpTemplate = $helpTemplate_lang ? $helpTemplate_lang :! !
! !
!
$this->getNewsSubpart($helpTemplate, '###TEMPLATE_DEFAULT###');! !
! !
!
// Markers and substitution:! !
! !
!
$markerArray['###CODE###'] = $this->theCode;! !
! !
!
$markerArray['###EXTPATH###'] = $GLOBALS['TYPO3_LOADED_EXT']['tt_news']['siteRelPath'];! !
! !
!
$content .= $this->displayFEHelp();! !
! !
}! !
! !
break;! !
!
}! !
}! !
if($noCode) {! !
!
$content .= $this->displayFEHelp();! !
}! !
return $content;!
}
!
/**! * Init Function: here all the needed configuration values are stored in class variables..! *! * @param!
array! !
$conf : configuration array from TS! * @return!
void! */!
function init($conf) {! !
$this->conf = $conf; //store configuration! !
$this->pi_loadLL(); // Loading language-labels! !
$this->pi_setPiVarDefaults(); // Set default piVars from TS! !
$this->pi_initPIflexForm(); // Init FlexForm configuration for plugin! !
$this->enableFields = $this->cObj->enableFields('tt_news');! !
$this->tt_news_uid = intval($this->piVars['tt_news']); // Get the submitted uid of a news (if any)
! !
if (!isset($this->conf['compatVersion']) || !preg_match('/^\d+\.\d+\.\d+$/', $this->conf['compatVersion'])) {! !
!
$this->conf['compatVersion'] = $this->getCurrentVersion();! !
}
! !
if (t3lib_extMgm::isLoaded('version')) {! !
!
$this->versioningEnabled = true;! !
}! !
// load available syslanguages! !
$this->initLanguages();! !
// sys_language_mode defines what to do if the requested translation is not found! !
$this->sys_language_mode = $this->conf['sys_language_mode']?$this->conf['sys_language_mode'] : $GLOBALS['TSFE']->sys_language_mode;
! !
// "CODE" decides what is rendered: codes can be set by TS or FF with priority on FF! !
$code = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'what_to_display', 'sDEF');! !
$this->config['code'] = $code ? $code : $this->cObj->stdWrap($this->conf['code'], $this->conf['code.']);
! !
// initialize category vars! !
$this->initCategoryVars();
! !
!
// get fieldnames from the tt_news db-table! !
$this->fieldNames = array_keys($GLOBALS['TYPO3_DB']->admin_get_fields('tt_news'));
! !
if ($this->conf['searchFieldList']) {! !
!
$searchFieldList = $this->validateFields($this->conf['searchFieldList']);! !
!
if ($searchFieldList) {! !
! !
$this->searchFieldList = $searchFieldList;! !
!
}! !
}! !
!
// Archive:! !
$this->config['archiveMode'] = trim($this->conf['archiveMode']) ; // month, quarter or year listing in AMENU! !
$this->config['archiveMode'] = $this->config['archiveMode']?$this->config['archiveMode']:'month';
! !
// arcExclusive : -1=only non-archived; 0=don't care; 1=only archived! !
$arcExclusive = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'archive', 'sDEF');! !
$this->arcExclusive = $arcExclusive?$arcExclusive:$this->conf['archive'];
! !
$this->config['datetimeDaysToArchive'] = intval($this->conf['datetimeDaysToArchive']);! !
$this->config['datetimeHoursToArchive'] = intval($this->conf['datetimeHoursToArchive']);! !
$this->config['datetimeMinutesToArchive'] = intval($this->conf['datetimeMinutesToArchive']);
! !
if ($this->conf['useHRDates']) {! !
!
$this->convertDates();! !
}
! !
// list of pages where news records will be taken from! !
if (!$this->conf['dontUsePidList']) {! !
!
$this->initPidList();! !
}
! !
// itemLinkTarget is only used for categoryLinkMode 3 (catselector) in framesets! !
$this->config['itemLinkTarget'] = trim($this->conf['itemLinkTarget']);! !
// id of the page where the search results should be displayed! !
$this->config['searchPid'] = intval($this->conf['searchPid']);
! !
// pages in Single view will be divided by this token! !
$this->config['pageBreakToken'] = trim($this->conf['pageBreakToken'])?trim($this->conf['pageBreakToken']):'<---newpage--->';
! !
$this->config['singleViewPointerName'] = trim($this->conf['singleViewPointerName'])?trim($this->conf['singleViewPointerName']):'sViewPointer';
! !
$maxWordsInSingleView = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'maxWordsInSingleView', 's_misc'));! !
$maxWordsInSingleView = $maxWordsInSingleView?$maxWordsInSingleView:intval($this->conf['maxWordsInSingleView']);! !
$this->config['maxWordsInSingleView'] = $maxWordsInSingleView?$maxWordsInSingleView:0;! !
$this->config['useMultiPageSingleView'] = $maxWordsInSingleView>1?1:$this->conf['useMultiPageSingleView'];
! !
// pid of the page with the single view. the old var PIDitemDisplay is still processed if no other value is found! !
$singlePid = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'PIDitemDisplay', 's_misc');! !
$singlePid = $singlePid?$singlePid:intval($this->cObj->stdWrap($this->conf['singlePid'],$this->conf['singlePid.']));! !
$this->config['singlePid'] = $singlePid ? $singlePid:intval($this->conf['PIDitemDisplay']);
! !
// pid to return to when leaving single view! !
$backPid = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'backPid', 's_misc'));! !
$backPid = $backPid?$backPid:intval($this->conf['backPid']);! !
$backPid = $backPid?$backPid:intval($this->piVars['backPid']);! !
$backPid = $backPid?$backPid:$GLOBALS['TSFE']->id ;! !
$this->config['backPid'] = $backPid;
! !
// max items per page! !
$FFlimit = t3lib_div::intInRange($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listLimit', 's_misc'), 0, 1000);
! !
$limit = t3lib_div::intInRange($this->cObj->stdWrap($this->conf['limit'],$this->conf['limit.']), 0, 1000);! !
$limit = $limit?$limit:!
50;! !
$this->config['limit'] = $FFlimit?$FFlimit:!
$limit;
! !
$latestLimit = t3lib_div::intInRange($this->cObj->stdWrap($this->conf['latestLimit'],$this->conf['latestLimit.']), 0, 1000);! !
$latestLimit = $latestLimit?$latestLimit:10;! !
$this->config['latestLimit'] = $FFlimit?$FFlimit:$latestLimit;
! !
// orderBy and groupBy statements for the list Query! !
$orderBy = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listOrderBy', 'sDEF');! !
$orderByTS = trim($this->conf['listOrderBy']);! !
$orderBy = $orderBy?$orderBy:$orderByTS;! !
$this->config['orderBy'] = $orderBy;
! !
if ($orderBy) {! !
!
$ascDesc = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'ascDesc', 'sDEF');! !
!
$this->config['ascDesc'] = $ascDesc;! !
!
if ($this->config['ascDesc']) {! !
! !
// remove ASC/DESC from 'orderBy' if it is already set from TS! !
! !
$this->config['orderBy'] = preg_replace('/( DESC| ASC)\b/i','',$this->config['orderBy']);! !
!
}! !
}! !
$this->config['groupBy'] = trim($this->conf['listGroupBy']);
! !
// if this is set, the first image is handled as preview image, which is only shown in list view! !
$fImgPreview = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'firstImageIsPreview', 's_misc');! !
$this->config['firstImageIsPreview'] = $fImgPreview?$fImgPreview : $this->conf['firstImageIsPreview'];! !
$forcefImgPreview = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'forceFirstImageIsPreview', 's_misc');! !
$this->config['forceFirstImageIsPreview'] = $forcefImgPreview?$fImgPreview : $this->conf['forceFirstImageIsPreview'];
! !
// List start id! !
$listStartId = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listStartId', 's_misc'));! !
$this->config['listStartId'] = $listStartId?$listStartId:intval($this->conf['listStartId']);! !
// supress pagebrowser! !
$noPageBrowser = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'noPageBrowser', 's_misc');! !
$this->config['noPageBrowser'] = $noPageBrowser?$noPageBrowser:!
$this->conf['noPageBrowser'];
! !
// image sizes given from FlexForms! !
$this->config['FFimgH'] = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'imageMaxHeight', 's_template'));! !
$this->config['FFimgW'] = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'imageMaxWidth', 's_template'));
! !
// Get number of alternative Layouts (loop layout in LATEST and LIST view) default is 2:! !
$altLayouts = intval($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'alternatingLayouts', 's_template'));! !
$altLayouts = $altLayouts?$altLayouts:intval($this->conf['alternatingLayouts']);! !
$this->alternatingLayouts = $altLayouts?$altLayouts:2;
! !
// Get cropping lenght! !
$this->config['croppingLenght'] = trim($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'croppingLenght', 's_template'));
! !
$this->initTemplate();
! !
// Configure caching! !
$this->allowCaching = $this->conf['allowCaching']?1:0;! !
if (!$this->allowCaching) {! !
!
$GLOBALS['TSFE']->set_no_cache();! !
}
! !
// get siteUrl for links in rss feeds. the 'dontInsert' option seems to be needed in some configurations depending on the baseUrl setting! !
if (!$this->conf['displayXML.']['dontInsertSiteUrl']) {! !
!
$this->config['siteUrl'] = t3lib_div::getIndpEnv('TYPO3_SITE_URL');! !
}!
}
!
/**! * generates the News archive menu! *! * @return!
string! !
html code of the archive menu! */!
function newsArchiveMenu() {
! !
$this->arcExclusive = 1;! !
$selectConf = $this->getSelectConf('', 1);! !
// Finding maximum and minimum values:! !
$selectConf['selectFields'] = 'max(tt_news.datetime) as maxval, min(tt_news.datetime) as minval';
! !
$res = $this->exec_getQuery('tt_news', $selectConf);
! !
$row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);! !
if ($row['minval'] || $row['maxval']) {! !
!
// if ($row['minval']) {! !
!
$dateArr = array();! !
!
$arcMode = $this->config['archiveMode'];! !
!
$c = 0;! !
!
do {! !
! !
switch ($arcMode) {! !
! !
!
case 'month':! !
! !
!
$theDate = mktime (0, 0, 0, date('m', $row['minval']) + $c, 1, date('Y', $row['minval']));! !
! !
!
break;! !
! !
!
case 'quarter':! !
! !
!
$theDate = mktime (0, 0, 0, floor(date('m', $row['minval']) / 3) + 1 + (3 * $c), 1, date('Y', $row['minval']));! !
! !
!
break;! !
! !
!
case 'year':! !
! !
!
$theDate = mktime (0, 0, 0, 1, 1, date('Y', $row['minval']) + $c);! !
! !
!
break;! !
! !
}! !
! !
$dateArr[] = $theDate;! !
! !
$c++;! !
! !
if ($c > 1000) break;! !
!
}! !
!
while ($theDate < $GLOBALS['SIM_EXEC_TIME']);
! !
!
reset($dateArr);! !
!
$periodAccum = array();
! !
!
$selectConf2['where'] = $selectConf['where'];! !
!
while (list($k, $v) = each($dateArr)) {! !
! !
if (!isset($dateArr[$k + 1])) {! !
! !
!
break;! !
! !
}
! !
! !
$periodInfo = array();! !
! !
$periodInfo['start'] = $dateArr[$k];! !
! !
$periodInfo['stop'] = $dateArr[$k + 1]-1;! !
! !
$periodInfo['HRstart'] = date('d-m-Y', $periodInfo['start']);! !
! !
$periodInfo['HRstop'] = date('d-m-Y', $periodInfo['stop']);! !
! !
$periodInfo['quarter'] = floor(date('m', $dateArr[$k]) / 3) + 1;! !
! !
// execute a query to count the archive periods! !
! !
$selectConf['selectFields'] = 'count(distinct(tt_news.uid))';! !
! !
$selectConf['where'] = $selectConf2['where'] . ' AND tt_news.datetime>=' . $periodInfo['start'] . ' AND tt_news.datetime<' . $periodInfo['stop'];
! !
! !
$res = $this->exec_getQuery('tt_news', $selectConf);
! !
! !
$row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);! !
! !
$periodInfo['count'] = $row[0];
! !
! !
if (!$this->conf['archiveMenuNoEmpty'] || $periodInfo['count']) {! !
! !
!
$periodAccum[] = $periodInfo;! !
! !
}! !
!
}
! !
!
// get template subpart! !
!
$t['total'] = $this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_ARCHIVE###'));! !
!
$t['item'] = $this->getLayouts($t['total'], $this->alternatingLayouts, 'MENUITEM');! !
!
$cc = 0;
! !
!
$veryLocal_cObj = t3lib_div::makeInstance('tslib_cObj');! !
!
// reverse amenu order if 'reverseAMenu' is given! !
!
if ($this->conf['reverseAMenu']) {! !
! !
arsort($periodAccum);! !
!
}
! !
!
$archiveLink = $this->conf['archiveTypoLink.']['parameter'];! !
!
$this->conf['parent.']['addParams'] = $this->conf['archiveTypoLink.']['addParams'];! !
!
reset($periodAccum);! !
!
$itemsOutArr = array();! !
!
while (list(, $pArr) = each($periodAccum)) {! !
! !
// Print Item Title! !
! !
$wrappedSubpartArray = array();
! !
! !
if (!$this->conf['disableCategoriesInAmenuLinks']) {! !
! !
!
if ($this->config['catSelection'] && $this->config['amenuWithCatSelector']) {! !
! !
! !
// use the catSelection from GPvars only if 'amenuWithCatSelector' is given.! !
! !
! !
$amenuLinkCat = $this->config['catSelection'];! !
! !
!
} else {! !
! !
! !
$amenuLinkCat = $this->catExclusive;! !
! !
!
}! !
! !
}
! !
! !
if ($this->conf['useHRDates']) {! !
! !
!
$year = date('Y',$pArr['start']);! !
! !
!
$month = date('m',$pArr['start']);! !
! !
!
if ($arcMode == 'year') {! !
! !
! !
$archLinkArr = $this->pi_linkTP_keepPIvars('|', array('cat' => ($amenuLinkCat?$amenuLinkCat:null), 'year' => $year), $this->allowCaching, 1, ($archiveLink?$archiveLink:$GLOBALS['TSFE']->id));! !
! !
!
} else {! !
! !
! !
$archLinkArr = $this->pi_linkTP_keepPIvars('|', array('cat' => ($amenuLinkCat?$amenuLinkCat:null), 'year' => $year, 'month' => $month), $this->allowCaching, 1, ($archiveLink?$archiveLink:$GLOBALS['TSFE']->id));! !
! !
!
}! !
! !
!
$wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $archLinkArr);! !
! !
} else {! !
! !
!
$wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $this->pi_linkTP_keepPIvars('|', array('cat' => ($amenuLinkCat?$amenuLinkCat:null), 'pS' => $pArr['start'], 'pL' => ($pArr['stop'] - $pArr['start']), 'arc' => 1), $this->allowCaching, 1, ($archiveLink?$archiveLink:$GLOBALS['TSFE']->id)));! !
! !
}
! !
! !
$markerArray = array();! !
! !
$veryLocal_cObj->start($pArr, '');! !
! !
$markerArray['###ARCHIVE_TITLE###'] = $veryLocal_cObj->cObjGetSingle($this->conf['archiveTitleCObject'], $this->conf['archiveTitleCObject.'], 'archiveTitle');! !
! !
$markerArray['###ARCHIVE_COUNT###'] = $pArr['count'];! !
! !
$markerArray['###ARCHIVE_ITEMS###'] = $this->pi_getLL('archiveItems');
! !
! !
// fill the generated data to an array to pass it to a userfuction as a single variable! !
! !
$itemsOutArr[] = array('html' => $this->cObj->substituteMarkerArrayCached($t['item'][($cc % count($t['item']))], $markerArray, array(), $wrappedSubpartArray), 'data' => $pArr);! !
! !
$cc++;! !
!
}! !
!
// Pass to user defined function! !
!
if ($this->conf['newsAmenuUserFunc']) {! !
! !
$itemsOutArr = $this->userProcess('newsAmenuUserFunc', $itemsOutArr);! !
!
}
! !
!
foreach ($itemsOutArr as $itemHtml) {! !
! !
$tmpItemsArr[] = $itemHtml['html'];! !
!
}
! !
!
if (is_array($tmpItemsArr)) {! !
! !
$itemsOut = implode('', $tmpItemsArr);! !
!
}
! !
!
// Reset:! !
!
$subpartArray = array();! !
!
$wrappedSubpartArray = array();! !
!
$markerArray = array();! !
!
$markerArray['###ARCHIVE_HEADER###'] = $this->local_cObj->stdWrap($this->pi_getLL('archiveHeader'), $this->conf['archiveHeader_stdWrap.']);! !
!
// Set content! !
!
$subpartArray['###CONTENT###'] = $itemsOut;! !
!
$content = $this->cObj->substituteMarkerArrayCached($t['total'], $markerArray, $subpartArray, $wrappedSubpartArray);! !
} else {! !
!
// if nothing is found in the archive display the TEMPLATE_ARCHIVE_NOITEMS message! !
!
$markerArray['###ARCHIVE_HEADER###'] = $this->local_cObj->stdWrap($this->pi_getLL('archiveHeader'), $this->conf['archiveHeader_stdWrap.']);! !
!
$markerArray['###ARCHIVE_EMPTY_MSG###'] = $this->local_cObj->stdWrap($this->pi_getLL('archiveEmptyMsg'), $this->conf['archiveEmptyMsg_stdWrap.']);! !
!
$noItemsMsg = $this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_ARCHIVE_NOITEMS###'));! !
!
$content = $this->cObj->substituteMarkerArrayCached($noItemsMsg, $markerArray);! !
}
! !
return $content;!
}
!
/**! * Displays the "single view" of a news article. Is also used when displaying single news records with the "insert records" content element.! *! * @return!
string! !
html-code for the "single view"! */!
function displaySingle() {! !
$singleWhere = 'tt_news.uid=' . intval($this->tt_news_uid);! !
$singleWhere .= ' AND type NOT IN(1,2)' . $this->enableFields; // only real news -> type=0
! !
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(! !
!
'*',! !
!
'tt_news',! !
!
$singleWhere);
! !
$row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);! !
// get the translated record if the content language is not the default language! !
if ($GLOBALS['TSFE']->sys_language_content) {! !
!
$OLmode = ($this->sys_language_mode == 'strict'?'hideNonTranslated':'');! !
!
$row = $GLOBALS['TSFE']->sys_page->getRecordOverlay('tt_news', $row, $GLOBALS['TSFE']->sys_language_content, $OLmode);! !
}! !
if ($this->versioningEnabled) {! !
!
// get workspaces Overlay! !
!
$GLOBALS['TSFE']->sys_page->versionOL('tt_news',$row);! !
!
// fix pid for record from workspace! !
!
$GLOBALS['TSFE']->sys_page->fixVersioningPid('tt_news',$row);! !
}! !
$GLOBALS['TSFE']->displayedNews[]=$row['uid'];
! !
if (is_array($row) && ($row['pid'] > 0 || $this->vPrev)) { // never display versions of a news record (having pid=-1) for normal website users! !
! !
// Get the subpart code! !
!
if ($this->conf['displayCurrentRecord']) {! !
! !
$item = trim($this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_SINGLE_RECORDINSERT###'), $row));! !
!
}! !
!
if (!$item) {! !
! !
$item = $this->getNewsSubpart($this->templateCode, $this->spMarker('###TEMPLATE_SINGLE###'), $row);! !
!
}! !
! !
// reset marker array! !
!
$wrappedSubpartArray = array();! !
! !
// build the backToList link! !
!
if ($this->conf['useHRDates']) {! !
! !
$pointerName = 'pointer';! !
! !
$wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $this->pi_linkTP_keepPIvars('|', array(! !
! !
!
'tt_news' => null,! !
! !
!
'backPid' => null,! !
! !
!
$this->config['singleViewPointerName'] => null,! !
! !
!
'pS' => null,! !
! !
!
'pL' => null), $this->allowCaching, ($this->conf['dontUseBackPid']?1:0), $this->config['backPid']));! !
!
} else {! !
! !
$wrappedSubpartArray['###LINK_ITEM###'] = explode('|', $this->pi_linkTP_keepPIvars('|', array(! !
! !
!
'tt_news' => null,! !
! !
!
'backPid' => null,! !
! !
!
$this->config['singleViewPointerName'] => null), $this->allowCaching, ($this->conf['dontUseBackPid']?1:0), $this->config['backPid']));! !
!
}! !
! !
// set the title of the single view page to the title of the news record! !
!
if ($this->conf['substitutePagetitle']) {! !
! !
$GLOBALS['TSFE']->page['title'] = $row['title'];! !
! !
// set pagetitle for indexed search to news title! !
! !
$GLOBALS['TSFE']->indexedDocTitle = $row['title'];! !
!
}! !
!
if ($this->conf['displaySingle.']['catOrderBy']) {! !
! !
$this->config['catOrderBy'] = $this->conf['displaySingle.']['catOrderBy'];! !
!
}! !
!
$markerArray = $this->getItemMarkerArray($row, 'displaySingle');! !
!
// Substitute! !
!
$content = $this->cObj->substituteMarkerArrayCached($item, $markerArray, array(), $wrappedSubpartArray);! !
} elseif ($this->sys_language_mode == 'strict' && $this->tt_news_uid && $GLOBALS['TSFE']->sys_language_content) { // not existing translation! !
!
$noTranslMsg = $this->local_cObj->stdWrap($this->pi_getLL('noTranslMsg'), $this->conf['noNewsIdMsg_stdWrap.']);! !
!
$content = $noTranslMsg;! !
} elseif ($row['pid'] < 0) { // a non-public version of a record was requested! !
!
$nonPlublicVersion = $this->local_cObj->stdWrap($this->pi_getLL('nonPlublicVersionMsg'), $this->conf['nonPlublicVersionMsg_stdWrap.']);! !
!
$content = $nonPlublicVersion;! !
} else { // if singleview is shown with no tt_news uid given from GETvars (&tx_ttnews[tt_news]=) an error message is displayed.! !
!
$noNewsIdMsg = $this->local_cObj->stdWrap($this->pi_getLL('noNewsIdMsg'), $this->conf['noNewsIdMsg_stdWrap.']);! !
!
$content = $noNewsIdMsg;! !
}! !
return $content;!
}
!
/**! * Displays the "versioning preview".! * The functions checks:! * - if the extension "version" is loaded! * - if a BE_user is logged in! * - the plausibility of the requested "version preview".! * If this is all OK, "displaySingle()" is executed to display the "versioning preview".! *! * @return!
string! !
html code for the "versioning preview"! */!
function displayVersionPreview () {! !
if ($this->versioningEnabled) {! !
!
$vPrev = t3lib_div::_GP('ADMCMD_vPrev');! !
!
if ($this->piVars['ADMCMD_vPrev']) {! !
! !
$piADMCMD = unserialize(rawurldecode($this->piVars['ADMCMD_vPrev']));! !
!
}! !
!
if ((is_array($vPrev) || is_array($piADMCMD)) && is_object($GLOBALS['BE_USER'])) { // check if ADMCMD_vPrev is set and if a BE_user is logged in. $this->piVars['ADMCMD_vPrev'] is needed for previewing a "single view with pagebrowser"! !
! !
if (!is_array($vPrev)) { $vPrev = $piADMCMD; }! !
! !
list($table,$t3ver_oid) = explode(':',key($vPrev));! !
! !
if ($table == 'tt_news') {! !
! !
!
if ($testrec = $this->pi_getRecord('tt_news', intval($vPrev[key($vPrev)]))) { // check if record exists before doing anything! !
! !
! !
if ($testrec['t3ver_oid'] == intval($t3ver_oid) && $testrec['pid']==-1) { // check if requested t3ver_oid is the t3ver_oid of the requested tt_news record, and if the pid of the record is -1 (=non-plublic version)! !
! !
! !
!
$GLOBALS['TSFE']->set_no_cache(); // version preview will never be cached! !
! !
! !
! !
// make version preview message with a link to the public version of hte record which is previewed! !
! !
! !
!
$vPrevHeader = $this->local_cObj->stdWrap(! !
! !
! !
! !
$this->pi_getLL('versionPreviewMessage').! !
! !
! !
! !
!
$this->local_cObj->typolink(! !
! !
! !
! !
! !
$this->local_cObj->stdWrap(! !
! !
! !
! !
! !
!
$this->pi_getLL('versionPreviewMessageLinkToOriginal'),$this->conf['versionPreviewMessageLinkToOriginal_stdWrap.']! !
! !
! !
! !
! !
),! !
! !
! !
! !
! !
array(! !
! !
! !
! !
! !
!
'parameter' => $this->config['singlePid'].' _blank',! !
! !
! !
! !
! !
!
'additionalParams' => '&tx_ttnews[tt_news]='.$t3ver_oid,! !
! !
! !
! !
! !
!
'no_cache' => 1! !
! !
! !
! !
! !
)! !
! !
! !
! !
!
),! !
! !
! !
! !
$this->conf['versionPreviewMessage_stdWrap.']! !
! !
! !
!
);! !
! !
! !
!
$this->tt_news_uid = intval($vPrev[key($vPrev)]);! !
! !
! !
!
$this->piVars['tt_news'] = $this->tt_news_uid;! !
! !
! !
!
$this->piVars['ADMCMD_vPrev'] = rawurlencode(serialize(array($table.':'.$t3ver_oid => $this->tt_news_uid)));! !
! !
! !
!
$this->theCode = 'SINGLE';! !
! !
! !
!
$this->vPrev = true;! !
! !
! !
!
$content = $vPrevHeader.$this->displaySingle();! !
! !
! !
} else { // error: t3ver_oid mismatch! !
! !
! !
!
$GLOBALS['TT']->setTSlogMessage('tt_news: ERROR! The "t3ver_oid" of requested tt_news record and the "t3ver_oid" from GPvars doesn\'t match.');! !
! !
! !
}! !
! !
!
}! !
! !
}! !
!
}! !
}! !
return $content;!
}
control flow
business logic
CRUD data
other , eg. config
render output
control flow
business logic
CRUD data
other , eg. config
render output
aggregate
generalize
control flow
business logic
CRUD data
other , eg. config
render output
partition
useExtbase & Fluid
control flow
business logic
CRUD data
other , eg. config
render output
Controller
Domain Model
Domain Repository
other , eg. config
View
Blog features
administrate blogs, blog posts and blog commentslist all available blogslist all blog posts of a bloglist all comments of a blog postallow users to post new comments
Blog features
administrate blogs, blog posts and blog commentslist all available blogslist all blog posts of a bloglist all comments of a blog postallow users to post new comments
Blog
Blog features
administrate blogs, blog posts and blog commentslist all available blogslist all blog posts of a bloglist all comments of a blog postallow users to post new comments
Blog
Post
Comment Tag
TYPO3
tx_blog_piTYPO3
userFunc
1tx_blog
tslib_piBase
tx_blog_piexec_SELECTgetRows
TYPO3
userFunc
1tx_blog
2
tslib_piBase
Database
tx_blog_piexec_SELECTgetRows
TYPO3
userFunc
1tx_blog
rows as array
2
3
tslib_piBase
Database
tx_blog_piexec_SELECTgetRows
TYPO3
userFunc
1tx_blog
rows as array
2
3
HTML
4
tslib_piBase
Database
Control !ow
public function main($content, $conf) {! $this->conf = $conf;! $this->pi_setPiVarDefaults();! $this->pi_loadLL();
! if ($this->piVars['postUid']) {! ! if ($this->piVars['newComment']) {! ! ! $this->storeNewComment();! ! }! ! $content = $this->renderPost();! } elseif ($this->piVars['blogUid']) {! ! $content = $this->renderBlog();! } else {! ! $content = $this->renderListOfBlogs();! }! return $this->pi_wrapInBaseClass($content);}
Task 1: Output a listing of blogs
protected function renderListOfBlogs() {! $blogs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! '*',! ! 'tx_blogexample_blog',! ! 'sys_language_uid=' . $GLOBALS['TSFE']->sys_language_uid
. $this->cObj->enableFields('tx_blogexample_blog'),! ! '',! ! 'date'! ! );
! $template = $this->cObj->fileResource($this->conf['template']);! $blogElementSubpart = $this->cObj->getSubpart($template, '###SUBPART_BLOGELEMENT###');
! foreach ($blogs as $blog) {! ! $linkParameters = array('blogUid' => $blog['uid']);! ! $markers = array(! ! ! '###BLOG_NAME###' => $blog['name'],! ! ! '###BLOG_LOGO###' => $this->cImage('uploads/tx_blog/' . $blog['logo']),! ! ! '###BLOG_DESCRIPTION###' => $this->pi_RTEcssText($blog['description']),! ! ! '###BLOG_MORELINK###' => $this->pi_linkTP('show blog', $linkParameters, true),! ! );! ! $blogElements.= $this->cObj->substituteMarkerArray($blogElementSubpart, $markers);! }! return $content;}
Task 1: Output a listing of blogs
protected function renderListOfBlogs() {! $blogs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! '*',! ! 'tx_blogexample_blog',! ! 'sys_language_uid=' . $GLOBALS['TSFE']->sys_language_uid
. $this->cObj->enableFields('tx_blogexample_blog'),! ! '',! ! 'date'! ! );
! $template = $this->cObj->fileResource($this->conf['template']);! $blogElementSubpart = $this->cObj->getSubpart($template, '###SUBPART_BLOGELEMENT###');
! foreach ($blogs as $blog) {! ! $linkParameters = array('blogUid' => $blog['uid']);! ! $markers = array(! ! ! '###BLOG_NAME###' => $blog['name'],! ! ! '###BLOG_LOGO###' => $this->cImage('uploads/tx_blog/' . $blog['logo']),! ! ! '###BLOG_DESCRIPTION###' => $this->pi_RTEcssText($blog['description']),! ! ! '###BLOG_MORELINK###' => $this->pi_linkTP('show blog', $linkParameters, true),! ! );! ! $blogElements.= $this->cObj->substituteMarkerArray($blogElementSubpart, $markers);! }! return $content;}
Task 1: Output a listing of blogs
<!-- ###SUBPART_BLOGELEMENT### begin --><div class="blog element">! ###BLOG_NAME###! ###BLOG_LOGO###! ###BLOG_DESCRIPTION###! ###BLOG_MORELINK###</div><!-- ###SUBPART_BLOGELEMENT### end -->
Task 2: Display a single post with its comments
protected function renderPost() {! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! '*',! ! 'tx_blogexample_comment',! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
. $GLOBALS['TSFE']->sys_language_uid! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
. $this->cObj->enableFields('tx_blogexample_comment'),! ! '',! ! 'date DESC'! );
// fill marker arrays and substitute in template// return content}
Task 3: Add a new comment to a blog post
the whole plugin is cached („USER“)dynamic user input won‘t outputted instantlyde"ne uncached behavior in TypoScript
[globalVar = _POST:tx_blogexample_pi1|newComment = 1]! plugin.tx_blogexample_pi1 = USER_INT[globals]
Task 3: Add a new comment to a blog post
protected function storeNewComment() {! $fields = array(! ! 'post_uid' => $this->piVars['postUid'],! ! 'post_table' => 'tx_blogexample_post',! ! 'date' => time(),! ! 'author' => $this->piVars['author'],! ! 'email' => $this->piVars['email'],! ! 'content' => $this->piVars['content'],! );
! $GLOBALS['TYPO3_DB']->exec_INSERTquery(! ! 'tx_blogexample_comment', $fields! );}
Security: SQL injections
protected function renderPost() {! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! '*',! ! 'tx_blogexample_comment',! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
. $GLOBALS['TSFE']->sys_language_uid! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
. $this->cObj->enableFields('tx_blogexample_comment'),! ! '',! ! 'date DESC'! );[...]
Security: SQL injections
protected function renderPost() {! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! '*',! ! 'tx_blogexample_comment',! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
. $GLOBALS['TSFE']->sys_language_uid! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
. $this->cObj->enableFields('tx_blogexample_comment'),! ! '',! ! 'date DESC'! );[...]
http://www.example.com/index.php&id=99&postUid=1
Security: SQL injections
protected function renderPost() {! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! '*',! ! 'tx_blogexample_comment',! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
. $GLOBALS['TSFE']->sys_language_uid! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
. $this->cObj->enableFields('tx_blogexample_comment'),! ! '',! ! 'date DESC'! );[...]
http://www.example.com/index.php&id=99&postUid=1
SELECT * FROM tx_blog_comment WHERE post_uid=1;
Security: SQL injections
protected function renderPost() {! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! '*',! ! 'tx_blogexample_comment',! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
. $GLOBALS['TSFE']->sys_language_uid! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
. $this->cObj->enableFields('tx_blogexample_comment'),! ! '',! ! 'date DESC'! );[...]
http://www.example.com/index.php&id=99&postUid=1
SELECT * FROM tx_blog_comment WHERE post_uid=1;INSERT INTO be_users SET ...;SELECT * FROM tx_blog_comment WHERE 1=1 AND post_table="tx_blogexample_post"
; INSERT INTO be_users SET ...; SELECT * FROM tx_blog_comment WHERE 1=1
Security: SQL injections
protected function renderPost() {! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! '*',! ! 'tx_blogexample_comment',! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
. $GLOBALS['TSFE']->sys_language_uid! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
. $this->cObj->enableFields('tx_blogexample_comment'),! ! '',! ! 'date DESC'! );[...]
http://www.example.com/index.php&id=99&postUid=1
SELECT * FROM tx_blog_comment WHERE post_uid=1;INSERT INTO be_users SET ...;SELECT * FROM tx_blog_comment WHERE 1=1 AND post_table="tx_blogexample_post"
; INSERT INTO be_users SET ...; SELECT * FROM tx_blog_comment WHERE 1=1
Security: SQL injections
http://www.example.com/index.php&id=99&postUid=1
SELECT * FROM tx_blog_comment WHERE post_uid=1;INSERT INTO be_users SET ...;SELECT * FROM tx_blog_comment WHERE 1=1 AND post_table="tx_blogexample_post"
; INSERT INTO be_users SET ...; SELECT * FROM tx_blog_comment WHERE 1=1
protected function renderPost() {! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! '*',! ! 'tx_blogexample_comment',! ! 'deleted=0 AND hidden=0 AND sys_language_uid= . $GLOBALS['TSFE']->sys_language_uid! ! ! . ' AND post_uid=' . intval($this->piVars['postUid']) . ' AND post_table="tx_blogexample_post"' . $this->cObj->enableFields('tx_blogexample_comment'),! ! '',! ! 'date DESC'! );[...]
http://www.sxc.hu/photo/516864/
Extension buildingwith Extbase
TYPO3
ExtbaseDispatcherTYPO3
userFunc
1
ExtbaseDispatcher
Controller
Request
TYPO3
userFunc
12 BlogExample
ExtbaseDispatcher
Controller
Repository
Request
findByTitle('MyBlog')
TYPO3
Domain Model
userFunc
12
3
Blog
Post
Comment Tag
BlogExample
ExtbaseDispatcher
Controller
Repository
Request
findByTitle('MyBlog')
Blog
TYPO3
Domain Model
userFunc
12
3
4
Blog
Post
Comment Tag
BlogExample
ExtbaseDispatcher
Controller
Repository View
Request
findByTitle('MyBlog')
Blog
assign(Blog)
TYPO3
Domain Model
render()
userFunc
12
3
4
5
Blog
Post
Comment Tag
BlogExample
ExtbaseDispatcher
Controller
Repository View
Request
findByTitle('MyBlog')
Response
Blog
assign(Blog)
Response
TYPO3
Domain Model
HTML
render()
userFunc
12
3
4
5
6
Blog
Post
Comment Tag
BlogExample
ExtbaseDispatcher
Controller
Repository View
Request
findByTitle('MyBlog')
Response
Blog
assign(Blog)
Response
TYPO3
Domain Model
HTML
render()
userFunc
12
3
4
5
6
Blog
Post
Comment Tag
BlogExample
View
Controller
Model
Blog
Post
Comment Tag
Model
/** * A blog * * @version $Id:$ * @copyright Copyright belongs to the respective authors * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2 * @scope prototype * @entity */class Tx_BlogExample_Domain_Model_Blog extends Tx_Extbase_DomainObject_AbstractEntity {
! /**! * The blog's title.! *! * @var string! * @validate Text, StringLength(minimum = 1, maximum = 80)! * @identity! */! protected $title = '';
! /**! * A short description of the blog! *! * @var string! * @validate Text, StringLength(maximum = 150)! */! protected $description = '';
! /**! * The posts contained in this blog! *! * @var Tx_Extbase_Persistence_ObjectStorage! * @lazy! */! protected $posts;
! /**! * The blog's administrator! *! * @var Tx_BlogExample_Domain_Model_Administrator! */! protected $administrator;
! /**! * Constructs a new Blog! *! */! public function __construct() {! ! $this->posts = new Tx_Extbase_Persistence_ObjectStorage();! }
! /**! * Sets this blog's title! *! * @param string $title The blog's title! * @return void! */! public function setTitle($title) {! ! $this->title = $title;! }
! /**! * Returns the blog's title! *! * @return string The blog's title! */! public function getTitle() {! ! return $this->title;! }
! /**! * Sets the description for the blog! *! * @param string $description! * @return void! */! public function setDescription($description) {! ! $this->description = $description;! }
! /**! * Returns the description! *! * @return string! */! public function getDescription() {! ! return $this->description;! }
! /**! * Adds a post to this blog! *! * @param Tx_BlogExample_Domain_Model_Post $post! * @return void! */! public function addPost(Tx_BlogExample_Domain_Model_Post $post) {! ! $this->posts->attach($post);! }
! /**! * Remove a post from this blog! *! * @param Tx_BlogExample_Domain_Model_Post $postToRemove The post to be removed! * @return void! */! public function removePost(Tx_BlogExample_Domain_Model_Post $postToRemove) {! ! $this->posts->detach($postToRemove);! }
! /**! * Remove all posts from this blog! *! * @return void! */! public function removeAllPosts() {! ! $this->posts = new Tx_Extbase_Persistence_ObjectStorage();! }
! /**! * Returns all posts in this blog! *! * @return Tx_Extbase_Persistence_ObjectStorage! */! public function getPosts() {! ! return $this->posts;! }
! /**! * Sets the administrator value! *! * @param Tx_BlogExample_Domain_Model_Administrator $administrator The Administrator of this Blog! * @return void! */! public function setAdministrator(Tx_BlogExample_Domain_Model_Administrator $administrator) {! ! $this->administrator = $administrator;! }
! /**! * Returns the administrator value! *! * @return Tx_BlogExample_Domain_Model_Administrator! */! public function getAdministrator() {! ! return $this->administrator;! }
}
/** * A blog * * @version $Id:$ * @copyright Copyright belongs to the respective authors * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2 * @scope prototype * @entity */class Tx_BlogExample_Domain_Model_Blog extends Tx_Extbase_DomainObject_AbstractEntity {
! /**! * The blog's title.! *! * @var string! * @validate Text, StringLength(minimum = 1, maximum = 80)! * @identity! */! protected $title = '';
! /**! * A short description of the blog! *! * @var string! * @validate Text, StringLength(maximum = 150)! */! protected $description = '';
! /**! * The posts contained in this blog! *! * @var Tx_Extbase_Persistence_ObjectStorage! * @lazy! */! protected $posts;
! /**! * The blog's administrator! *! * @var Tx_BlogExample_Domain_Model_Administrator! */! protected $administrator;
! /**! * Constructs a new Blog! *! */! public function __construct() {! ! $this->posts = new Tx_Extbase_Persistence_ObjectStorage();! }
! /**! * Sets this blog's title! *! * @param string $title The blog's title! * @return void! */! public function setTitle($title) {! ! $this->title = $title;! }
! /**! * Returns the blog's title! *! * @return string The blog's title! */! public function getTitle() {! ! return $this->title;! }
! /**! * Sets the description for the blog! *! * @param string $description! * @return void! */! public function setDescription($description) {! ! $this->description = $description;! }
! /**! * Returns the description! *! * @return string! */! public function getDescription() {! ! return $this->description;! }
! /**! * Adds a post to this blog! *! * @param Tx_BlogExample_Domain_Model_Post $post! * @return void! */! public function addPost(Tx_BlogExample_Domain_Model_Post $post) {! ! $this->posts->attach($post);! }
! /**! * Remove a post from this blog! *! * @param Tx_BlogExample_Domain_Model_Post $postToRemove The post to be removed! * @return void! */! public function removePost(Tx_BlogExample_Domain_Model_Post $postToRemove) {! ! $this->posts->detach($postToRemove);! }
! /**! * Remove all posts from this blog! *! * @return void! */! public function removeAllPosts() {! ! $this->posts = new Tx_Extbase_Persistence_ObjectStorage();! }
! /**! * Returns all posts in this blog! *! * @return Tx_Extbase_Persistence_ObjectStorage! */! public function getPosts() {! ! return $this->posts;! }
! /**! * Sets the administrator value! *! * @param Tx_BlogExample_Domain_Model_Administrator $administrator The Administrator of this Blog! * @return void! */! public function setAdministrator(Tx_BlogExample_Domain_Model_Administrator $administrator) {! ! $this->administrator = $administrator;! }
! /**! * Returns the administrator value! *! * @return Tx_BlogExample_Domain_Model_Administrator! */! public function getAdministrator() {! ! return $this->administrator;! }
}
/** * A blog * * @version $Id:$ * @copyright Copyright belongs to the respective authors * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2 * @scope prototype * @entity */class Tx_BlogExample_Domain_Model_Blog extends Tx_Extbase_DomainObject_AbstractEntity {
! /**! * The blog's title.! *! * @var string! * @validate Text, StringLength(minimum = 1, maximum = 80)! * @identity! */! protected $title = '';
! /**! * A short description of the blog! *! * @var string! * @validate Text, StringLength(maximum = 150)! */! protected $description = '';
! /**! * The posts contained in this blog! *! * @var Tx_Extbase_Persistence_ObjectStorage! * @lazy! */! protected $posts;
! /**! * The blog's administrator! *! * @var Tx_BlogExample_Domain_Model_Administrator! */! protected $administrator;
! /**! * Constructs a new Blog! *! */! public function __construct() {! ! $this->posts = new Tx_Extbase_Persistence_ObjectStorage();! }
! /**! * Sets this blog's title! *! * @param string $title The blog's title! * @return void! */! public function setTitle($title) {! ! $this->title = $title;! }
! /**! * Returns the blog's title! *! * @return string The blog's title! */! public function getTitle() {! ! return $this->title;! }
! /**! * Sets the description for the blog! *! * @param string $description! * @return void! */! public function setDescription($description) {! ! $this->description = $description;! }
! /**! * Returns the description! *! * @return string! */! public function getDescription() {! ! return $this->description;! }
! /**! * Adds a post to this blog! *! * @param Tx_BlogExample_Domain_Model_Post $post! * @return void! */! public function addPost(Tx_BlogExample_Domain_Model_Post $post) {! ! $this->posts->attach($post);! }
! /**! * Remove a post from this blog! *! * @param Tx_BlogExample_Domain_Model_Post $postToRemove The post to be removed! * @return void! */! public function removePost(Tx_BlogExample_Domain_Model_Post $postToRemove) {! ! $this->posts->detach($postToRemove);! }
! /**! * Remove all posts from this blog! *! * @return void! */! public function removeAllPosts() {! ! $this->posts = new Tx_Extbase_Persistence_ObjectStorage();! }
! /**! * Returns all posts in this blog! *! * @return Tx_Extbase_Persistence_ObjectStorage! */! public function getPosts() {! ! return $this->posts;! }
! /**! * Sets the administrator value! *! * @param Tx_BlogExample_Domain_Model_Administrator $administrator The Administrator of this Blog! * @return void! */! public function setAdministrator(Tx_BlogExample_Domain_Model_Administrator $administrator) {! ! $this->administrator = $administrator;! }
! /**! * Returns the administrator value! *! * @return Tx_BlogExample_Domain_Model_Administrator! */! public function getAdministrator() {! ! return $this->administrator;! }
}
/** * A blog post comment * * @package Blog * @subpackage Domain * @version $Id:$ * @copyright Copyright belongs to the respective authors * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2 * @scope prototype * @entity */class Tx_BlogExample_Domain_Model_Comment extends Tx_Extbase_DomainObject_AbstractEntity {
! /**! * @var DateTime! */! protected $date;
! /**! * @var string! * @validate Text, StringLength(minimum = 3, maximum = 80)! */! protected $author;
! /**! * @var string! * @validate EmailAddress! */! protected $email;
! /**! * @var string! * @validate Text, NotEmpty! */! protected $content;!
!
! /**! * Constructs this post! */! public function __construct() {! ! $this->date = new DateTime();! }
! /**! * Setter for date! *! * @param DateTime $date! * @return void! */! public function setDate(DateTime $date) {! ! $this->date = $date;! }
! /**! * Getter for date! *! * @return DateTime! */! public function getDate() {! ! return $this->date;! }
! /**! * Sets the author for this comment! *! * @param string $author! * @return void! */! public function setAuthor($author) {! ! $this->author = $author;! }
! /**! * Getter for author! *! * @return string! */! public function getAuthor() {! ! return $this->author;! }
! /**! * Sets the authors email for this comment! *! * @param string $email email of the author! * @return void! */! public function setEmail($email) {! ! $this->email = $email;! }
! /**! * Getter for authors email! *! * @return string! */! public function getEmail() {! ! return $this->email;! }
! /**! * Sets the content for this comment! *! * @param string $content! * @return void! */! public function setContent($content) {! ! $this->content = $content;! }
! /**! * Getter for content! *! * @return string! */! public function getContent() {! ! return $this->content;! }
! /**! * Returns this comment as a formatted string! *! * @return string! */! public function __toString() {! ! return $this->author . ' (' . $this->email . ') said on ' . $this->date->format('Y-m-d') . ':' . chr(10) .! ! ! $this->content . chr(10);! }}
/** * A blog post comment * * @package Blog * @subpackage Domain * @version $Id:$ * @copyright Copyright belongs to the respective authors * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2 * @scope prototype * @entity */class Tx_BlogExample_Domain_Model_Comment extends Tx_Extbase_DomainObject_AbstractEntity {
! /**! * @var DateTime! */! protected $date;
! /**! * @var string! * @validate Text, StringLength(minimum = 3, maximum = 80)! */! protected $author;
! /**! * @var string! * @validate EmailAddress! */! protected $email;
! /**! * @var string! * @validate Text, NotEmpty! */! protected $content;!
!
! /**! * Constructs this post! */! public function __construct() {! ! $this->date = new DateTime();! }
! /**! * Setter for date! *! * @param DateTime $date! * @return void! */! public function setDate(DateTime $date) {! ! $this->date = $date;! }
! /**! * Getter for date! *! * @return DateTime! */! public function getDate() {! ! return $this->date;! }
! /**! * Sets the author for this comment! *! * @param string $author! * @return void! */! public function setAuthor($author) {! ! $this->author = $author;! }
! /**! * Getter for author! *! * @return string! */! public function getAuthor() {! ! return $this->author;! }
! /**! * Sets the authors email for this comment! *! * @param string $email email of the author! * @return void! */! public function setEmail($email) {! ! $this->email = $email;! }
! /**! * Getter for authors email! *! * @return string! */! public function getEmail() {! ! return $this->email;! }
! /**! * Sets the content for this comment! *! * @param string $content! * @return void! */! public function setContent($content) {! ! $this->content = $content;! }
! /**! * Getter for content! *! * @return string! */! public function getContent() {! ! return $this->content;! }
! /**! * Returns this comment as a formatted string! *! * @return string! */! public function __toString() {! ! return $this->author . ' (' . $this->email . ') said on ' . $this->date->format('Y-m-d') . ':' . chr(10) .! ! ! $this->content . chr(10);! }}
and...
action
http://www.sxc.hu/photo/444174/
/** * The blog controller for the Blog package * * @version $Id:$ * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2 */class Tx_BlogExample_Controller_BlogController extends Tx_Extbase_MVC_Controller_ActionController {
! /**! * @var Tx_BlogExample_Domain_Model_BlogRepository! */! protected $blogRepository;
! /**! * Initializes the current action! *! * @return void! */! public function initializeAction() {! ! $this->blogRepository = t3lib_div::makeInstance('Tx_BlogExample_Domain_Repository_BlogRepository');! ! $this->postRepository = t3lib_div::makeInstance('Tx_BlogExample_Domain_Repository_PostRepository');! ! $this->administratorRepository = t3lib_div::makeInstance('Tx_BlogExample_Domain_Repository_AdministratorRepository');! }
! /**! * Index action for this controller. Displays a list of blogs.! *! * @return string The rendered view! */! public function indexAction() {! ! $this->view->assign('blogs', $this->blogRepository->findAll());! }
! /**! * Displays a form for creating a new blog! *! * @param Tx_BlogExample_Domain_Model_Blog $newBlog A fresh blog object taken as a basis for the rendering! * @return string An HTML form for creating a new blog! * @dontvalidate $newBlog! */! public function newAction(Tx_BlogExample_Domain_Model_Blog $newBlog = NULL) {! ! $this->view->assign('newBlog', $newBlog);! ! $this->view->assign('administrators', $this->administratorRepository->findAll());! }
! /**! * Creates a new blog! *! * @param Tx_BlogExample_Domain_Model_Blog $newBlog A fresh Blog object which has not yet been added to the repository! * @return void! */! public function createAction(Tx_BlogExample_Domain_Model_Blog $newBlog) {! ! $this->blogRepository->add($newBlog);! ! $this->pushFlashMessage('Your new blog was created.');! ! $this->redirect('index');! }
! /**! * Edits an existing blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog The blog to edit or the blog with updated properties! * @param Tx_BlogExample_Domain_Model_Blog $existingBlog The existing unmodified blog or NULL to use the blog! * @return string Form for editing the existing blog! * @validate $blog Raw! */! public function editAction(Tx_BlogExample_Domain_Model_Blog $blog, Tx_BlogExample_Domain_Model_Blog $existingBlog = NULL) {! ! if ($existingBlog === NULL) {! ! ! $existingBlog = $blog;! ! }! ! $this->view->assign('blog', $blog);! ! $this->view->assign('existingBlog', $existingBlog);! ! $this->view->assign('administrators', $this->administratorRepository->findAll());! }
! /**! * Updates an existing blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog A not yet persisted clone of the original blog containing the modifications! * @return void! */! public function updateAction(Tx_BlogExample_Domain_Model_Blog $blog) {! ! $this->blogRepository->update($blog);! ! $this->pushFlashMessage('Your blog has been updated.');! ! $this->redirect('index');! }
! /**! * Deletes an existing blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog The blog to delete! * @return void! */! public function deleteAction(Tx_BlogExample_Domain_Model_Blog $blog) {! ! $this->blogRepository->remove($blog);! ! $this->pushFlashMessage('Your blog has been removed.');! ! $this->redirect('index');! }
! /**! * Deletes an existing blog! *! * @return void! */! public function deleteAllAction() {! ! $blogs = $this->blogRepository->findAll();! ! foreach ($blogs as $blog) {! ! ! $this->blogRepository->remove($blog);! ! }! ! $this->redirect('index');! }
! /**! * Creates a several new blogs! *! * @return void! */! public function populateAction() {! ! $author = t3lib_div::makeInstance('Tx_BlogExample_Domain_Model_Person', 'Jochen', 'Rau', '[email protected]');! ! for ($blogNumber = 1; $blogNumber < 4; $blogNumber++) {! ! ! $blog = $this->getBlog($blogNumber, $author);! ! ! $this->blogRepository->add($blog);! ! }! ! $this->redirect('index');! }
! /**! * Returns a sample blog populated with generic data. It is also an example how to handle objects and repositories in general.! *! * @param int $blogNumber The number of the blog! * @param Tx_BlogExample_Domain_Model_Person $author The author of posts! * @return Tx_BlogExample_Domain_Model_Blog The blog object! */! private function getBlog($blogNumber, $author) {! ! $blog = new Tx_BlogExample_Domain_Model_Blog;! ! $blog->setTitle('Blog #' . $blogNumber);! ! $blog->setDescription('A blog about TYPO3 extension development.');
! ! $administrator = new Tx_BlogExample_Domain_Model_Administrator('foobar', '123455');! ! $administrator->setName('John Doe');! ! $administrator->setEmail('[email protected]');! ! $administrator->setUsername(''); // For security reasons! ! $administrator->setPassword(''); // For security reasons! ! $blog->setAdministrator($administrator);
! ! for ($postNumber = 1; $postNumber < 6; $postNumber++) {! ! ! $post = new Tx_BlogExample_Domain_Model_Post;! ! ! $post->setTitle('The Post #' . $postNumber);! ! ! $post->setAuthor($author);! ! ! $post->setContent('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.');! ! ! $blog->addPost($post);
! ! ! $comment = new Tx_BlogExample_Domain_Model_Comment;! ! ! $comment->setDate(new DateTime);! ! ! $comment->setAuthor('Peter Pan');! ! ! $comment->setEmail('[email protected]');! ! ! $comment->setContent('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.');! ! ! $post->addComment($comment);
! ! ! $comment = new Tx_BlogExample_Domain_Model_Comment;! ! ! $comment->setDate(new DateTime('2009-03-19 23:44'));! ! ! $comment->setAuthor('John Smith');! ! ! $comment->setEmail('[email protected]');! ! ! $comment->setContent('Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.');! ! ! $post->addComment($comment);
! ! ! $tag = new Tx_BlogExample_Domain_Model_Tag('MVC');! ! ! $post->addTag($tag);
! ! ! $tag = new Tx_BlogExample_Domain_Model_Tag('Domain Driven Design');! ! ! $post->addTag($tag);
! ! ! $post->setBlog($blog);! ! }
! ! return $blog;! }!
! /**! * Override getErrorFlashMessage to present! * nice flash error messages.! *! * @return string! */! protected function getErrorFlashMessage() {! ! switch ($this->actionMethodName) {! ! ! case 'updateAction' :! ! ! ! return 'Could not update the blog:';! ! ! case 'createAction' :! ! ! ! return 'Could not create the new blog:';! ! ! default :! ! ! ! return parent::getErrorFlashMessage();! ! }! }
}
/** * The blog controller for the Blog package * * @version $Id:$ * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2 */class Tx_BlogExample_Controller_BlogController extends Tx_Extbase_MVC_Controller_ActionController {
! /**! * @var Tx_BlogExample_Domain_Model_BlogRepository! */! protected $blogRepository;
! /**! * Initializes the current action! *! * @return void! */! public function initializeAction() {! ! $this->blogRepository = t3lib_div::makeInstance('Tx_BlogExample_Domain_Repository_BlogRepository');! ! $this->postRepository = t3lib_div::makeInstance('Tx_BlogExample_Domain_Repository_PostRepository');! ! $this->administratorRepository = t3lib_div::makeInstance('Tx_BlogExample_Domain_Repository_AdministratorRepository');! }
! /**! * Index action for this controller. Displays a list of blogs.! *! * @return string The rendered view! */! public function indexAction() {! ! $this->view->assign('blogs', $this->blogRepository->findAll());! }
! /**! * Displays a form for creating a new blog! *! * @param Tx_BlogExample_Domain_Model_Blog $newBlog A fresh blog object taken as a basis for the rendering! * @return string An HTML form for creating a new blog! * @dontvalidate $newBlog! */! public function newAction(Tx_BlogExample_Domain_Model_Blog $newBlog = NULL) {! ! $this->view->assign('newBlog', $newBlog);! ! $this->view->assign('administrators', $this->administratorRepository->findAll());! }
! /**! * Creates a new blog! *! * @param Tx_BlogExample_Domain_Model_Blog $newBlog A fresh Blog object which has not yet been added to the repository! * @return void! */! public function createAction(Tx_BlogExample_Domain_Model_Blog $newBlog) {! ! $this->blogRepository->add($newBlog);! ! $this->pushFlashMessage('Your new blog was created.');! ! $this->redirect('index');! }
! /**! * Edits an existing blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog The blog to edit or the blog with updated properties! * @param Tx_BlogExample_Domain_Model_Blog $existingBlog The existing unmodified blog or NULL to use the blog! * @return string Form for editing the existing blog! * @validate $blog Raw! */! public function editAction(Tx_BlogExample_Domain_Model_Blog $blog, Tx_BlogExample_Domain_Model_Blog $existingBlog = NULL) {! ! if ($existingBlog === NULL) {! ! ! $existingBlog = $blog;! ! }! ! $this->view->assign('blog', $blog);! ! $this->view->assign('existingBlog', $existingBlog);! ! $this->view->assign('administrators', $this->administratorRepository->findAll());! }
! /**! * Updates an existing blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog A not yet persisted clone of the original blog containing the modifications! * @return void! */! public function updateAction(Tx_BlogExample_Domain_Model_Blog $blog) {! ! $this->blogRepository->update($blog);! ! $this->pushFlashMessage('Your blog has been updated.');! ! $this->redirect('index');! }
! /**! * Deletes an existing blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog The blog to delete! * @return void! */! public function deleteAction(Tx_BlogExample_Domain_Model_Blog $blog) {! ! $this->blogRepository->remove($blog);! ! $this->pushFlashMessage('Your blog has been removed.');! ! $this->redirect('index');! }
! /**! * Deletes an existing blog! *! * @return void! */! public function deleteAllAction() {! ! $blogs = $this->blogRepository->findAll();! ! foreach ($blogs as $blog) {! ! ! $this->blogRepository->remove($blog);! ! }! ! $this->redirect('index');! }
! /**! * Creates a several new blogs! *! * @return void! */! public function populateAction() {! ! $author = t3lib_div::makeInstance('Tx_BlogExample_Domain_Model_Person', 'Jochen', 'Rau', '[email protected]');! ! for ($blogNumber = 1; $blogNumber < 4; $blogNumber++) {! ! ! $blog = $this->getBlog($blogNumber, $author);! ! ! $this->blogRepository->add($blog);! ! }! ! $this->redirect('index');! }
! /**! * Returns a sample blog populated with generic data. It is also an example how to handle objects and repositories in general.! *! * @param int $blogNumber The number of the blog! * @param Tx_BlogExample_Domain_Model_Person $author The author of posts! * @return Tx_BlogExample_Domain_Model_Blog The blog object! */! private function getBlog($blogNumber, $author) {! ! $blog = new Tx_BlogExample_Domain_Model_Blog;! ! $blog->setTitle('Blog #' . $blogNumber);! ! $blog->setDescription('A blog about TYPO3 extension development.');
! ! $administrator = new Tx_BlogExample_Domain_Model_Administrator('foobar', '123455');! ! $administrator->setName('John Doe');! ! $administrator->setEmail('[email protected]');! ! $administrator->setUsername(''); // For security reasons! ! $administrator->setPassword(''); // For security reasons! ! $blog->setAdministrator($administrator);
! ! for ($postNumber = 1; $postNumber < 6; $postNumber++) {! ! ! $post = new Tx_BlogExample_Domain_Model_Post;! ! ! $post->setTitle('The Post #' . $postNumber);! ! ! $post->setAuthor($author);! ! ! $post->setContent('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.');! ! ! $blog->addPost($post);
! ! ! $comment = new Tx_BlogExample_Domain_Model_Comment;! ! ! $comment->setDate(new DateTime);! ! ! $comment->setAuthor('Peter Pan');! ! ! $comment->setEmail('[email protected]');! ! ! $comment->setContent('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.');! ! ! $post->addComment($comment);
! ! ! $comment = new Tx_BlogExample_Domain_Model_Comment;! ! ! $comment->setDate(new DateTime('2009-03-19 23:44'));! ! ! $comment->setAuthor('John Smith');! ! ! $comment->setEmail('[email protected]');! ! ! $comment->setContent('Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.');! ! ! $post->addComment($comment);
! ! ! $tag = new Tx_BlogExample_Domain_Model_Tag('MVC');! ! ! $post->addTag($tag);
! ! ! $tag = new Tx_BlogExample_Domain_Model_Tag('Domain Driven Design');! ! ! $post->addTag($tag);
! ! ! $post->setBlog($blog);! ! }
! ! return $blog;! }!
! /**! * Override getErrorFlashMessage to present! * nice flash error messages.! *! * @return string! */! protected function getErrorFlashMessage() {! ! switch ($this->actionMethodName) {! ! ! case 'updateAction' :! ! ! ! return 'Could not update the blog:';! ! ! case 'createAction' :! ! ! ! return 'Could not create the new blog:';! ! ! default :! ! ! ! return parent::getErrorFlashMessage();! ! }! }
}
How could you fetch a blog?
How could you fetch a book?
Blog
Post
Comment Tag
Model
Blog
Post
Comment Tag
Model
BlogRepository
/** * A repository for Blogs */class Tx_BlogExample_Domain_Repository_BlogRepository extends Tx_Extbase_Persistence_Repository {!
! /**! * Remove the blog's posts before removing the blog itself.! *! * @return array An array filled with blogs! */! public function findAll() {! ! $blogs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(! ! ! '*',! ! ! 'tx_blogexample_domain_model_blog',! ! ! 'sys_language_uid=' . $GLOBALS['TSFE']->sys_language_uid
. $this->cObj->enableFields('tx_blogexample_domain_model_blog'),! ! ! '',! ! ! 'date'! ! ! );! ! !
! ! return $blogs;! }}
/** * A repository for Blogs */class Tx_BlogExample_Domain_Repository_BlogRepository extends Tx_Extbase_Persistence_Repository {!
}
/** * A repository for Posts */class Tx_BlogExample_Domain_Repository_PostRepository extends Tx_Extbase_Persistence_Repository {!
! /**! * Finds posts by the specified blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog The blog the post must refer to! * @param integer $limit The number of posts to return at max! * @return array The posts! */! public function findByBlog(Tx_BlogExample_Domain_Model_Blog $blog, $limit = 20) {! ! $query = $this->createQuery();! ! return $query->matching($query->equals('blog', $blog))! ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))! ! ! ->setLimit($limit)! ! ! ->execute();! }
! /**! * Finds the previous of the given post! *! * @param Tx_BlogExample_Domain_Model_Post $post The reference post! * @return Tx_BlogExample_Domain_Model_Post! */! public function findPrevious(Tx_BlogExample_Domain_Model_Post $post) {! ! $query = $this->createQuery();! ! $posts = $query->matching($query->lessThan('date', $post->getDate()))! ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))! ! ! ->setLimit(1)! ! ! ->execute();! ! return (count($posts) == 0) ? NULL : current($posts);! }
! /**! * Finds the post next to the given post! *! * @param Tx_BlogExample_Domain_Model_Post $post The reference post! * @return Tx_BlogExample_Domain_Model_Post! */! public function findNext(Tx_BlogExample_Domain_Model_Post $post) {! ! $query = $this->createQuery();! ! $posts = $query->matching($query->greaterThan('date', $post->getDate()))! ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))! ! ! ->setLimit(1)! ! ! ->execute();! ! return (count($posts) == 0) ? NULL : current($posts);! }
! /**! * Finds most recent posts by the specified blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog The blog the post must refer to! * @param integer $limit The number of posts to return at max! * @return array The posts! */! public function findRecentByBlog(Tx_BlogExample_Domain_Model_Blog $blog, $limit = 5) {! ! $query = $this->createQuery();! ! return $query->matching($query->equals('blog', $blog))! ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))! ! ! ->setLimit($limit)! ! ! ->execute();! }}
/** * A repository for Posts */class Tx_BlogExample_Domain_Repository_PostRepository extends Tx_Extbase_Persistence_Repository {!
! /**! * Finds posts by the specified blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog The blog the post must refer to! * @param integer $limit The number of posts to return at max! * @return array The posts! */! public function findByBlog(Tx_BlogExample_Domain_Model_Blog $blog, $limit = 20) {! ! $query = $this->createQuery();! ! return $query->matching($query->equals('blog', $blog))! ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))! ! ! ->setLimit($limit)! ! ! ->execute();! }
! /**! * Finds the previous of the given post! *! * @param Tx_BlogExample_Domain_Model_Post $post The reference post! * @return Tx_BlogExample_Domain_Model_Post! */! public function findPrevious(Tx_BlogExample_Domain_Model_Post $post) {! ! $query = $this->createQuery();! ! $posts = $query->matching($query->lessThan('date', $post->getDate()))! ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))! ! ! ->setLimit(1)! ! ! ->execute();! ! return (count($posts) == 0) ? NULL : current($posts);! }
! /**! * Finds the post next to the given post! *! * @param Tx_BlogExample_Domain_Model_Post $post The reference post! * @return Tx_BlogExample_Domain_Model_Post! */! public function findNext(Tx_BlogExample_Domain_Model_Post $post) {! ! $query = $this->createQuery();! ! $posts = $query->matching($query->greaterThan('date', $post->getDate()))! ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))! ! ! ->setLimit(1)! ! ! ->execute();! ! return (count($posts) == 0) ? NULL : current($posts);! }
! /**! * Finds most recent posts by the specified blog! *! * @param Tx_BlogExample_Domain_Model_Blog $blog The blog the post must refer to! * @param integer $limit The number of posts to return at max! * @return array The posts! */! public function findRecentByBlog(Tx_BlogExample_Domain_Model_Blog $blog, $limit = 5) {! ! $query = $this->createQuery();! ! return $query->matching($query->equals('blog', $blog))! ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))! ! ! ->setLimit($limit)! ! ! ->execute();! }}
Repositories
Encapsulate all data accessSQL is allowed only in the Repository... but not necessary anymore: use the Query object insteadMagic methods: "ndBy*, "ndOneBy*
Blog
Post
Comment Tag
Blog
Post
Comment Tag
Aggregate
Blog
Post
Comment Tag
Entity
Blog
Post
Comment Tag
ValueObject
Entity
Blog
Post
Comment Tag
Aggregate Root
ValueObject
Entity
Blog
Post
Comment Tag
Aggregate RootgetLatestComment()
Blog
Post
Comment Tag
Aggregate RootgetLatestComment()
Blog
Post
Comment Tag
Aggregate RootgetLatestComment()
<h1 class="csc-firstHeader">Welcome to {blog.title}</h1><p class="bodytext">{blog.description}</p><div class="tx-blogexample-list-container">! <f:if condition="{blog.posts}">! ! <f:then>! ! <p class="bodytext"><f:translate key="label_recent_posts">Below are the most recent posts:</f:translate></p>! ! ! <ul>! ! ! ! <f:for each="{blog.posts}" as="post">! ! ! ! ! <li>! ! ! ! ! ! <h3>! ! ! ! ! ! ! <f:format.date>{post.date}</f:format.date>! ! ! ! ! ! ! <f:link.action action="show" controller="Post" arguments="{post: post, blog: post.blog}">{post.title}</f:link.action>! ! ! ! ! ! </h3>! ! ! ! ! ! <p class="bodytext"><f:format.crop maxCharacters="100">{post.content}</f:format.crop></p>! ! ! ! ! ! <p>! ! ! ! ! ! ! By: {post.author.fullName}<br />! ! ! ! ! ! ! Tags: <f:for each="{post.tags}" as="tag">[{tag.name}] </f:for><br />! ! ! ! ! ! ! <f:link.action controller="Post" action="show" arguments="{post : post}">
<f:translate key="read_more">read more >></f:translate></f:link.action><br />
! ! ! ! ! ! ! <f:link.action controller="Post" action="edit" arguments="{post : post, blog : blog}">Edit
</f:link.action> <f:link.action controller="Post" action="delete" arguments="{post : post, blog : blog}">
Delete</f:link.action>
! ! ! ! ! ! </p>! ! ! ! ! </li>! ! ! ! </f:for>! ! ! </ul>! ! </f:then>! ! <f:else>! ! ! <p>This blog currently doesn't contain any posts.</p>! ! </f:else>! </f:if>! <p><f:link.action action="new" controller="Post" arguments="{blog : blog}">Create a new Post</f:link.action></p></div>
Security
All arguments must be registered.Registration of expected arguments happens through de"ning them as method parameters.PHPDoc is mandatory as it is used for data type validation
/** * A blog post comment * * @package Blog * @subpackage Domain * @version $Id:$ * @copyright Copyright belongs to the respective authors * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2 * @scope prototype * @entity */class Tx_BlogExample_Domain_Model_Comment extends Tx_Extbase_DomainObject_AbstractEntity {
! /**! * @var DateTime! */! protected $date;
! /**! * @var string! * @validate Text, StringLength(minimum = 3, maximum = 80)! */! protected $author;
! /**! * @var string! * @validate EmailAddress! */! protected $email;
! /**! * @var string! * @validate Text, NotEmpty! */! protected $content;!
!
! /**! * Constructs this post! */! public function __construct() {! ! $this->date = new DateTime();! }
! /**! * Setter for date! *! * @param DateTime $date! * @return void! */! public function setDate(DateTime $date) {! ! $this->date = $date;! }
! /**! * Getter for date! *! * @return DateTime! */! public function getDate() {! ! return $this->date;! }
! /**! * Sets the author for this comment! *! * @param string $author! * @return void! */! public function setAuthor($author) {! ! $this->author = $author;! }
! /**! * Getter for author! *! * @return string! */! public function getAuthor() {! ! return $this->author;! }
! /**! * Sets the authors email for this comment! *! * @param string $email email of the author! * @return void! */! public function setEmail($email) {! ! $this->email = $email;! }
! /**! * Getter for authors email! *! * @return string! */! public function getEmail() {! ! return $this->email;! }
! /**! * Sets the content for this comment! *! * @param string $content! * @return void! */! public function setContent($content) {! ! $this->content = $content;! }
! /**! * Getter for content! *! * @return string! */! public function getContent() {! ! return $this->content;! }
! /**! * Returns this comment as a formatted string! *! * @return string! */! public function __toString() {! ! return $this->author . ' (' . $this->email . ') said on ' . $this->date->format('Y-m-d') . ':' . chr(10) .! ! ! $this->content . chr(10);! }}
Domain / Model
View
Configuration
Controller
Principles of Domain Driven Design
focus on the domain = activity or business of user
we start with the business logic (PHP classes)
we don't care about the database backend / persistence layer
objects represent things in the real world, with their attributes and behavior
ubiquitous language
building blocks
Entity
Value Objects
Repositories
What's next?
What's next
New Kickstartercurrently ongoing project by the core development teamwill be released shortly after 4.3Domain-Driven Design - Don't think in databases, think in Domain Models!
Support for BE-Modulesexperimental by now
AJAX-DispatcherDependency InjectionPDO Storage Backend
Modern architecture
-
Greatly reusablecomponents
Modularreusablecomponents
Easy and clean API
Easy testable
Get more implementedin less time
You willget addicted
Christopher Hlubek
Sebastian Kurfürst
Bastian Waidelich
Ingmar Schlecht
and the TYPO3 V5 Team for all the inspiration and the beautiful code
Thank YouSteffen Kamper
Xavier Perseguers
Resources and links
Project web site: http://forge.typo3.org/projects/show/typo3v4-mvcSVN: https://svn.typo3.org/TYPO3v4/CoreProjects/MVC/Newslist [email protected]"elders.deFirst stable release with TYPO3 4.3 alpha3: http://typo3.org/download/packages/