SlideShare a Scribd company logo
1 of 114
Download to read offline
Get into the FLOW
                                 with Extbase




http://www.sxc.hu/photo/768249
Who is this?
Dipl.-Ing.
Mechanical
Engineering
infected with
TYPO3 in 2OO1
Tübingen
6O% selfemployed
   6O% father
8O%
---- selfemployed
6O%
   6O% father
5 years:
  Fraunhofer-
  Gesellschaft
German Aerospace
      Center
5 years:
high school
  teacher
What is Extbase
  all about?
1997
v4



 2OO9
v4
v4



2OO6
v5

v4
v5

v4
v5

v4
Extbase   v5

     v4
v5

v4
What is Extbase
  all about?
Extbase
FLOW 3
What is Extbase
  all about?
Extbase
OOP     A ggregate    DDD

       Extbase
                            V iew
          Entity           H elp er
M VC
                     VfB
  R epository
Extbase
 Value
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)
tp://commons.wikimedia.org/wiki/File:Z%C3%BCrich_-_Seefeld_-_Heureka_IMG_1757.JPG
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
!   /**
!    * 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:
!   /**
!     * 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']));
'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-
control flow

business logic

CRUD data

render output

other , eg. config
control flow

            business logic

aggregate   CRUD data

            render output

            other , eg. config
control flow

             business logic

generalize   CRUD data

             render output

             other , eg. config
partition
Extbase
use
      & Fluid
control flow

business logic

CRUD data

render output

other , eg. config
Controller

Domain Model

Domain Repository

View

other , eg. config
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
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
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
TYPO3
tslib_piBase
                                  tx_blog
           1
        userFunc


TYPO3              tx_blog_pi
tslib_piBase
                                  tx_blog
           1
        userFunc                   2
                                  exec_SELECTgetRows
TYPO3              tx_blog_pi
                                                       Database
tslib_piBase
                                     tx_blog
           1
        userFunc                        2
                                    exec_SELECTgetRows
TYPO3              tx_blog_pi

                                  rows as                Database
                                   array

                                    3
tslib_piBase
                                     tx_blog
           1
        userFunc                        2
                                    exec_SELECTgetRows
TYPO3              tx_blog_pi
         HTML
                                  rows as                Database
           4                       array

                                    3
Control ow

public function main($content, $conf) {
! $this->conf = $conf;
! $this->pi_setPiVarDefaults();
! $this->pi_loadLL();

!   if ($this->piVars['postUid']) {
!   ! if ($this->piVars['newComment']) {
!   ! ! $this->storeNewComment();
!   ! }
!   ! $content = $this->renderPost();
!   } elseif ($this->piVars['blogUid']) {
!   ! $content = $this->renderBlog();
!   } else {
!   ! $content = $this->renderListOfBlogs();
!   }
!   return $this->pi_wrapInBaseClass($content);
}
Task 1: Output a listing of blogs

protected function renderListOfBlogs() {
! $blogs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
! ! '*',
! ! 'tx_blogexample_blog',
! ! 'sys_language_uid=' . $GLOBALS['TSFE']->sys_language_uid
         . $this->cObj->enableFields('tx_blogexample_blog'),
! ! '',
! ! 'date'
! ! );



!   $template = $this->cObj->fileResource($this->conf['template']);
!   $blogElementSubpart = $this->cObj->getSubpart($template, '###SUBPART_BLOGELEMENT###');
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;
}
Task 1: Output a listing of blogs


<!-- ###SUBPART_BLOGELEMENT### begin -->
<div class="blog element">
! ###BLOG_NAME###
! ###BLOG_LOGO###
! ###BLOG_DESCRIPTION###
! ###BLOG_MORELINK###
</div>
<!-- ###SUBPART_BLOGELEMENT### end -->
Task 2: Display a single post with its comments

protected function renderPost() {
! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);
! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
! ! '*',
! ! 'tx_blogexample_comment',
! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
          . $GLOBALS['TSFE']->sys_language_uid
! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
          . $this->cObj->enableFields('tx_blogexample_comment'),
! ! '',
! ! 'date DESC'
! );

// fill marker arrays and substitute in template
// return content
}
Task 3: Add a new comment to a blog post

 the whole plugin is cached („USER“)
 dynamic user input won‘t outputted instantly
 de ne uncached behavior in TypoScript


             [globalVar = _POST:tx_blogexample_pi1|newComment = 1]
             ! plugin.tx_blogexample_pi1 = USER_INT
             [globals]
Task 3: Add a new comment to a blog post

protected function storeNewComment() {
! $fields = array(
! ! 'post_uid' => $this->piVars['postUid'],
! ! 'post_table' => 'tx_blogexample_post',
! ! 'date' => time(),
! ! 'author' => $this->piVars['author'],
! ! 'email' => $this->piVars['email'],
! ! 'content' => $this->piVars['content'],
! );

!   $GLOBALS['TYPO3_DB']->exec_INSERTquery(
!   ! 'tx_blogexample_comment', $fields
!   );
}
Security: SQL injections
protected function renderPost() {
! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);
! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
! ! '*',
! ! 'tx_blogexample_comment',
! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
          . $GLOBALS['TSFE']->sys_language_uid
! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
          . $this->cObj->enableFields('tx_blogexample_comment'),
! ! '',
! ! 'date DESC'
! );
[...]
Security: SQL injections
protected function renderPost() {
! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);
! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
! ! '*',
! ! 'tx_blogexample_comment',
! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
          . $GLOBALS['TSFE']->sys_language_uid
! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
          . $this->cObj->enableFields('tx_blogexample_comment'),
! ! '',
! ! 'date DESC'
! );
[...]

  http://www.example.com/index.php&id=99&postUid=1
Security: SQL injections
protected function renderPost() {
! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);
! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
! ! '*',
! ! 'tx_blogexample_comment',
! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
          . $GLOBALS['TSFE']->sys_language_uid
! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
          . $this->cObj->enableFields('tx_blogexample_comment'),
! ! '',
! ! 'date DESC'
! );
[...]

  http://www.example.com/index.php&id=99&postUid=1



SELECT * FROM tx_blog_comment WHERE post_uid=1;
Security: SQL injections
protected function renderPost() {
! $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']);
! $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
! ! '*',
! ! 'tx_blogexample_comment',
! ! 'deleted=0 AND hidden=0 AND sys_language_uid='
          . $GLOBALS['TSFE']->sys_language_uid
! ! ! . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"'
          . $this->cObj->enableFields('tx_blogexample_comment'),
! ! '',
! ! 'date DESC'
! );
[...]

  http://www.example.com/index.php&id=99&postUid=1; 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"
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"
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"
http://www.sxc.hu/photo/516864/




                                  Extension building
                                        with Extbase
TYPO3
1
        userFunc

                    Extbase
TYPO3              Dispatcher
1
                                  2
        userFunc
                                Request
                                               BlogExample
                    Extbase
TYPO3              Dispatcher
                                          Controller
1
                                       2
        userFunc
                                    Request
                                                     BlogExample
                    Extbase
TYPO3              Dispatcher
                                              Controller

                            3
                         findByTitle('MyBlog')




                            Repository


                                                 Domain Model
                                    Blog


                                    Post



                           Comment         Tag
1
                                       2
        userFunc
                                    Request
                                                        BlogExample
                    Extbase
TYPO3              Dispatcher
                                              Controller

                            3
                         findByTitle('MyBlog')
                                                 Blog

                                                   4
                            Repository


                                                 Domain Model
                                    Blog


                                    Post



                           Comment         Tag
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
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
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
Blog




          Post




Comment          Tag
Model
/**
 * A blog
 *
 * @version $Id:$
 * @copyright Copyright belongs to the respective authors
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
 * @scope prototype
 * @entity
 */
