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