+ All Categories
Home > Technology > Get into the FLOW with Extbase and TYPO3 4.3

Get into the FLOW with Extbase and TYPO3 4.3

Date post: 06-May-2015
Category:
Upload: sebastian-kurfuerst
View: 14,658 times
Download: 3 times
Share this document with a friend
Description:
Slides of the presentation on Extbase on T3DD09. Extbase is a new Extension framework for TYPO3 backporting great features from FLOW3 - Domain Driven Design and Model View Controller. The video of this presentation can be found at http://t3dd09.typo3.org/recordings.html
97
Inspiring people to share T3DD09 Get into FLOW with Extbase
Transcript
Page 1: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshare

T3DD09

Get into FLOW with Extbase

Page 2: Get into the FLOW with Extbase and TYPO3 4.3

Get into the FLOW with Extbase

Jochen Rau <[email protected]>Sebastian Kurfürst <[email protected]>

with contributions by Oliver Hader

15.05.2009

Page 3: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Topictext

Who is that?

Dipl.-Ing. Mechanical Engineering (Stuttgart University)

infected with TYPO3 in 2001 (after that: 5 years of immunity)

today living and working in Tübingen

60% self-employed TYPO3-developer (since 2007)

60% father of a family (since 2003 ;-) )

before that

5 years: researcher at the Fraunhofer-Gesellschaft and the German Aerospace Center

Page 4: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

- WARNING -TYPO3 addict

Page 5: Get into the FLOW with Extbase and TYPO3 4.3

The current stateof the art

http://commons.wikimedia.org/wiki/File:Z%C3%BCrich_-_Seefeld_-_Heureka_IMG_1757.JPG

Page 6: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

The current state of the art

FEPlugin

Database tables

dispatches callsfetches data

renders outputResources

templatesJavaScript/CSS

imagesextends tslib_pibase TypoScript

FrontendExtension

Page 7: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

File structure

Page 8: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

A new extension: Blogging with TYPO3

define features of the new blogging application

implement the business logic

define the look and feel

take a look at security issues

Page 9: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

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

Page 10: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Blog

Post

Comment Tag

Page 11: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Blog business logicpublic function main($content, $conf) { $this->conf = $conf; $this->pi_setPiVarDefaults(); $this->pi_loadLL();

if ($this->piVars['postUid']) { if ($this->piVars['newComment']) { $this->storeNewComment(); } $content = $this->renderPost(); } elseif ($this->piVars['blogUid']) { $content = $this->renderBlog(); } else { $content = $this->renderListOfBlogs(); } return $this->pi_wrapInBaseClass($content);}

Page 12: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Task 1: Output a listing of blogs

fetch available blogs from database

implement a new method „renderListOfBlogs()“

protected function renderListOfBlogs() { $blogs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( '*', 'tx_blogexample_blog', 'deleted=0 AND hidden=0 AND sys_language_uid=' .

$GLOBALS['TSFE']->sys_language_uid . $this->cObj->enableFields('tx_blogexample_blog'), '', 'name' );

...

Page 13: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Task 1: Output a listing of blogs

iterate through all blogs and render them

... $template = $this->cObj->fileResource($this->conf['template']); $blogElementSubpart = $this->cObj->getSubpart($template, '###SUBPART_BLOGELEMENT###');

$blogs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(...); foreach ($blogs as $blog) { $linkParameters = array('blogUid' => $blog['uid']); $markers = array( '###BLOG_NAME###' => $blog['name'], '###BLOG_LOGO###' => $this->cImage('uploads/tx_blog/' . $blog['logo']), '###BLOG_DESCRIPTION###' => $this->pi_RTEcssText($blog['description']), '###BLOG_MORELINK###' => $this->pi_linkTP('show blog', $linkParameters, true), ); $blogElements.= $this->cObj->substituteMarkerArray($blogElementSubpart, $markers); } return $content;}

Page 14: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Task 1: Output a listing of blogs

create the template with markers and subparts

<!-- ###SUBPART_BLOGELEMENT### begin --><div class="blog element"> ###BLOG_NAME### ###BLOG_LOGO### ###BLOG_DESCRIPTION### ###BLOG_MORELINK###</div><!-- ###SUBPART_BLOGELEMENT### end -->

Page 15: Get into the FLOW with Extbase and TYPO3 4.3
Page 16: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Task 2: Display a single post with its comments

