114
http://www.sxc.hu/photo/768249 Get into the FLOW with Extbase

Get into the FLOW with Extbase

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

Page 1: Get into the FLOW with Extbase

http://www.sxc.hu/photo/768249

Get into the FLOW with Extbase

Page 2: Get into the FLOW with Extbase

Who is this?

Page 3: Get into the FLOW with Extbase

Dipl.-Ing. Mechanical Engineering

Page 4: Get into the FLOW with Extbase

infected with TYPO3 in 2OO1

Page 5: Get into the FLOW with Extbase

Tübingen

Page 6: Get into the FLOW with Extbase
Page 7: Get into the FLOW with Extbase

6O% selfemployed6O% father

Page 8: Get into the FLOW with Extbase

6O% selfemployed6O% father

----8O%

Page 9: Get into the FLOW with Extbase

5 years: Fraunhofer-Gesellschaft

German Aerospace Center

Page 10: Get into the FLOW with Extbase

5 years:high school

teacher

Page 11: Get into the FLOW with Extbase

What is Extbase all about?

Page 12: Get into the FLOW with Extbase

1997

Page 13: Get into the FLOW with Extbase

v4

2OO9

Page 14: Get into the FLOW with Extbase

v4

Page 15: Get into the FLOW with Extbase

v4

2OO6

Page 16: Get into the FLOW with Extbase

v4

v5

Page 17: Get into the FLOW with Extbase

v4

v5

Page 18: Get into the FLOW with Extbase

v4

v5

Page 19: Get into the FLOW with Extbase

v4

v5Extbase

Page 20: Get into the FLOW with Extbase

v4

v5

Page 21: Get into the FLOW with Extbase

What is Extbase all about?

Page 22: Get into the FLOW with Extbase

Extbase

FLOW 3

Page 23: Get into the FLOW with Extbase

What is Extbase all about?

Page 24: Get into the FLOW with Extbase

Extbase

Page 25: Get into the FLOW with Extbase

Extbase

MVC

DDD

VfB

OOP Aggregate

Entity

Repository

View

Helper

Page 26: Get into the FLOW with Extbase

Extbase

Entity

View Helper

Value

Page 27: Get into the FLOW with Extbase

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)

Page 29: Get into the FLOW with Extbase

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

Page 30: Get into the FLOW with Extbase

<?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;! }

Page 31: Get into the FLOW with Extbase

<?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;! }

Page 32: Get into the FLOW with Extbase

<?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;!

}

Page 33: Get into the FLOW with Extbase
Page 34: Get into the FLOW with Extbase

control flow

business logic

CRUD data

other , eg. config

render output

Page 35: Get into the FLOW with Extbase

control flow

business logic

CRUD data

other , eg. config

render output

aggregate

Page 36: Get into the FLOW with Extbase

generalize

control flow

business logic

CRUD data

other , eg. config

render output

Page 37: Get into the FLOW with Extbase

partition

Page 38: Get into the FLOW with Extbase

useExtbase & Fluid

Page 39: Get into the FLOW with Extbase
Page 40: Get into the FLOW with Extbase

control flow

business logic

CRUD data

other , eg. config

render output

Page 41: Get into the FLOW with Extbase

Controller

Domain Model

Domain Repository

other , eg. config

View

Page 42: Get into the FLOW with Extbase

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

Page 43: Get into the FLOW with Extbase

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

Page 44: Get into the FLOW with Extbase

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

Page 45: Get into the FLOW with Extbase

TYPO3

Page 46: Get into the FLOW with Extbase

tx_blog_piTYPO3

userFunc

1tx_blog

tslib_piBase

Page 47: Get into the FLOW with Extbase

tx_blog_piexec_SELECTgetRows

TYPO3

userFunc

1tx_blog

2

tslib_piBase

Database

Page 48: Get into the FLOW with Extbase

tx_blog_piexec_SELECTgetRows

TYPO3

userFunc

1tx_blog

rows as array

2

3

tslib_piBase

Database

Page 49: Get into the FLOW with Extbase

tx_blog_piexec_SELECTgetRows

TYPO3

userFunc

1tx_blog

rows as array

2

3

HTML

4

tslib_piBase

Database

Page 50: Get into the FLOW with Extbase

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);}

Page 51: Get into the FLOW with Extbase

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;}

Page 52: Get into the FLOW with Extbase

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;}

Page 53: Get into the FLOW with Extbase

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 -->

Page 54: Get into the FLOW with Extbase

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}

Page 55: Get into the FLOW with Extbase

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]

Page 56: Get into the FLOW with Extbase

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! );}

Page 57: Get into the FLOW with Extbase

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'! );[...]

Page 58: Get into the FLOW with Extbase

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

Page 59: Get into the FLOW with Extbase

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;

Page 60: Get into the FLOW with Extbase

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

Page 61: Get into the FLOW with Extbase

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