class Tx_BlogExample_Domain_Model_Blog extends Tx_Extbase_DomainObject_AbstractEntity {

!   /**
!    * The blog's title.
!    *
!    * @var string
!    * @validate Text, StringLength(minimum = 1, maximum = 80)
!    * @identity
!    */
!   protected $title = '';

!   /**
!    * A short description of the blog
!    *
!    * @var string
!    * @validate Text, StringLength(maximum = 150)
!    */
!   protected $description = '';
!   }

!   /**
!    * 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;
!     * @return Tx_Extbase_Persistence_ObjectStorage
!     */
!   public function getPosts() {
!   ! return $this->posts;
!   }

!   /**
!     * Sets the administrator value
!     *
!     * @param Tx_BlogExample_Domain_Model_Administrator $administrator The Administrator of this Blog
!     * @return void
!     */
!   public function setAdministrator(Tx_BlogExample_Domain_Model_Administrator $administrator) {
!   ! $this->administrator = $administrator;
!   }

!   /**
!     * Returns the administrator value
!     *
!     * @return Tx_BlogExample_Domain_Model_Administrator
!     */
!   public function getAdministrator() {
!   ! return $this->administrator;
!   }

}
/**
 * A blog post comment
 *
 * @package Blog
 * @subpackage Domain
 * @version $Id:$
 * @copyright Copyright belongs to the respective authors
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
 * @scope prototype
 * @entity
 */