implement a new method „renderPost()“protected function renderPost() { $post = $this->pi_getRecord('tx_blogexample_post', $this->piVars['postUid']); $comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( '*', 'tx_blogexample_comment', 'deleted=0 AND hidden=0 AND sys_language_uid=' .

$GLOBALS['TSFE']->sys_language_uid . ' AND post_uid=' . $this->piVars['postUid'] . ' AND post_table="tx_blogexample_post"' . $this->cObj->enableFields('tx_blogexample_comment'), '', 'date DESC' );

// fill marker arrays and substitute in template// return content

}

Page 17: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Task 3: Add a new comment to a blog post

the whole plugin is cached („USER“)

dynamic user input won‘t be handled by the rendering when cached

define uncached behavior in TypoScript

[globalVar = _POST:tx_blogexample_pi1|newComment = 1] plugin.tx_blogexample_pi1 = USER_INT[global]

Page 18: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Task 3: Add a new comment to a blog post

store new comment in database

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

$GLOBALS['TYPO3_DB']->exec_INSERTquery( 'tx_blogexample_comment', $fields );}

Page 19: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Take a look at security issues

possibility of SQL injections

unvalidated information submitted by a user

is there really a mail address where it was expected?

are integers really integers?

malicious information submitted by a user (XSS)

is there a possibility to inject JavaScript code?

Page 20: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Security: SQL injections

unescaped or unchecked values that are transferred to the database directly$comments = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*','tx_blog_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_blog_post"' .$this->cObj->enableFields('tx_blog_comment'));

with &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_blog_post“ ...

Page 21: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

The current state of the art

Security: SQL injections - solution

always escape or cast variables from outside

' AND post_uid=' . intval($this->piVars['postUid']) . ' AND post_table="tx_blog_post"' .

Page 22: Get into the FLOW with Extbase and TYPO3 4.3
Page 23: Get into the FLOW with Extbase and TYPO3 4.3

Spaghetti codeLasagna code

Hmmm.Much better.

Page 24: Get into the FLOW with Extbase and TYPO3 4.3
Page 25: Get into the FLOW with Extbase and TYPO3 4.3
Page 26: Get into the FLOW with Extbase and TYPO3 4.3
Page 27: Get into the FLOW with Extbase and TYPO3 4.3
Page 28: Get into the FLOW with Extbase and TYPO3 4.3
Page 29: Get into the FLOW with Extbase and TYPO3 4.3
Page 30: Get into the FLOW with Extbase and TYPO3 4.3

Extension Framework

Page 31: Get into the FLOW with Extbase and TYPO3 4.3

Extension Framework

Page 32: Get into the FLOW with Extbase and TYPO3 4.3
Page 33: Get into the FLOW with Extbase and TYPO3 4.3

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

Extension buildingwith ExtbaseHow to build a typo3

v4 based app

Page 34: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Blog

Post

Comment Tag

Page 35: Get into the FLOW with Extbase and TYPO3 4.3

http://www.flickr.com/photos/bunchofpants/106465356/sizes/o/

The model is arepresentation of

reality.

Page 36: Get into the FLOW with Extbase and TYPO3 4.3

Model

Page 37: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