Page 62: Get into the FLOW with Extbase

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'! );[...]

Page 63: Get into the FLOW with Extbase

http://www.sxc.hu/photo/516864/

Extension buildingwith Extbase

Page 64: Get into the FLOW with Extbase

TYPO3

Page 65: Get into the FLOW with Extbase

ExtbaseDispatcherTYPO3

userFunc

1

Page 66: Get into the FLOW with Extbase

ExtbaseDispatcher

Controller

Request

TYPO3

userFunc

12 BlogExample

Page 67: Get into the FLOW with Extbase

ExtbaseDispatcher

Controller

Repository

Request

findByTitle('MyBlog')

TYPO3

Domain Model

userFunc

12

3

Blog

Post

Comment Tag

BlogExample

Page 68: Get into the FLOW with Extbase

ExtbaseDispatcher

Controller

Repository

Request

findByTitle('MyBlog')

Blog

TYPO3

Domain Model

userFunc

12

3

4

Blog

Post

Comment Tag

BlogExample

Page 69: Get into the FLOW with Extbase

ExtbaseDispatcher

Controller

Repository View

Request

findByTitle('MyBlog')

Blog

assign(Blog)

TYPO3

Domain Model

render()

userFunc

12

3

4

5

Blog

Post

Comment Tag

BlogExample

Page 70: Get into the FLOW with Extbase

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

Page 71: Get into the FLOW with Extbase

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

Page 72: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Page 73: Get into the FLOW with Extbase

Model

Page 74: Get into the FLOW with Extbase

/** * 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;! }

}

Page 75: Get into the FLOW with Extbase

/** * 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;! }

}

Page 76: Get into the FLOW with Extbase

/** * 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;! }

}

Page 77: Get into the FLOW with Extbase

/** * 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);! }}

Page 78: Get into the FLOW with Extbase

/** * 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);! }}

Page 79: Get into the FLOW with Extbase

and...

action

http://www.sxc.hu/photo/444174/

Page 80: Get into the FLOW with Extbase

/** * 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();! ! }! }

}

Page 81: Get into the FLOW with Extbase

/** * 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();! ! }! }

}

Page 82: Get into the FLOW with Extbase

How could you fetch a blog?

Page 83: Get into the FLOW with Extbase

How could you fetch a book?

Page 84: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Model

Page 85: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Model

BlogRepository

Page 86: Get into the FLOW with Extbase

/** * 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;! }}

Page 87: Get into the FLOW with Extbase

/** * A repository for Blogs */class Tx_BlogExample_Domain_Repository_BlogRepository extends Tx_Extbase_Persistence_Repository {!

}

Page 88: Get into the FLOW with Extbase

/** * 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();! }}

Page 89: Get into the FLOW with Extbase

/** * 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();! }}

Page 90: Get into the FLOW with Extbase

Repositories

Encapsulate all data accessSQL is allowed only in the Repository... but not necessary anymore: use the Query object insteadMagic methods: "ndBy*, "ndOneBy*

Page 91: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Page 92: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Aggregate

Page 93: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Entity

Page 94: Get into the FLOW with Extbase

Blog

Post

Comment Tag

ValueObject

Entity

Page 95: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Aggregate Root

ValueObject

Entity

Page 96: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Aggregate RootgetLatestComment()

Page 97: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Aggregate RootgetLatestComment()

Page 98: Get into the FLOW with Extbase

Blog

Post

Comment Tag

Aggregate RootgetLatestComment()

Page 99: Get into the FLOW with Extbase

<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}]&nbsp;</f:for><br />! ! ! ! ! ! ! <f:link.action controller="Post" action="show" arguments="{post : post}">

<f:translate key="read_more">read more &gt;&gt;</f:translate></f:link.action><br />

! ! ! ! ! ! ! <f:link.action controller="Post" action="edit" arguments="{post : post, blog : blog}">Edit

</f:link.action>&nbsp;<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>

Page 100: Get into the FLOW with Extbase

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

Page 101: Get into the FLOW with Extbase

/** * 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);! }}

Page 102: Get into the FLOW with Extbase

Domain / Model

View

Configuration

Controller

Page 103: Get into the FLOW with Extbase

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

Page 104: Get into the FLOW with Extbase

What's next?

Page 105: Get into the FLOW with Extbase

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

Page 106: Get into the FLOW with Extbase
Page 107: Get into the FLOW with Extbase

Modern architecture

-

Page 108: Get into the FLOW with Extbase

Greatly reusablecomponents

Modularreusablecomponents

Page 109: Get into the FLOW with Extbase

Easy and clean API

Page 110: Get into the FLOW with Extbase

Easy testable

Page 111: Get into the FLOW with Extbase

Get more implementedin less time

Page 112: Get into the FLOW with Extbase

You willget addicted

Page 113: Get into the FLOW with Extbase

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

Page 114: Get into the FLOW with Extbase

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/