class Tx_BlogExample_Domain_Model_Comment extends Tx_Extbase_DomainObject_AbstractEntity {

!   /**
!    * @var DateTime
!    */
!   protected $date;

!   /**
!    * @var string
!    * @validate Text, StringLength(minimum = 3, maximum = 80)
!    */
!   protected $author;

!   /**
!    * @var string
!    * @validate EmailAddress
!    * @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);
!   }
}
http://www.sxc.hu/photo/444174/




                                  and...




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

!   /**
!     * 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');
!   }
How could you
fetch a blog?
How could you
fetch a book?
Model

                  Blog




                  Post




        Comment          Tag
Model

        BlogRepository
                                   Blog




                                   Post




                         Comment          Tag
/**
 * A repository for Blogs
 */
class Tx_BlogExample_Domain_Repository_BlogRepository extends Tx_Extbase_Persistence_Repository {
!
! /**
!   * Remove the blog's posts before removing the blog itself.
!   *
!   * @return array An array filled with blogs
!   */
! public function findAll() {
! ! $blogs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
! ! ! '*',
! ! ! 'tx_blogexample_domain_model_blog',
! ! ! 'sys_language_uid=' . $GLOBALS['TSFE']->sys_language_uid
           . $this->cObj->enableFields('tx_blogexample_domain_model_blog'),
! ! ! '',
! ! ! 'date'
! ! ! );
! ! !
! ! return $blogs;
! }
}
/**
 * A repository for Blogs
 */
class Tx_BlogExample_Domain_Repository_BlogRepository extends Tx_Extbase_Persistence_Repository {
!
}
/**
 * A repository for Posts
 */
class Tx_BlogExample_Domain_Repository_PostRepository extends Tx_Extbase_Persistence_Repository {
!
! /**
!   * Finds posts by the specified blog
!   *
!   * @param Tx_BlogExample_Domain_Model_Blog $blog The blog the post must refer to
!   * @param integer $limit The number of posts to return at max
!   * @return array The posts
!   */
! public function findByBlog(Tx_BlogExample_Domain_Model_Blog $blog, $limit = 20) {
! ! $query = $this->createQuery();
! ! return $query->matching($query->equals('blog', $blog))
! ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))
! ! ! ->setLimit($limit)
! ! ! ->execute();
! }

!   /**
!    * Finds the previous of the given post
!    *
!    * @param Tx_BlogExample_Domain_Model_Post $post The reference post
!    * @return Tx_BlogExample_Domain_Model_Post
!    */
!   public function findPrevious(Tx_BlogExample_Domain_Model_Post $post) {
!    * @param Tx_BlogExample_Domain_Model_Post $post The reference post
!    * @return Tx_BlogExample_Domain_Model_Post
!    */
!   public function findNext(Tx_BlogExample_Domain_Model_Post $post) {
!   ! $query = $this->createQuery();
!   ! $posts = $query->matching($query->greaterThan('date', $post->getDate()))
!   ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))
!   ! ! ->setLimit(1)
!   ! ! ->execute();
!   ! return (count($posts) == 0) ? NULL : current($posts);
!   }

!   /**
!    * Finds most recent posts by the specified blog
!    *
!    * @param Tx_BlogExample_Domain_Model_Blog $blog The blog the post must refer to
!    * @param integer $limit The number of posts to return at max
!    * @return array The posts
!    */
!   public function findRecentByBlog(Tx_BlogExample_Domain_Model_Blog $blog, $limit = 5) {
!   ! $query = $this->createQuery();
!   ! return $query->matching($query->equals('blog', $blog))
!   ! ! ->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING))
!   ! ! ->setLimit($limit)
!   ! ! ->execute();
!   }
}
Repositories

 Encapsulate all data access
 SQL is allowed only in the Repository
 ... but not necessary anymore: use the Query object instead
 Magic methods: ndBy*, ndOneBy*