class Tx_BlogExample_Domain_Model_Blog extends Tx_Extbase_DomainObject_AbstractEntity {

// Comments are missing protected $name = ''; protected $description = ''; protected $logo; protected $posts = array();

public function setName($name) { $this->name = $name; } public function getName() { return $this->name; }

public function addPost(Tx_BlogExample_Domain_Model_Post $post) { $this->posts[] = $post; } public function removeAllPosts() { $this->posts = array(); }

/** * Returns all posts in this blog * * @return array of Tx_BlogExample_Domain_Model_Post */ public function getPosts() { return $this->posts; }

Inspiring people toshareGet into FLOW with Extbase

Page 38: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

class Tx_BlogExample_Domain_Model_Comment extends Tx_Extbase_DomainObject_AbstractEntity {

protected $date; protected $author; protected $email; protected $content;

public function __construct() { $this->date = new DateTime(); }

public function setDate(DateTime $date) { $this->date = $date; }

public function getDate() { return $this->date; }

public function setAuthor($author) { $this->author = $author; }

public function getAuthor() { return $this->author; }

public function setEmail($email) { $this->email = $email; }

public function getEmail() { return $this->email; }

public function setContent($content) { $this->content = $content; }

public function getContent() { return $this->content; }}

Inspiring people toshareGet into FLOW with Extbase

Page 39: Get into the FLOW with Extbase and TYPO3 4.3

Model classes are POPOs (almost)

POPO = Plain Old PHP Object

Page 40: Get into the FLOW with Extbase and TYPO3 4.3

domain object encapsulates data + behavior

Page 41: Get into the FLOW with Extbase and TYPO3 4.3
Page 42: Get into the FLOW with Extbase and TYPO3 4.3

and...

action

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

Page 43: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase

Task 1: Output a listing of blog postings

You want to output the postings of a predefined blog.

public function showAction() { $blogUid = 1; // get blog by UID // render blog}

Page 44: Get into the FLOW with Extbase and TYPO3 4.3

How could you get a blog?

Page 45: Get into the FLOW with Extbase and TYPO3 4.3

How could you get a book?

Page 46: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Blog

Post

Comment Tag

Extension building with Extbase - Blog Example

ModelBlogRepository

Page 47: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Repositories

Encapsulate all data access

SQL is allowed only in the Repository

Magic methods: findBy*, findOneBy*

Page 48: Get into the FLOW with Extbase and TYPO3 4.3

Extension building with Extbase - Blog Example

Repositories

class Tx_BlogExample_Domain_Model_BlogRepository extends Tx_Extbase_Persistence_Repository {}

Page 49: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Task 1: Output a listing of blog postings

You want to output the postings of a predefined blog.

public function showAction() { $blogUid = 1; $blog = $this->blogRepository->findOneByUid($blogUid); // render blog}

Page 50: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Task 1: Output a listing of blog postings

You want to output the postings of a predefined blog.

public function showAction() { $blogUid = 1; $blog = $this->blogRepository->findOneByUid($blogUid); $this->view->assign('blog', $blog); return $this->view->render(); // can be omitted}

Page 51: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Task 1: Output a listing of blog postings

Inside the template:

<h1>Welcome to {blog.name}</h1>

<f:for each="{blog.posts}" as="singlePost"> <h1>{singlePost.title}</h1> <f:link controller="Post" action="show" arguments="{post : singlePost}">read more </f:link></f:for>

Page 52: Get into the FLOW with Extbase and TYPO3 4.3
Page 53: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Task 2: Display a single blog post

Display a post with comments

public function showAction() { // Get the post // Pass post to view so it can be rendered}

Page 54: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Task 2: Display a single blog post

/** * Display a post * * @param Tx_Blog_Domain_Model_Post $post The post to show */public function showAction(Tx_Blog_Domain_Model_Post $post) { // Pass post to view so it can be rendered}

Page 55: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Arguments

All arguments must be registered.

Registration of expected arguments happens through defining them as method parameters.

PHPDoc is mandatory as it is used for data type validation

Page 56: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Arguments - more advanced

/** * Action that displays one single post * * @param string $title Title of the post * @param string $content Content of the post * @validate $title Length(maximum=100) * @return string The rendered view */public function createAction($title, $content) {}

Do additional validation

Page 57: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Task 2: Display a single blog post

/** * Display a post * * @param Tx_Blog_Domain_Model_Post $post The post to show */public function showAction(Tx_Blog_Domain_Model_Post $post) { $this->view->assign('post', $post);}

Page 58: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Task 2: Display a single blog post - template

Page 59: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase - Blog Example

Task 3: Add a new comment

a new comment needs to be stored for a given post

1. Create the template

2. Add the comment in the controller

Page 60: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

<f:form name="comment" method="post" controllerName="Comment" actionName="create" object="{comment}" arguments="{post : post}"> <h4>Add your own</h4> <label for="author">name <span class="required">(required)</span></label><br /> <f:form.textbox id="author" property="author" /> <br /> <label for="email">email <span class="required">(required)</span></label><br /> <f:form.textbox id="email" property="email" /> <br /> <label for="text">message <span class="required">(required)</span></label><br /> <f:form.textarea id="text" property="content" rows="8" cols="46"/> <br /> <f:form.submit>Say it</f:form.submit></f:form>

Page 61: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

/** * Action that adds a comment to a blog post and redirects to single view * * @param Tx_BlogExample_Domain_Model_Post $post The post the comment is related to * @param Tx_BlogExample_Domain_Model_Comment $comment The comment to create * @return void */ public function createAction(Tx_BlogExample_Domain_Model_Post $post, Tx_BlogExample_Domain_Model_Comment $comment) { $post->addComment($comment); $this->redirect('show', 'Post', NULL, array('post' => $post)); }

<f:form name="comment" method="post" controllerName="Comment" actionName="create" object="{comment}" arguments="{post : post}">

Page 62: Get into the FLOW with Extbase and TYPO3 4.3

ExtbaseDispatcher

Controller

Repository View

Request

findByName('MyBlog')

Response

Blog

assign(Blog)

Response

TYPO3

Domain Model

HTML

render()

userFunc

12

3

4

5

6

Blog

Post

Comment Tag

BlogExample

Page 63: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Extension building with Extbase

Controller

Controllers contain actions: *Action

all controllers inherit from Tx_Extbase_MVC_Controller_ActionController

Default action: indexAction

Page 64: Get into the FLOW with Extbase and TYPO3 4.3

Model

View

Other Stuff

Controller

Page 65: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Persistence

Page 66: Get into the FLOW with Extbase and TYPO3 4.3

Blog

Post

Comment Tag

Aggregate RootgetLatestComment()

Page 67: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Persistence

adding a blog

the blog is an aggregate root

Now, the Blog is a managed object - changes are now automatically persisted!

Persistent objectsBlogRepository

Blog$blogRepository->add(Blog $blog);

Page 68: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

PostRepository

Comment is no aggregate root

Thus, Comment is automatically persisted

Persistence

adding a comment

Persistent objects

Comment

PostPost

Page 69: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Persistence

Transparent object persistence

All objects (and their child-objects) managed by a repository are automatically persisted

changes to these objects are automatically persisted

Page 70: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Page 71: Get into the FLOW with Extbase and TYPO3 4.3

Domain Driven Design

Page 72: Get into the FLOW with Extbase and TYPO3 4.3

Domain describes activity or business of user.

Page 73: Get into the FLOW with Extbase and TYPO3 4.3

Ubiquitous LAnguage

Page 74: Get into the FLOW with Extbase and TYPO3 4.3

Blog

Post

Comment Tag

ValueObject

Entity

Page 75: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Core concepts - Domain Driven Design

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

bbjects represent things in the real world, with their attributes and behavior

ubiquitous language

building blocks

Entity

Value Objects

Repositories

Page 76: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Why should you use DDD?

Page 77: Get into the FLOW with Extbase and TYPO3 4.3

Build complexSQL queries

Implement application logic

Mix PHP and HTML templateto build a template-based

layout

Read lots of TypoScriptand core API docs

Build frontend formswith error handling

Care about securityadapt to the coding style,structure and thinking of

different developers

Page 78: Get into the FLOW with Extbase and TYPO3 4.3

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

Page 79: Get into the FLOW with Extbase and TYPO3 4.3

Implement application logic

Page 80: Get into the FLOW with Extbase and TYPO3 4.3

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

Flow [flō] is the mental state of operation in which the person is fully immersed in what he or she is doing by a feeling of energized focus, full involvement, and success in the process of the activity.

Page 81: Get into the FLOW with Extbase and TYPO3 4.3
Page 82: Get into the FLOW with Extbase and TYPO3 4.3
Page 83: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Outlook

Page 84: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Outlook

Availability and documentation

Extbase will be included in TYPO3 4.3

full-blown replacement for pibase

new preferred way to write extensions

futureproof, with concepts of FLOW3

Currently no documentation, but will be available with the final release

Page 85: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Outlook

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

Page 86: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Resources and links

Project web site: http://forge.typo3.org/projects/show/typo3v4-mvc

SVN: https://svn.typo3.org/TYPO3v4/CoreProjects/MVC/

we will provide documentation until the release of TYPO3 4.3

First release with TYPO3 4.3 alpha3: http://typo3.org/download/packages/

Page 87: Get into the FLOW with Extbase and TYPO3 4.3

Inspiring people toshareGet into FLOW with Extbase

Conclusion

Page 88: Get into the FLOW with Extbase and TYPO3 4.3

Greatly reusablecomponents

+

Page 89: Get into the FLOW with Extbase and TYPO3 4.3

Easy and consistent API

+

Page 90: Get into the FLOW with Extbase and TYPO3 4.3

Easily testable+

Page 91: Get into the FLOW with Extbase and TYPO3 4.3

Needs initiallearning time

-

Page 92: Get into the FLOW with Extbase and TYPO3 4.3

Extensionsneed proper

planning

-

Page 93: Get into the FLOW with Extbase and TYPO3 4.3

You willget addicted

-

Page 94: Get into the FLOW with Extbase and TYPO3 4.3

Feel the flowin TYPO3 v4

Page 95: Get into the FLOW with Extbase and TYPO3 4.3

Christopher Hlubek

Niels Pardon

Bastian Waidelich

Benjamin Mack

Ingmar Schlecht

and the TYPO3 V5 Team for all the inspiration and the beautiful code

Thank You

Page 96: Get into the FLOW with Extbase and TYPO3 4.3

?????????????

Page 97: Get into the FLOW with Extbase and TYPO3 4.3

inspiring people to share.


Recommended