The Future of Extension Development

Transcription

The Future of Extension Development
The Future of Extension Development
New MVC framework “Extbase” paves the way from 4.x to FLOW3
The next TYPO3 version and its newly developed basis called FLOW3 will severely change the way in which
people develop for TYPO3. Version 5 will only be available for productive use in a few months though. The
new framework Extbase is part of TYPO3 version 4.3 and later. With its help developers can already program
their extensions in the style of version 5 today. We show you what Extbase can do and how the framework
actually functions. ↘ Jochen Rau
In October 2008 the “Transition Days” took place in Berlin. There the
members of the TYPO3 core team finished the work on a mutual
vision and strategy for the transition of the current version 4.x to
version 5. One of the results of this very productive meeting was
the decision to develop a successor of the basis class “tslib piBase”,
on which the majority of the over 3.600 extensions are based. An
important goal for the development of the new extension framework is closing the gap between the current branch and version 5
while staying as close as possible to the ideas, the architecture and
the interfaces of FLOW3. On the following pages we will take a look
on how it is possible to shape the future of extensions with Extbase
from three different perspectives - first from the perspective of the
contractor, then with the help of an example of the core of an extension and finally we take a look behind the scenes of the framework. Auf den folgenden Seiten blicken wir aus drei verschiedenen
Richtungen darauf, wie man in Zukunft Extensions mit Extbase entwickelt. Zunächst aus der Perspektive des „Auftraggebers“, dann
anhand eines Beispiels aus dem Inneren einer Extension, abschließend blicken wir hinter die Kulissen des Frameworks.
publishing date and so on. A post can be assigned tags and the
visitors of the blog have the possibility to post comments. Accordingly, a blog consists of an aggregate of objects (blog, post,
comment, tag), which are kept in a sort of tree structure. This tree
structure has exactly one object as its root (aggregate root).
Please Concentrate!
Successful software projects are often characterized by a mutual
learning process: Developers learn to move within the mental and
linguistic domain of the contractor while the contractor follows the
code and learns if the structure and business policy of his domain
were implemented correctly. This makes a “ubiquitous language”
between the participants a must.
The domain of the contractor is translated into abstract software objects - the so called “domain model” - during this mutual
learning process [1]. Objects that do not belong to the domain model are all those which are responsible for saving, finding, validating,
filtering and displaying data. These are taken out of the extension
nearly completely and sourced out to Extbase.
Eric Evans coined the name “domain driven design” for this development process [2] [3]. The big advantage can be found in a
natural concentration on the essence: the benefit for the contractor.
Extbase has been built around the concept of domain driven design
and supports this procedure in an optimal way and without limiting
the developer to this approach.
The extension “BlogExample” is an example for a simple domain
model which can be downloaded freely from the TYPO3 Extension
Repository as an example of use for Extbase [4]. The domain model
of this exemplary extension looks as follows: A blog (of which several versions can exist) has a name and a description. It includes
several posts and every single post has an author, a title, content, a
1
The domain model of the exemplary extension “BlogExample”.
Access to all included libraries (post, comments and tags) takes
place via the root object. A direct readout of a single tag from the
database for example is not necessary (and not allowed). The root
objects are managed via specific objects called “repositories”, which
we will deal with later on. Let us first take a look on the blog class
though:
PHP
1 class Tx_BlogExample_Domain_Model_Blog extends
Tx_Extbase_DomainObject_AbstractEntity {
2
3
protected $name = '';
4
protected $description = '';
5
protected $logo;
6
protected $posts = array();
7
8
public function setName($name) {
9
$this->name = $name;
10
}
11
12
public function getName() {
13
return $this->name;
14
}
15
16
public function setDescription($description) {
17
$this->description = $description;
18
}
© yeebase 2009. Publication and reproduction only with approval by yeebase media GbR. t3n.yeebase.com
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public function getDescription() {
return $this->description;
}
public function addPost(Tx_BlogExample_Domain_Model_Post $post) {
$this->posts[$post->getUid()] = $post;
}
public function removePost(Tx_BlogExample_Domain_Model_Post
$postToRemove) {
foreach ($this->posts as $uid => $post) {
if ($post === $postToRemove) {
unset($this->posts[$uid]);
}
}
}
[...]
public function findPostsByTag($tag) {
$foundPosts = array();
foreach ($this->posts as $post) {
foreach ($post->getTags() as $postTag) {
if (strtolower($postTag) === strtolower($tag)) {
$foundPosts[] = $post;
break;
}
}
}
return $foundPosts;
}
[...]
them to the object of the class “View” which is responsible for the
output (5). This specialized object independently cares for the
transformation of the file to the desired form (usually HTML code
on the basis of a pattern). The completed content is output as a
“response” via the controller to TYPO 3 (6).
This reasonable separation of responsibilities and the chronology of the information flow which is based on the former is called
“model-view-controller” pattern (MVC pattern) because of the three
classes involved.
}
Listing 1
The blog class is deduced from a generic domain object called “AbstractEntity-Object” (row 1). This provides methods for the management and monitoring of the internal state of the object
amongst other things.
All properties of the object are
labeled as “protected” (row
3-6) and they can be accessed
exclusively via “getter”- and
“setter”-methods (row 8-22).
Post objects are stored under
their UID in an array (row
24-26). The method for deleting a post is a bit more complex because the object identity needs to be verified (row
28-34). The method “findPostsByTag()” shows the possibility to navigate from the root
object “Blog” to the “Tag” obThe new directory structure of an exject on the third hierarchical letension.
vel as mentioned above (row
36-47). It is noteworthy that the
argument “Stag” is assigned as a string and compared to the tag
object in “$postTag”. This is possible because the “Tag” object is
converted to a string via its method “toString ()“.
And Action!
Now the domain model is in the right folder on the server in the
form of individual class files. But how can you put this new file
structure to action? The correct objects which are filled with the
correct data need to be called for at the correct time in order to
output them in the desired format.
A specific class of objects, the “controllers” have the control over
this operation. A controller accesses the domain objects from the
repositories according to its “request” - (3) und (4) – and forwards
Simplified cycle through an extension.
The procedure of the single steps to clarify the process:
1. TYPO3 processes the page content and “finds” the plugin on
the page. It does not call the extension directly but rather passes
control to the “dispatcher” of Extbase. The dispatcher decides
which combination of controller and action should take over
the action based on the configuration passed on by TYPO3 and
the $_GET/$_POST parameter.
2. The dispatcher passes all information which is necessary for the
control of the process to the responsible controller. The controller internally executes the according action („Action“) in the
form of a method.
3. The responsible repository is requested within the action method. This happens with the help of a “find” method (see table
below).
4. The repository delivers a completely built domain object. This
is an instance of the class “Blog” in our example. This blog object
already contains all associated post-, comment- and tag objects
(in order to calm down all experts; lazy loading will be supported in the future).
5. The action method allocates the blog object to the responsible
view object (assign()) and requests the creation of the content
in the desired format (render()).
6. View returns the created content within its response to the dispatcher, and the dispatcher passes it on to the superior TYPO3
rendering process.
It is noteworthy that this way through the extension does not call
any method which loads or saves an object from or to a database.
Therefor, it is not necessary to call the function „$blog->save()“ if
one has changed the blog during runtime. It is important to remember though that the object is managed via a repository. Extbase then automatically identifies changed properties of the object
and persists these after a run through the extension.
© yeebase 2009. Publication and reproduction only with approval by yeebase media GbR. t3n.yeebase.com
2
Excursion: The Repository
A repository is a hermaphrodite. It belongs to the domain but is only
part of the infrastructure (database connection) to a certain extent.
A repository functions similarly to a university library: One asks an
employee at the counter to find a book according to certain criteria.
After several minutes to days one gets the according book. The person
asking for a book does not care where exactly the book can be found
in the basement. It is neither important if the book is already behind
the counter, has to be fetched from the basement, needs to be requested from a different library via interlending or needs to be printed.
It is only important that the book is present physically at some point
in time. Annotations taken with a pencil will be taken over when returning the book (hopefully without any changes).
For a repository the analogy goes as follows: One assigns a method
to find an object based on certain criteria via a repository. After a few
milliseconds to seconds one gets the desired object. It makes no difference for the person asking for the object, where that object is saved.
It does not make a difference either if the object is already located in
the RAM, needs to be fetched from the hard drive, needs to be requested from a different server via web service or has to be instanced
for the first time. It is only important that the object is delivered as
an instance at some point in time. Changed properties of the object
need to be taken over when quitting the extension (hopefully without
any changes).
In order to find objects in the repository, one can take advantage
of some generic “find” methods. Complex requests can and must
be implemented by individual “find” methods.
Request
Functionality
$repository->findAll()
The repository delivers all objects of the managed class which are not labeled as deleted
or hidden.
$repository->findByFoo('bar')
The repository delivers all objects of the managed class which are not labeled as deleted
or hidden and whose property „$foo“ corresponds with the given value.
$repository->findOneByFoo('bar')
The same as findOneByFoo('bar'). But this
time only the first found object is returned.
The controllers have the central part in the course within an extension. Let us take a look at some selected actions of the BlogController of the exemplary extension (Listing 2).
PHP
1 class Tx_BlogExample_Controller_BlogController extends
Tx_Extbase_MVC_Controller_ActionController {
2
[...]
3
/**
4
* Index action for this controller. Displays a list of blogs.
5
* @return string The rendered view
6
*/
7
public function indexAction() {
8
$this->view->assign('blogs', $this->blogRepository->findAll());
9
}
10
[...]
11
/**
12
* Displays a form for creating a new blog
13
* @return string An HTML form for creating a new blog
14
*/
15
public function newAction() {
16
}
17
18
/**
19
* Creates a new blog
20
* @param string $name The name of the new blog
21
* @param string $description The description of the new blog
22
* @return void
23
* @validate $name Text, Length(maximum = 150)
24
*/
25
public function createAction($name, $description) {
3
26
$blog = t3lib_div::makeInstance('Tx_BlogExample_Domain_Model_Blog');
27
$blog->setName($name);
28
$blog->setDescription($description);
29
$this->blogRepository->add($blog);
30
$this->redirect('index');
31
}
32
[...]
33
/**
34
* Updates an existing blog
35
* @param int $blogUid The uid of the the existing, unmodified blog
36
* @param string $name The updated name of the blog
37
* @param string $description The updated blog description
38
* @return void
39
*/
40
public function updateAction($blogUid, $name, $description) {
41
$blog = $this->blogRepository->findOneByUid($blogUid);
42
$blog->setName($name);
43
$blog->setDescription($description);
44
$this->redirect('index');
45
}
46
[...]
47 }
Listing 2
The BlogController is deduced from the the framework classe
“ActionController” (row 1). This ensures amongst other things that
all arguments which are passed to actions are validated beforehand. At first instances of all existing blog objects are obtained
(findAll)) from the BlogRepository within the “indexAction()” (row
8). Afterwards these are passed to the view under the variable name
“blogs” (assign()). Since the method “render()” of the view is invoked
automatically, this single row of code creates a complete output of
a list of all blogs.
This is even more amazing in the “newAction()” which has the
function to show a form for the input of the new blog (row 11-16).
The method contains not a single line of code. The method outputs
the form nevertheless because Extbase has a certain “intelligence”
which automatically instances and invokes the correct view with
the according HTML template due to naming conventions.
The action “createAction()” (row 18-31)and the action “updateAction()” (row 33-45) only differ marginally on the first look. In row
25 validated arguments are already passed and their content had
been input in an HTML form. It was checked for example if the text
field “description” contained malicious script code before it was
passed on to the argument “$description”.
The rule for the validation is taken from the PHP comment above
the actual method (row 20,21 and 23 as well as 35-37) by Extbase.
“@param int $blogUid [...]“ for example tells Extbase that the value
needs to be of the type “integer”. More complex validation rules can
be state explicitly (“@validate [...]”).
By default “Fluid” is used as view in Extbase. Fluid is a completely
new template engine for TYPO 3 version 5, which has been ported
back to TYPO3 version 4.x as well. More about this powerful tool
can be find in the article by Sebastian Kurfürst in this edition of the
t3n magazine on page 124.
Holding The World Together From Within
The following part offers experienced developers a look behind the
scenes of the framework. Beginners can skip this part.
Extbase is based to a large extend on back ported FLOW3 code.
Where this was not possible, functionality had to be recreated. This
hold especially true for the content repository of FLOW3. Its functions are carried over to Extbase via an individual transparent
persistence layer. To achieve this, a persistence session is set up
(according to the “unit of work” pattern) in the dispatcher in which
all newly added, changed and deleted domain objects are registered. After the cycle through the extension the registered objects are
© yeebase 2009. Publication and reproduction only with approval by yeebase media GbR. t3n.yeebase.com
persisted with the help of an object relational mapper (ORM). The
ORM’s task is to translate between the hierarchical object structure
of the aggregate and the relational model of the database in both
directions. This especially includes the management of relations
tables for m:n relations and the capsulation of the metadata from
the &TCA into data- and column maps.
The registration of the changed properties of the domain objects as well as the reconstitution of an object from a database tulip
were some of the challenges. This problem was solved via the deduction of a domain object from abstract domain objects. This
makes it possible to set and read the properties which are labeled
as “protected”. In FLOW3 aspect oriented programming (AOP) is an
elegant tool for achieving this. In Exbase on the other hand, the
values of the properties are stored in an internal array as “clean
properties” shortly after the reconstruction. They are compare with
the actual values when committing the persistence session.
“Convention before configuration” is another important principle of Extbase (and of FLOW3 as well). By establishing naming
conventions and a corresponding folder structure the complexity
of the configuration of a frontend plugin could be reduced to two
lines of code.
New Bases
Some people may wonder which advantages Extbase developers have when programming extensions compared to the “conventional” method and which impacts and side effects the use of
Extbase poses.
Extbase purports a clear distinction between different responsibilities, which allows for an easy maintenance of the code and its
modular extensions. The modular nature lowers development time
for initial developments as well as adaptional developments. It also
lowers the costs for development. Extbase relieves the developer
when it comes to security- and recurrent tasks (validation of the
arguments, implementation of page templates, persistence of data,
reading of settings from TypoScript and FlexForms). All this empowers and comforts the developer to concentrate mostly on the tasks
and desires of the contractor.
Extensions which build up on Extbase can be ported to TYPO
v5 with a reasonable effort because the structure of the extension,
its naming conventions and the used interface definition (API) are
mostly the same.
A modern extension architecture and up-to-date software paradigms boost the appeal for new developers (even from the world
of Java). Extbase requires different know how then before. Qualifications are asked for which are not specific to TYPO3 but which
contribute to a broader qualification (for example in software architecture or quality management via software tests). The acquired
know how can be used for FLOW3 or other software projects without any problems though.
Extbase boosts the mental transition of TYPO3 developers by
allowing to accede the learning path to TYPO3 version 5 earlier than
it was possible before. This article might be your first step on this
path.
wants to thank everyone who have worked on Extbase over the last
few months for their commitment. “Inspire people to share!”. ↔
Links and Literature
[1]
[2]
[3]
[4]
[5]
[6]
↗ Softlink 2460
Lemke, Robert. Domain-Driven Design. t3n Magazin Nr. 11 (02/2008):
http://t3n.yeebase.com/magazin/domain-driven-designlosungsansatze-entwicklung-220511/
Vortrag von Eric Evans zu Domain-Driven Design: http://
www.infoq.com/presentations/model-to-work-evans
Eric Evans, Domain-Driven Design: tackling complexity in the heart of
software. 10. Aufl. Upper Saddle River, NJ: Addison-Wesley, 2007
Extbase-Dokumentation: http://typo3.org/extensions/repository/
view/doc_extbase/current/
Literatur-Tipps: http://flow3.typo3.org/documentation/books/
Mailingliste der TYPO3-Entwickler: http://lists.netfielders.de/cgi-bin/
mailman/listinfo/typo3-dev
The Author
Jochen Rau lives and works as a freelance
TYPO3 developer in Tübingen. Before he
joined the TYPO3 community, he worked
as a project manager in research with the
Fraunhofer Gesellschaft and the German
Zentrum für Luft- und Raumfahrt as well as
a teacher for mathematics, physics and
computer technics for several years. He is
an active member of the TYPO3 user group
Stuttgart and publishes articles about software development and TYPO3 regularly
on http://blog.typoplanet.de.
Please Embark!
Those interested in the new framework should deal with the exemplary extension and read the Extbase documentation [4]. Afterwards it could prove useful to study the basic literature to the used
paradigms [5]. If questions remain, one can contact the mailinglist
of the TYPO3 developers [6].
Shortly there will be a newly developed kick starter which completely supports the domain driven design. Finally, the author
© yeebase 2009. Publication and reproduction only with approval by yeebase media GbR. t3n.yeebase.com
4