Blog




          Post




Comment          Tag
Aggregate

                Blog




                Post




      Comment          Tag
Blog


Entity

                   Post




         Comment          Tag
Blog


Entity

                   Post


                                Value
                                Object
         Comment          Tag
Aggregate
                                  Root
                   Blog


Entity

                   Post


                                  Value
                                  Object
         Comment          Tag
Aggregate
getLatestComment()                            Root
                               Blog




                               Post




                     Comment          Tag
Aggregate
getLatestComment()                            Root
                               Blog




                               Post




                     Comment          Tag
Aggregate
getLatestComment()                            Root
                               Blog




                               Post




                     Comment          Tag
<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>
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
*/
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
Controlle
                r




                  odel
      Do main / M




             View




Con
   fig
       ura
           tio
               n
Principles of Domain Driven Design

 focus on the domain = activity or business of user
   we start with the business logic (PHP classes)
   we don't care about the database backend / persistence layer
 objects represent things in the real world, with their attributes and behavior
 ubiquitous language
 building blocks
   Entity
   Value Objects
   Repositories
What's next?
What's next

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


          Modern
    architecture
Modular
reusable
 Greatly reusable
components
   components
Easy and
clean API
Easy testable
Get more
implemented
in less time
You will
get addicted
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
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/

More Related Content

What's hot

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
Fabien Potencier
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
Fabien Potencier
 

What's hot (20)

Perl6 grammars
Perl6 grammarsPerl6 grammars
Perl6 grammars
 
Bouncingballs sh
Bouncingballs shBouncingballs sh
Bouncingballs sh
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
Perl 6 by example
Perl 6 by examplePerl 6 by example
Perl 6 by example
 
Session8
Session8Session8
Session8
 
I, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 OverlordsI, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 Overlords
 
The Magic Of Tie
The Magic Of TieThe Magic Of Tie
The Magic Of Tie
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
Php Enums
Php EnumsPhp Enums
Php Enums
 
PHP 5.4
PHP 5.4PHP 5.4
PHP 5.4
 
Hidden treasures of Ruby
Hidden treasures of RubyHidden treasures of Ruby
Hidden treasures of Ruby
 
Perl5i
Perl5iPerl5i
Perl5i
 
PHP 8.1: Enums
PHP 8.1: EnumsPHP 8.1: Enums
PHP 8.1: Enums
 
8時間耐久CakePHP2 勉強会
8時間耐久CakePHP2 勉強会8時間耐久CakePHP2 勉強会
8時間耐久CakePHP2 勉強会
 
Perl Bag of Tricks - Baltimore Perl mongers
Perl Bag of Tricks  -  Baltimore Perl mongersPerl Bag of Tricks  -  Baltimore Perl mongers
Perl Bag of Tricks - Baltimore Perl mongers
 
Advanced modulinos trial
Advanced modulinos trialAdvanced modulinos trial
Advanced modulinos trial
 
London XQuery Meetup: Querying the World (Web Scraping)
London XQuery Meetup: Querying the World (Web Scraping)London XQuery Meetup: Querying the World (Web Scraping)
London XQuery Meetup: Querying the World (Web Scraping)
 
ภาษา C
ภาษา Cภาษา C
ภาษา C
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 

Viewers also liked

2012 08-11-flow3-northeast-php
2012 08-11-flow3-northeast-php2012 08-11-flow3-northeast-php
2012 08-11-flow3-northeast-php
Jochen Rau
 
TYPO3 5.0 - Der aktuelle Stand der Zukunft
TYPO3 5.0 - Der aktuelle Stand der ZukunftTYPO3 5.0 - Der aktuelle Stand der Zukunft
TYPO3 5.0 - Der aktuelle Stand der Zukunft
Jochen Rau
 

Viewers also liked (6)

2012 08-11-flow3-northeast-php
2012 08-11-flow3-northeast-php2012 08-11-flow3-northeast-php
2012 08-11-flow3-northeast-php
 
Semantic TYPO3
Semantic TYPO3Semantic TYPO3
Semantic TYPO3
 
Extbase and Beyond
Extbase and BeyondExtbase and Beyond
Extbase and Beyond
 
Future Challenges for TYPO3
Future Challenges for TYPO3Future Challenges for TYPO3
Future Challenges for TYPO3
 
