Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Get into the FLOW with Extbase

21,859 views

Published on

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.

Published in: Technology, Business
  • This is real take it serious, who will believe that a herb can cure herpes, i navel believe that this will work i have spend a lot when getting drugs from the hospital to keep me healthy, what i was waiting for is death because i was broke, one day i hard about this great man who is well know of HIV and cancer cure, i decided to email him, unknowingly to me that this will be the end of the herpes in my body, he prepare the herb for me, and give me instruction on how to take it, at the end of the one month, he told me to go to the hospital for a check up, and i went, surprisingly after the test the doctor confirm me negative, i thought it was a joke, i went to other hospital was also negative, then i took my friend who was also herpes positive to the Dr Agumagu, after the treatment she was also confirm negative . He also have the herb to cure cancer. please i want every one with this virus to be free, that is why am dropping his email address, agumaguspelltemple@outlook.com or agumaguspelltemple@gmail.com do email him he is a great man. the government is also interested in this DR, thank you for saving my life, and I promise I will always testify for your good work call his number +233200116937
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • That's good overview slide. ;-)
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Nice information about extbase..

    Regards,
    http://evoire.com/members/azuan/
    http://www.azuanrazi.com/contest-hidup-seorang-blogger/
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Extbase is a great resource and It is very interesting. business administration careers. http://www.floridatechonline.com/online-degree-resources/business-administration-career-opportunities.asp
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Extbase is a great resource and It is very interesting. business administration careers business administration careers
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Get into the FLOW with Extbase

  1. 1. Get into the FLOW with Extbase http://www.sxc.hu/photo/768249
  2. 2. Who is this?
  3. 3. Dipl.-Ing. Mechanical Engineering
  4. 4. infected with TYPO3 in 2OO1
  5. 5. Tübingen
  6. 6. 6O% selfemployed 6O% father
  7. 7. 8O% ---- selfemployed 6O% 6O% father
  8. 8. 5 years: Fraunhofer- Gesellschaft German Aerospace Center
  9. 9. 5 years: high school teacher
  10. 10. What is Extbase all about?
  11. 11. 1997
  12. 12. v4 2OO9
  13. 13. v4
  14. 14. v4 2OO6
  15. 15. v5 v4
  16. 16. v5 v4
  17. 17. v5 v4
  18. 18. Extbase v5 v4
  19. 19. v5 v4
  20. 20. What is Extbase all about?
  21. 21. Extbase FLOW 3
  22. 22. What is Extbase all about?
  23. 23. Extbase
  24. 24. OOP A ggregate DDD Extbase V iew Entity H elp er M VC VfB R epository
  25. 25. Extbase Value
  26. 26. Value enables and encourages the developer to write maintainable code separates di erent responsibilities modular architecture of the extension relieves the developer in safety-critical and recurring tasks validation of arguments invoking the template mechanism persistence read 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)
  27. 27. tp://commons.wikimedia.org/wiki/File:Z%C3%BCrich_-_Seefeld_-_Heureka_IMG_1757.JPG
  28. 28. tx_ttnews 3397 tx_pbsurvey_pi1 253O tx_ttproducts_pi1 1O9O tx_mmforum_pi1 6126 tx_veguestbook_pi1 1156 tp://commons.wikimedia.org/wiki/File:Z%C3%BCrich_-_Seefeld_-_Heureka_IMG_1757.JPG
  29. 29. ! /** ! * 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:
  30. 30. ! /** ! * 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']));
  31. 31. 'pointer'; ! ! ! ! $wrappedSubpartArray['# ##LINK_ITEM###'] = explode('|', $this- >pi_linkTP_keepPIvars(' |', array( ! ! ! ! ! 'tt_news' => null, ! ! ! ! ! 'backPid' => null, ! ! ! ! ! $this- >config['singleViewPoin terName'] => 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['singleViewPoin terName'] => 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['substitutePageti tle']) { ! ! ! ! $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($ro w, 'displaySingle'); ! ! ! // Substitute ! ! ! $content = $this->cObj- >substituteMarkerArrayC ached($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_stdW rap.']); ! ! ! $content = $noTranslMsg; ! ! } elseif ($row['pid'] < 0) { // a non-public version of a record was requested ! ! ! $nonPlublicVersion = $this->local_cObj- >stdWrap($this- >pi_getLL('nonPlublicVe rsionMsg'), $this- >conf['nonPlublicVersio nMsg_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-
  32. 32. control flow business logic CRUD data render output other , eg. config
  33. 33. control flow business logic aggregate CRUD data render output other , eg. config
  34. 34. control flow business logic generalize CRUD data render output other , eg. config
  35. 35. partition
  36. 36. Extbase use & Fluid
  37. 37. control flow business logic CRUD data render output other , eg. config
  38. 38. Controller Domain Model Domain Repository View other , eg. config
  39. 39. Blog features administrate blogs, blog posts and blog comments list all available blogs list all blog posts of a blog list all comments of a blog post allow users to post new comments
  40. 40. Blog features administrate blogs, blog posts and blog comments Blog list all available blogs list all blog posts of a blog list all comments of a blog post allow users to post new comments
  41. 41. Blog features administrate blogs, blog posts and blog comments Blog list all available blogs list all blog posts of a blog list all comments of a blog post allow users to post new comments Post Comment Tag
  42. 42. TYPO3
  43. 43. tslib_piBase tx_blog 1 userFunc TYPO3 tx_blog_pi
  44. 44. tslib_piBase tx_blog 1 userFunc 2 exec_SELECTgetRows TYPO3 tx_blog_pi Database
  45. 45. tslib_piBase tx_blog 1 userFunc 2 exec_SELECTgetRows TYPO3 tx_blog_pi rows as Database array 3
  46. 46. tslib_piBase tx_blog 1 userFunc 2 exec_SELECTgetRows TYPO3 tx_blog_pi HTML rows as Database 4 array 3
  47. 47. 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); }
  48. 48. 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###');
  49. 49. Task 1: Output a listing of blogs ! 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; }
  50. 50. 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 -->
  51. 51. 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 }
  52. 52. Task 3: Add a new comment to a blog post the whole plugin is cached („USER“) dynamic user input won‘t outputted instantly de ne uncached behavior in TypoScript [globalVar = _POST:tx_blogexample_pi1|newComment = 1] ! plugin.tx_blogexample_pi1 = USER_INT [globals]
  53. 53. 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 ! ); }
  54. 54. 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' ! ); [...]
  55. 55. 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
  56. 56. 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;
  57. 57. 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; INSERT INTO be_users SET ...; SELECT * FROM tx_blog_comment WHERE 1=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"
  58. 58. 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; INSERT INTO be_users SET ...; SELECT * FROM tx_blog_comment WHERE 1=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"
  59. 59. 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=' . intval($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; INSERT INTO be_users SET ...; SELECT * FROM tx_blog_comment WHERE 1=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"
  60. 60. http://www.sxc.hu/photo/516864/ Extension building with Extbase
  61. 61. TYPO3
  62. 62. 1 userFunc Extbase TYPO3 Dispatcher
  63. 63. 1 2 userFunc Request BlogExample Extbase TYPO3 Dispatcher Controller
  64. 64. 1 2 userFunc Request BlogExample Extbase TYPO3 Dispatcher Controller 3 findByTitle('MyBlog') Repository Domain Model Blog Post Comment Tag
  65. 65. 1 2 userFunc Request BlogExample Extbase TYPO3 Dispatcher Controller 3 findByTitle('MyBlog') Blog 4 Repository Domain Model Blog Post Comment Tag
  66. 66. 1 2 userFunc Request BlogExample Extbase TYPO3 Dispatcher Controller 3 assign(Blog) findByTitle('MyBlog') render() 5 Blog 4 View Repository Domain Model Blog Post Comment Tag
  67. 67. 1 2 userFunc Request BlogExample Extbase TYPO3 Dispatcher HTML Response Controller 6 3 assign(Blog) findByTitle('MyBlog') render() 5 Blog Response 4 View Repository Domain Model Blog Post Comment Tag
  68. 68. 1 2 userFunc Request BlogExample Extbase TYPO3 Dispatcher HTML Response Controller 6 3 assign(Blog) findByTitle('MyBlog') render() 5 Blog Response 4 View Repository Domain Model Blog Post Comment Tag
  69. 69. Blog Post Comment Tag
  70. 70. Model
  71. 71. /** * 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 = '';
  72. 72. ! } ! /** ! * 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;
  73. 73. ! * @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; ! } }
  74. 74. /** * 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
  75. 75. ! * @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); ! } }
  76. 76. http://www.sxc.hu/photo/444174/ and... action
  77. 77. /** * 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()); ! }
  78. 78. ! } ! /** ! * 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'); ! }
  79. 79. How could you fetch a blog?
  80. 80. How could you fetch a book?
  81. 81. Model Blog Post Comment Tag
  82. 82. Model BlogRepository Blog Post Comment Tag
  83. 83. /** * 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; ! } }
  84. 84. /** * A repository for Blogs */ class Tx_BlogExample_Domain_Repository_BlogRepository extends Tx_Extbase_Persistence_Repository { ! }
  85. 85. /** * 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) {
  86. 86. ! * @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(); ! } }
  87. 87. Repositories Encapsulate all data access SQL is allowed only in the Repository ... but not necessary anymore: use the Query object instead Magic methods: ndBy*, ndOneBy*
  88. 88. Blog Post Comment Tag
  89. 89. Aggregate Blog Post Comment Tag
  90. 90. Blog Entity Post Comment Tag
  91. 91. Blog Entity Post Value Object Comment Tag
  92. 92. Aggregate Root Blog Entity Post Value Object Comment Tag
  93. 93. Aggregate getLatestComment() Root Blog Post Comment Tag
  94. 94. Aggregate getLatestComment() Root Blog Post Comment Tag
  95. 95. Aggregate getLatestComment() Root Blog Post Comment Tag
  96. 96. <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>
  97. 97. 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
  98. 98. */ 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
  99. 99. Controlle r odel Do main / M View Con fig ura tio n
  100. 100. 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
  101. 101. What's next?
  102. 102. What's next New Kickstarter currently ongoing project by the core development team will be released shortly after 4.3 Domain-Driven Design - Don't think in databases, think in Domain Models! Support for BE-Modules experimental by now AJAX-Dispatcher Dependency Injection PDO Storage Backend
  103. 103. - Modern architecture
  104. 104. Modular reusable Greatly reusable components components
  105. 105. Easy and clean API
  106. 106. Easy testable
  107. 107. Get more implemented in less time
  108. 108. You will get addicted
  109. 109. Bastian Waidelich Sebastian Kurfürst Than k You Steffen Kamper and the TYPO3 V5 Team for all the inspiration and the beautiful code Ingmar Schlecht Christopher Hlubek Xavier Perseguers
  110. 110. Resources and links Project web site: http://forge.typo3.org/projects/show/typo3v4-mvc SVN: https://svn.typo3.org/TYPO3v4/CoreProjects/MVC/ Newslist typo3.projects.typo3v4mvc@lists.net elders.de First stable release with TYPO3 4.3 alpha3: http://typo3.org/download/packages/

×