The Web as Application Platform Driven by Semantic Technologies
The Web as Application Platform Driven by Semantic TechnologiesThe Web as Application Platform Driven by Semantic Technologies
The Web as Application Platform Driven by Semantic Technologies
 
TYPO3 5.0 - Der aktuelle Stand der Zukunft
TYPO3 5.0 - Der aktuelle Stand der ZukunftTYPO3 5.0 - Der aktuelle Stand der Zukunft
TYPO3 5.0 - Der aktuelle Stand der Zukunft
 

Similar to Get into the FLOW with Extbase

C A S Sample Php
C A S Sample PhpC A S Sample Php
C A S Sample Php
JH Lee
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2
ady36
 
Operation Oriented Web Applications / Yokohama pm7
Operation Oriented Web Applications / Yokohama pm7Operation Oriented Web Applications / Yokohama pm7
Operation Oriented Web Applications / Yokohama pm7
Masahiro Nagano
 
R57shell
R57shellR57shell
R57shell
ady36
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
elliando dias
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Masahiro Nagano
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
elliando dias
 
Propel sfugmd
Propel sfugmdPropel sfugmd
Propel sfugmd
iKlaus
 
Pgm2_UpgradeReport_FilesUpgradeReport.cssBODY{BACKGRO.docx
Pgm2_UpgradeReport_FilesUpgradeReport.cssBODY{BACKGRO.docxPgm2_UpgradeReport_FilesUpgradeReport.cssBODY{BACKGRO.docx
Pgm2_UpgradeReport_FilesUpgradeReport.cssBODY{BACKGRO.docx
mattjtoni51554
 

Similar to Get into the FLOW with Extbase (20)

TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase framework
 
C A S Sample Php
C A S Sample PhpC A S Sample Php
C A S Sample Php
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2
 
Blog Hacks 2011
Blog Hacks 2011Blog Hacks 2011
Blog Hacks 2011
 
Operation Oriented Web Applications / Yokohama pm7
Operation Oriented Web Applications / Yokohama pm7Operation Oriented Web Applications / Yokohama pm7
Operation Oriented Web Applications / Yokohama pm7
 
R57.Php
R57.PhpR57.Php
R57.Php
 
logic321
logic321logic321
logic321
 
Drupal Development (Part 2)
Drupal Development (Part 2)Drupal Development (Part 2)
Drupal Development (Part 2)
 
R57shell
R57shellR57shell
R57shell
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
 
Let's write secure drupal code!
Let's write secure drupal code!Let's write secure drupal code!
Let's write secure drupal code!
 
InnoDB Magic
InnoDB MagicInnoDB Magic
InnoDB Magic
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
 
Let's write secure Drupal code! - DrupalCamp Oslo, 2018
Let's write secure Drupal code! - DrupalCamp Oslo, 2018Let's write secure Drupal code! - DrupalCamp Oslo, 2018
Let's write secure Drupal code! - DrupalCamp Oslo, 2018
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
Propel sfugmd
Propel sfugmdPropel sfugmd
Propel sfugmd
 
Pgm2_UpgradeReport_FilesUpgradeReport.cssBODY{BACKGRO.docx
Pgm2_UpgradeReport_FilesUpgradeReport.cssBODY{BACKGRO.docxPgm2_UpgradeReport_FilesUpgradeReport.cssBODY{BACKGRO.docx
Pgm2_UpgradeReport_FilesUpgradeReport.cssBODY{BACKGRO.docx
 

Recently uploaded

TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc
 
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
panagenda
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
FIDO Alliance
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
FIDO Alliance
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
FIDO Alliance
 

Recently uploaded (20)

Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
 
JavaScript Usage Statistics 2024 - The Ultimate Guide
JavaScript Usage Statistics 2024 - The Ultimate GuideJavaScript Usage Statistics 2024 - The Ultimate Guide
JavaScript Usage Statistics 2024 - The Ultimate Guide
 
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
 
Design and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data ScienceDesign and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data Science
 
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
 
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM Performance
 
ChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps Productivity
 
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe
 
Design Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptxDesign Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptx
 
UiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overviewUiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overview
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream Processing
 
How to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cfHow to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cf
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
 
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsContinuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
 
State of the Smart Building Startup Landscape 2024!
State of the Smart Building Startup Landscape 2024!State of the Smart Building Startup Landscape 2024!
State of the Smart Building Startup Landscape 2024!
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
 

Get into the FLOW with Extbase

  • 1. Get into the FLOW with Extbase http://www.sxc.hu/photo/768249
  • 6.
  • 7. 6O% selfemployed 6O% father
  • 9. 5 years: Fraunhofer- Gesellschaft German Aerospace Center
  • 11. What is Extbase all about?
  • 12. 1997
  • 14. v4
  • 16. v5 v4
  • 17. v5 v4
  • 18. v5 v4
  • 19. Extbase v5 v4
  • 20. v5 v4
  • 21. What is Extbase all about?
  • 23. What is Extbase all about?
  • 25. OOP A ggregate DDD Extbase V iew Entity H elp er M VC VfB R epository
  • 27. 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)
  • 29. 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
  • 30. ! /** ! * 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:
  • 31. ! /** ! * 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']));
  • 32. '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-
  • 33.
  • 34. control flow business logic CRUD data render output other , eg. config
  • 35. control flow business logic aggregate CRUD data render output other , eg. config
  • 36. control flow business logic generalize CRUD data render output other , eg. config
  • 38. Extbase use & Fluid
  • 39.
  • 40. control flow business logic CRUD data render output other , eg. config
  • 42. 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
  • 43. 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
  • 44. 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
  • 45. TYPO3
  • 46. tslib_piBase tx_blog 1 userFunc TYPO3 tx_blog_pi
  • 47. tslib_piBase tx_blog 1 userFunc 2 exec_SELECTgetRows TYPO3 tx_blog_pi Database
  • 48. tslib_piBase tx_blog 1 userFunc 2 exec_SELECTgetRows TYPO3 tx_blog_pi rows as Database array 3
  • 49. tslib_piBase tx_blog 1 userFunc 2 exec_SELECTgetRows TYPO3 tx_blog_pi HTML rows as Database 4 array 3
  • 50. 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); }
  • 51. 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###');
  • 52. 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; }
  • 53. 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 -->
  • 54. 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 }
  • 55. 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]
  • 56. 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 ! ); }
  • 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' ! ); [...]
  • 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
  • 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=' . $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;
  • 60. 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"
  • 61. 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"
  • 62. 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"
  • 63. http://www.sxc.hu/photo/516864/ Extension building with Extbase
  • 64. TYPO3
  • 65. 1 userFunc Extbase TYPO3 Dispatcher
  • 66. 1 2 userFunc Request BlogExample Extbase TYPO3 Dispatcher Controller
  • 67. 1 2 userFunc Request BlogExample Extbase TYPO3 Dispatcher Controller 3 findByTitle('MyBlog') Repository Domain Model Blog Post Comment Tag
  • 68. 1 2 userFunc Request BlogExample Extbase TYPO3 Dispatcher Controller 3 findByTitle('MyBlog') Blog 4 Repository Domain Model Blog Post Comment Tag
  • 69. 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
  • 70. 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
  • 71. 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
  • 72. Blog Post Comment Tag
  • 73. Model
  • 74. /** * 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 = '';
  • 75. ! } ! /** ! * 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;
  • 76. ! * @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; ! } }
  • 77. /** * 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
  • 78. ! * @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); ! } }
  • 80. /** * 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()); ! }
  • 81. ! } ! /** ! * 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'); ! }
  • 84. Model Blog Post Comment Tag
  • 85. Model BlogRepository Blog Post Comment Tag
  • 86. /** * 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; ! } }
  • 87. /** * A repository for Blogs */ class Tx_BlogExample_Domain_Repository_BlogRepository extends Tx_Extbase_Persistence_Repository { ! }
  • 88. /** * 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) {
  • 89. ! * @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(); ! } }
  • 90. 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*
  • 91. Blog Post Comment Tag
  • 92. Aggregate Blog Post Comment Tag
  • 93. Blog Entity Post Comment Tag
  • 94. Blog Entity Post Value Object Comment Tag
  • 95. Aggregate Root Blog Entity Post Value Object Comment Tag
  • 96. Aggregate getLatestComment() Root Blog Post Comment Tag
  • 97. Aggregate getLatestComment() Root Blog Post Comment Tag
  • 98. Aggregate getLatestComment() Root Blog Post Comment Tag
  • 99. <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>
  • 100. 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
  • 101. */ 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
  • 102. Controlle r odel Do main / M View Con fig ura tio n
  • 103. 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
  • 105. 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
  • 106.
  • 107. - Modern architecture
  • 113. 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
  • 114. 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/