Thursday, December 19, 2013

Final day: some observations about extension building with Extension Builder and Extbase

We've arrived at the last week of the Hackership, and my goal this week was to master get pretty good at PHPUnit testing. To that end, I'm creating mock objects to test interactions in my "Organization" class with classes that have not yet been implemented. I ran into a tricky problem with this, in that the "magic" that Extbase is supposed to conjure in the following line:

/**
 * Contacts of Organization
 * 
 * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\YouthAct\Domain\Model\Person>
 *
 */
protected $contacts;

doesn't actually work. Trying to use "contacts" later in the class leads to the fatal error "Call to member-function on a non-object". Thanks to a lot of help from one of the Hackership organizers, we found out that the "initStorageObjects" function, which instantiates the related objects, isn't complete:

protected function initStorageObjects() {
$this->contacts = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}

public function __construct() {
$this->initStorageObjects();
//if you don't add this following line of code, Extbase magic suffers an epic fail:
$this->setContacts($contacts);
}

This kind of sucks. But at least now I don't get any more fatal errors: just errors about problems with my code. This is a good thing - this is how we learn! Using mock-objects allows me to test interactions of the class I'm testing with classes that haven't yet been implemented. This is a great alternative to creating a bunch of skeleton classes and wiring them up together. Additionally, using mock-objects to imitate the behavior of classes within an aggregate root makes for lean, strict and correct PHPUnit tests.

This week I built an Extension from mostly scratch, based on two domain-entities created with Extension Builder and implemented test-first with PHPUnit tests. Writing a hundred tests for getters and setters can lead to catatonia, so I decided to "see what would happen" if I were to supplement my domain-model with Extension Builder to include all domain-entities with their properties. My hope was that EB would create the new classes with getters and setters, and magically generate the test-files with the tedious setter and getter tests already done. Without breaking any of the code I'd already written. Hope springs eternal.

A note before I dive right in: no matter what your settings are in the "yaml.settings" file (i.e. "merge"), updating your domain model with the Extension Builder after having written your own code WILL OVERWRITE (almost) EVERYTHING. ALMOST everything. If it really overwrote everything, at least the code errors would be consistent! Luckily I made a hard backup of my files so that I could compare them to those generated by Extension Builder.

All of MY test code - gone. All of the setter and getter tests I had supplemented - overwritten. EB overwrites all the "getter" tests with yawning emptiness. Let me repeat: if you do not make a backup of your tests before expanding your domain-model with Extension Builder, EB WILL OVERWRITE YOUR HOPES AND DREAMS, leaving you in a yawning lacuna of existential emptiness. Hell is dynamically-generated code.

If that were not enough, here's an additional disadvantage: in its tests, EB takes care of class dependencies by instantiating objects instead of mocking them. This causes an interdependence between test classes that is NOT a good thing, and makes for test code that is difficult to correct when running it leads to failed tests. Additionally, EB has a strange habit of changing all "implements \TYPO3\whatever\this\interface" into "implements TYPO3\whatever\this\interface" EVERY time you save the domain-model through EB which, of course, leads to a fatal error which you will have to correct every time after pressing "save". Eventually I just commented out the "implements" and wrote it in after I was definitively done "saving" (ha!) the model with Extension Builder.

But wait, there's more! Everywhere a class needs to extend "Persistence\ObjectStorage", EB likes to overwrite that with "Persistence\Generic\ObjectStorage". This breaks all code, everywhere, and you will have to do a search-and-replace to get rid of the introduced errors.

"Extension Builder" might be more aptly named "Extension Wrecker". Take heed.

I ran the tests generated by EB again and again until everything passed. I think that that took as much time as writing them by hand, and the errors I had to correct were not actually introduced by me. THANKS (dripping with saracasm), Extension "Builder".

One good thing is that the otherwise nefarious Extension Builder actually added tests that helped me uncover the correct way of implementing, getting and setting storage objects. This was done in 2 different ways in the code I downloaded for "Reliable Extensions" and I'm glad that there were dynamically generated tests that could point out to me the flaw in logic in one of the implementations.

OK, so I think I'm done bitching for now. But I've come to the conclusion that, just like with the old "kickstarter" extension builder, you should really only use Extension Builder ONCE - or, never, ever again after you've started working with the code it generates. Seriously. I'm looking forward to see what the process is in my new place of employment: EB first, EB never, or EB always and forever?

It's been a very long, very productive, frusterating and also incredibly rewarding six weeks. Several times during my learning process I was able to move forward only with the help of fellow-students and organizers. At home, when I got stuck, I would always have to give up (Laravel, I'm looking at you -- YOU'RE NEXT).

It was especially in these past two weeks, where I could concentrate on domain-driven-design and test-driven-development with PHPUnit, that I've become a more professional object-oriented PHP coder than ever before. Within this short time I've gotten farther than in a whole TWO YEARS of working full-time with procedural PHP, taking online courses (in everything BUT PHP), and going to one to three programming meetups a week!

Thank you, Hackership, organizers and fellow-students, for giving me the opportunity of a lifetime - the opportunity to become a better programmer, to really learn, and practice, and share. Your support, your enthusiasm, has kept me going when things got frusterating, when it was too cold outside to want to get out of bed, when I came home after 9 hours of coding completely exhausted. You were motivation and reward.

I feel like I now know what it's like to work on a team that feels like a family.

Tuesday, December 17, 2013

Day 19: PHPUnit testing for TYPO3, the success story

Erfolgserlebnis! 

Today, with a lot of help from a hacker-in-residence, I figured out how to get my PHPUnit tests for TYPO3 running. The problem stemmed from the fact that, instead of extending PHPUnit_Framework_TestCase, TYPO3 tests extend their own Test class that serves as an autoloader for TYPO3 dependencies. PHPUnit from the command line doesn't recognize that without the help of an executable (included with the TYPO3 source code) called "cli_dispatch.phpsh".

This file can be found in the main "typo3" folder of your TYPO3 installation. To run PHPUnit tests with TYPO3 dependencies - presumably as part of extension development with Extbase - here's what you need to do:

On the command line, navigate to the directory right above where your "typo3" folder is found. On my local machine, that's:

$ cd /var/www/html

Call phpunit as the argument ("cli key") for the cli_dispatch.phpsh file, run as an exectuble. Follow the "phpunit" argument with any phpunit configurations you'd like (configuration file, colors, strict, etc.) and then the file you want to test - just as if you were calling phpunit directly from the command line:

$ ./typo3/cli_dispatch.phpsh phpunit typo3conf/ext/sjr_offers/Tests/Domain/Model/OrganizationTest.php

If you're like me, nothing will happen - you'll just get a new command line without output. To find out what the problem could be, you can call the following code on the command line:

$ ./typo3/cli_dispatch.phpsh phpunit status; echo $?

If you get "1" as output (which means, cryptically, "error"), you still need to change the following configurations in the TYPO3 Install Tool in order to get a better idea of what's going on:

$TYPO3_CONF_VARS['SYS']['displayErrors'] = 2;
$TYPO3_CONF_VARS['SYS']['devIPmask'] = '*';

This will tell TYPO3 to output errors as long as the caller's IP address matches TYPO3's IP address (i.e., if we are in a development environment). Setting the "devIPmask" to "*" tells TYPO3 that all callers' IP addresses should be accepted as "matching".

Thank you, @Christian Weiske, for this tip - you seriously saved my day!

After doing this, you should get a more detailed error of phpunit's problem. For me, it was insufficient write permissions on the typo3temp file, where locks on files are set up and log files are written. After adding some group write permissions on this file, running the "status" command got me a PHPUnit error, which means that PHPUnit is now working - awesome!

Running the code from above again,

$ ./typo3/cli_dispatch.phpsh phpunit typo3conf/ext/sjr_offers/Tests/Domain/Model/OrganizationTest.php

PHPUnit runs through all assertions in the test without problems and gives me a status report. Gods, I'm so happy I could just cry. :)

For now, I'm going to put off running PHPUnit tests from Eclipse on hold, in order to write some tests and have more of that "success experience" today, after the horrible Day of Failure that was yesterday. I'm going to create a new extension with Extension Builder, modelling the same domain model and start-functionality as the "sjr_offers" extension used by the book and import it into TYPO3. Then I will create the "Tests" directory structure in my extension and start implementing tests for each functionality. I can run them through PHPUnit and compare my efforts with the code from "Reliable Extensions". I'd also like to write a configuration file ("phpunit.xml") that loads my command-line configuration for me - without breaking anything!

Stay tuned...

After a lot of googling, I'm going to have to guess that this suggested procedure is a sensible one.

Wednesday, December 11, 2013

Day 18: PHPUnit-Eclipse hacker hell on earth

Feels just like Christmas!

I don't even want to go through the list of all the stuff I did today, trying to get my TYPO3 PHPUnit tests to run successfully from within Eclipse. I spent the last 2 hours of yesterday evening trying things out, and today it went on as I tried some new ideas I'd gotten while washing dishes this morning, and then going back to basic concepts by reading everything I could find on PHPUnit and Eclipse.

Unfortunately the majority of articles online about this topic are from 2011 or 2012.

I wrote a phpunit.xml and a bootstrap.php file for the project and, along the way, learned some interesting things about Eclipse that helped me to understand it better, like how I can set up a view for PHPUnit output in its own window and set up a button in the toolbar for running the unit tests with a click of a button instead of right-click - select - select, open console because it won't stay pinned and disappears as soon as I right-click on a file in the project-tree... (I found out that you can fix that by selecting "Restore" within the console window).

My final strategy was that on which I stumbled yesterday evening: google the error-message. "Fatal error:  Call to undefined method PHP_CodeCoverage_Filter::getInstance()". What I found is that there are two possible PERL libraries for PHPUnit to use in Eclipse, thus there are two possible "Filter" classes for PHP Code Coverage. The one being used no longer has the method being called - it has no constructor and looks like an older model.

I guess that when the code for PHPUnit in Eclipse was updated, IT WAS NOT TESTED WITH PHPUNIT. OH THE IRONY.

What I did was make a copy of each Filter class and include both of them in each library. Then in the file where the error is raised, I changed the require_once directive to require the file with the needed code.

The reason I did this is because though I entered both PERL paths as the PHPUnit libraray in Eclipse, whichever one I picked as the default, the behavior remained the same.

This fixed the problem in Eclipse, and showed me the error that I was getting from running the same unit tests from the command line. Looked like some kind of autoloader problem. After lots of trial and error, I decided to get back to basics and build the same class and test class in a simple setup without any TYPO3 extras. By doing this I figured out a few things I had done incorrectly with the bootstrap and phpunit.xml file, for instance, forgetting the "includePath" tag for where to find the classes corresponding to my test classes (doh!).

Going back to the TYPO3 PHPUnit test files in Eclipse, the autoloading problem was still the same. I finally decided, with less than two hours left until the day is over, to continue going through the tutorial from "Reliable Extensions", while building out the test classes in my simple environment. At least then I will get some practice with assertions and the basics of test-driven development. At the same time, I will continue developing them (as they should be developed) in my TYPO3 environment without even bothering to run them.

Today I spent the whole day trying to get something to work, that did not work out in the end - and I have four, dull handwritten pages recording all the steps I took and the logic I used. It made me aware of the fact that my first strategy in trying to fix a problem is trial-and-error. When my frusteration gets too great, I take a break and then get back to basics, to reset my mind and get it unknotted. Finally, if I think that it's really, really not going to work, I stop hammering myself in the head with it and do something similar that I know DOES work. In this way, I am going to get through this fu chapter, hopefully within the next one and a half hours, and be ready for the next chapter on building the persistence layer tomorrow.

I can't wait to be able to ask experts about how to solve these problems and get some insight into how they work, what their process is. If anything else, I've learned to be impatiently curious about how to solve all the difficulties I've come across and was not able to solve on my own. TYPO3 remains a challenge.

Tuesday, December 10, 2013

Day 18: Chapter - modelling the domain

Today I'm going to tackle Chapter 5 in "Reliable Extensions": Modelling the domain.

The step in which we abstract a part of the real world (the "domain") into a representation within the extension is called "domain modelling" and is, according to "Reliable Extensions", the most important part of extension development. The book uses the "sjr_offers" extension as an example of how to model a real-world domain: namely, this extension was developed for the "Stadtjugendring Stuttgart e.V." (Youth Organisation Ring Stuttgart). Whereas yesterday we developed a simple extension with the help of Extension Builder, today we're going to model the example domain by hand, using the principles of test-driven-development by writing PHPUnit tests before implementing functionality. Whee!

Looking at the list of desired functionalities, I sketched out a primary list of actions and from this list, gleaned a bunch of terms I thought might be part of the domain models. I was mostly right - yeah! Luckily, though the book (and the example domain) is in German, extensions are developed in English and I don't have to translate back and forth.

I then sketched a primitve design of how a few of the models are associated with each other - again, there was a pretty good match between what I had supposed to be the model associations and what the book revealed. This is only because the book also started with a very basic model and then refined it, step by step.

In the process, I learned a useful trick for abstracting pair-properties within a model. For example, if we have the properties "minimum age" and "maximum age", "minimum participant number" and "maximum particpant number" and "start date" and "end date", these pairs have their own rules that only apply to the two properties within the pair, and not necessarily to their aggregate root model (in this case, "activity offer"). Therefore, these pair properties are all extracted to their own models: ParticipationRange, AgeRange, and DateRange.

Furthermore, each of these new models have something in common that can be further abstracted, and that is a minimum value and a maximum value. "Reliable Extensions" extracted these generic properties into their own domain model: RangeConstraint. The models for AgeRange, ParticipantRange and DateRange are now associated with the RangeConstraint model.

This is an incredibly useful tip - this is exactly the kind of thing I want to learn from people who have more experience working on complex (real-world) projects. Thanks, @Sebastien Kurürst and @Martin Helmich!

On to implementation. My questions from yesterday, about how to take a test-driven approach to extension development, were answered neatly today. There are two ways to implement a domain-model: the "top-to-bottom" approach starts with aggregate root objects, like "offer" or "organization", that "contain" other models. The "bottom-to-top" approach does the opposite and starts with the elementary objects contained with the aggregate root. The approach you decide to use will have an effect on how tests are written - "Reliable Extensions" paves the way with the top-to-bottom approach, tackling the big ol' "organization" model first.

Yesterday, basic domain models were implemented as PHP classes for us by the Extension Builder and saved in the "Classes/Domain/Model" directory. Today, we create these classes by hand. Instead of, however, starting with "Organization.php", we will start with "OrganizationTest.php", which we will create in the Tests/Domain/Model" directory.

I decided to bite the bullet and start actually using Eclipse to develop. Following the instructions from last week, I started a new project, "SrjOffers" and linked the PHP paths "Extbase", "Fluid" and "PHPUnit" to my new project in order to set the basis for auto-completion. In order to do this, you need to make sure that the owners and permissions for the root directories of these libraries are correct.

"Reliable Extensions" recommends that the structure of the "Tests" directory should mirror that of the "Classes" directory, in order to keep everything clearly arranged as the number of unit-tests grows. I'm wondering, though, if I should start with "Tests/Unit/Domain/Model" instead of their recommended structure "Tests/Domain/Model", to make room for other kinds of tests later, like integration and acceptence testing.

So, the first unit test is written... how do I run it in Eclipse? I know how to run unit tests from the command line and from within the TYPO3 backend. However, since we're writing this extension by hand, it is not yet an official "extension" in TYPO3 and therefore cannot be connected with unit tests. Hello again, my friend Google. "PHPhatesme.com" was an excellent source of information for this question:

Under "Help" -> "Install new software", click on the "Add" button and enter "http://www.phpsrc.org/eclipse/pti-dev/" as URL and "PHP Tool Integration" as the name. Now, select this site from the dropdown and open up the lists that appear in the select box: Core, Library, and Tools. Select the PTI core under "Core", PEAR under "Library" and "PHPUnit" under "Tools". You know what's really cool? Under "Tools" you can also pick PHP Code Sniffer, PHP Copy-and-Paste detector, PHP Mess Detector, and PHP Depend, if you want to.

Eclipse will install your selections and then you have to restart. Now, when I right-click on my OrganizationTest.php file in the project tree, I can select from the menu "PHP Tools" -> "PHP Unit" -> "Run Unit Test". Unfortunately, what this produces in the console is "No case / test suite found for file OrganizationTest.php". I'm guessing that I have to write a bootstrap file? I wrote to the forum on the article on "phphatesme" - because, PHP does hate me, apparently.

Despite all of our difficulties, PHP, we've been through so much together, and after 15 years of ups and downs I'm obviously still willing to work on our relationship, 'till death do us part!

I have two specific problems now: 1) why isn't Eclipse auto-completing the code I write in the class inheriting from \TYPO3\CMS\Extbase\Tests\Unit? and 2) why can't PHPUnit find my class to test? Both seem to be related, because the error message I get when running PHPUnit on the command line is that "Class TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase not found".

Problem 1: with the help of two co-hackers we saw, first of all, that I had typos in my name-space and directory-name (eye-roll). Fixed these, deleted the project, re-imported the correctly-named project in Eclipse, and tried again. Same error. With some more help and prodigious googling, we came up with the following solution by @Carsten König:

Bind TYPO3 as a library in Eclipse - for autocompletion on all Typo3 libraries


  1. Open "Window"->"Preferences".
  2. Select "PHP"->"PHP Libraries" -> "New...".
  3. A window titled "User Library" will pop up prompting you to enter a name. Type the name "TYPO3" and click "OK".
  4. Select the new entry, "TYPO3" and then "Add external folder".
  5. Browse for the "typo3_src" file - on my system, it was in "\var\www\buch\html\typo3_src", select it, and click "OK".
  6. Right-click on project that should have auto-completion. Select "Properties" -> "PHP Include Path" and click on the "Libraries" tab.
  7. Choose "Add Library" and check the box next to "TYPO3". Click "Finish" and then "OK".

This worked in that writing a test class that extends the TYPO3 BaseTestCase, which in turn extends the TYPO3 Core UnitTestCase, calling "$this" gives me a long list of methods from PHPUnit to choose from. I still get the same error running the unit test in Eclipse, though (and a probably related one on the command line).

Running PHPUnit on one of the files "without detection" gives me the error "PHP Fatal error:  Call to undefined method PHP_CodeCoverage_Filter::getInstance() in /home/kaiser/programming/zend-eclipse-php/plugins/org.phpsrc.eclipse.pti.tools.phpunit_0.7.2.R201106270000000/php/tools/phpunit.php on line 40".

I report this after 2 hours of searching for an answer. The command line error remains "can not find (TYPO3 BaseTestCase) class". Enough for now, though; I've been working for nearly 9 hours and it's time to take a break.

To be continued, friends (and enemies) of Typo3...

Monday, December 9, 2013

Day 17: building another simple extension with Extension-Builder.

Today I tackle Chapter 4 of "Reliable Extensions", which involves building a(nother) basic extension with Extension Builder. To review, building an extension involves the following steps:

1. Create a directory structure and the basic configuration files.
2. Model the problem domain.
3. Configure the persistence layer:
   a) define the database tables.
   b) configure the backend forms.
   c) set up the repositories.
4. Define the inner processes of the extension (design the controllers and their action methods).
5. Design and implement HTML templates to present data.
6. Create plugins ("plugins" in Typo3 always refer to the frontend) for listing data.
7. Install and test extension.

Wait a minute... why does testing the extension come last in the steps? If I want to use test-driven-development in creating an extension, what's the best approach? Do I test everything, or only the controllers and their action methods? I'm guessing that testing these, at least, would be a good start, but should I generate test-cases after the code for the extension is generated by Extension Builder, or beforehand?

Extension Builder (from now on referred to as "EB" to spare me some typing) takes care of all the above-listed steps except for 7: basic configuration (step 1), plugin - frontend - configuration (step 6), and domain-modelling (step 2) are done through EB's graphical interface. On saving, EB generates the directory structure (step 1) with the following folders: Classes/Controller, Classes/Domain/Model, Classes/Domain/Repository, Configuration/TCA, Resources/Private/Templates/Product, Tests/Unit, and some others.

Under "Configuration/TCA/", the PHP class, "Product", is configured to allow us to determine how the forms in the backend should be shown (step 3b). Additionally, in "Classes/Domain/Repository/ProductRepository.php", EB has generated a class for us that will allow us to access the data of our persisted models (step 3c).

In "Classes/Controller/ProductController.php", EB has generated a controller and its action methods for us (step 4) as we have determined them in the "default actions" section of the EB graphical interface. Here, the action methods access our model data through a repository, and then assign this data to a view for presentation. A basic first template for the view for the "list" action has been created for us (step 5 - thanks, EB) under "Resources/Private/Templates/Product/list.html".

Basic configuration files are saved in the main directory named after our extension key - in this case, "inventory" - and are all preceded with the prefix "ext_". For instance, the file "inventory/ext_tables.sql" provides the SQL commands necessary to set up the database tables accomodating our domain model (step 3a), "inventory/ext_localconf.php" defines for our frontend plugin which controller-actions are allowed, and "inventory/ext_tables.php" registers the plugin for the frontend.

The entire generated directory structure is stored in the main directory for our local extension: "inventory". This, in turn, is stored where all local extensions are stored, in typo3conf/ext. In contrast, global extensions, which are globally available to every page, are stored in typo3/ext, and system extensions, which are valid for the entire TYPO3 installation, are saved in typo3/sysext.

Finally, we reach a point where we actually have to do something ourselves: install the extension. Under "Extension Manager" / "Manage Extensions", you'll find the "Inventory" extension - click on the icon to activate. Logout, and login again - if you're lucky, nothing's broken.

Set up a system folder in your page tree. I'm calling mine "Inventory" (duh). Once it's created, add a new record to this folder of the type "Product" - in the list of plugins, you should see this under the plugin "Inventory". You can repeat this last step to insert as many products as you like into our new inventory database.

Now you can set up pages that use the plugin. Just add a page of type standard in the page tree, go into the list view on this new page, and add a new content record of type "Insert Plugin". Choose "Product List" as the "type" under the tab "Plugin". Also set the "Record Storage Page" (under the tab "Behavior") to the system folder "Inventory", and you should see our list of inventory records in the frontend.

Unless you're using TemplaVoila: then you'll just see the ID of the page's content-record. I'll have to figure this out tomorrow.

Today I've accomplished my goal of working through chapter 4 of "Reliable Extensions". I also read a chapter from "Advanced PHP" on saving session variables to the database instead of the file-system, during my lunch "break". Tonight I'll see if I have the energy and the desire to finish Code School's "Git Real" course after dinner. Or if I decide to just crash on the couch and engage in staring contests with my cats. What I do know is that I am the most unhip programmer in Berlin for admitting that last bit.

Thursday, December 5, 2013

Day 16: OOP, DDD, TDD, and MVC in Typo3. And something about me.

Day 16

Today I once again got through one chapter of "Reliable Extensions" with a lot more success than yesterday. For example, today's chapter, on object-oriented programming, domain-driven design, test-driven design and the Model-View-Control pattern, where I often referenced my "Hands-On with PHPUnit" book for additional information, was 40 pages. Yesterday's chapter was 8.

First off, I started the day with a revelation: I learn better when the rest of my life is in order. When the apartment looks decent and I have clean clothes to wear, healthy, home-made food to eat, groceries in the cupboard, a legally valid public-transportation ticket, and all errands run. Because then my head is clear for other things, like refreshing my knowledge of concepts important to OOP (object-oriented programming).

Objected-oriented-programming is a programming paradigm that assumes that processes in the world can be abstracted into and represented by models (or objects), and the relationships and interactions between those objects. Objects have relationships, just like in the real world: a car HAS a motor. A Volvo IS a car. A Smart WANTS TO BE a car... These relationships can be one-to-one (a car has ONE steering wheel), one-to-many (a car has FOUR - or more - wheels) or many-to-many: a City-Car is driven by MANY drivers, Michael Jordan drives MANY cars.

The objects closely or inseperably involved in a "has a" or "belongs to" relationship can be described as aggregates: for example, wheels, brakes and a motor belong together in a car. The car would constitute the "aggregate root object" since it represents its composite parts as belonging to a complete whole. An aggregate root object, just like a car, must be an individual object in the world. We call an object that can be an individual object in the real world an "entity". In contrast to an entity, a value ("value object") would be something like the color blue, or the number 1. Blue is blue - it wouldn't make sense to say that it was an individual in the world.

Another concept from the world of OOP is the idea of "services". Services are containers for actions that can't really be attributed to any object. A service should be "stateless", that is, it should have no internal status that can be changed or manipulated. A service is kind of like a verb, where objects are more like nouns: a car can have a state (in motion, at rest) whereas "to drive" can't really be talked about that way. A service usually receives an entity or a value object whose state it can manipulate or change.

In the world of software, which consists not of REAL objects, but of mere representations of objects, the act of keeping these objects around in the virtual world (in memory or on the hard drive) is known as "persisting". In the world of OOP, the act of persisting an object is the responsibility of "repositiories". A database could be called a repository. It's responsible for "remembering" an instantiated object and its state so that it can be used in a program with consistency.

Our object-representations (let's just call them objects so that I don't have to type so much) can be created with factories. A factory is something that builds complex objects and sets all their properties before giving out the complete object at the end for use. In OOP, we use either a factory or the "constructor" method of a class to create an aggregate root object and set all its properties with consistency.

Aggregate root objects and persistence are tied together in that every aggregate root has to have exactly one repository: something (even a virtual something) can only be in one place at one time. In Extbase (ay, there's the mark of the matter), we define an aggregate root by creating its repository first.

On to MVC: Model-View-Control. The MVC is a pattern that can be used when writing software that (when used sensibly) will make software easier to read, maintain, and develop further. This is because the MVC pattern seperates software functionalities into distinct areas of responsibility: the Model, the View and the Controller.

The model is responsible for encapsualting data, the logic of how the data is used, how it's accessed, and how it's persisted. The view is responsible for presenting data to the user. Finally, the controller is responsible for coordinating the interaction between the model and the view. It ONLY coordinates: the actual domain functionality is implemented in the model. In Extbase, the model is further structured into domain model (abstraction of the domain, its logic and rules), repository (database access), and validator (container for the "invariants of the model", whatever that means) .

This brings us to DDD: domain-driven-development. What's a doman, you ask? It's an area of special knowledge and specific processes that belong together. For example, a hospital (the domain) has admissions, appointments, examinations, surgeries, therapy, medications, medical records, etc. The goal of a software developer who wants to develop a program to make these processes easier (cheaper, faster, more reliable, less tedious, compliant with the law) for the people who work within the domain, is to understand the language of this area and these processes. In order to do this, she has to sit together with someone who knows the domain inside out (and does actual, competent WORK within it...) and together with them, develop a way of talking about this domain that both developer and domain expert can understand.

This way of talking about the domain that both developer and expert (and software user) can understand is called "ubiquitous language" and can be best made useful by developing a kind of dictionary, or glossary, of terms, that both developer and domain expert can refer to. This glossary can then be used by the developer to implement software that is easy to talk about with the expert/user and to check with them that the desired functionality has been correctly understood and implemented.

Here's a personal aside: I use the hospital example because it's the domain in which I have had over 10 years of experience developing software for. By this point, I'd consider myself both a developer of software as well as a domain expert for hospital administration processes. I got there by consistently asking to watch how my colleagues work, asking them to tell me all about the way they do things, and then asking them questions about things I didn't understand or weren't clear. I would then sketch out a step-by-step example of a program and go through it with them, asking them at each step if what we were talking about made sense and corresponded to the way they needed to get their job done. I would do this again and again until they were satisfied with what we had worked on together, and only then would I start programming.

Only when I did NOT do this (for example, when the domain expert believed that they could communicate with me indirectly about what they "needed" by telling my boss about it, or in an incomprehensible email, or via telepathy), or the domain "expert" did not actually do any real WORK in the area they were supposed to represent, that software "got developed" that was of no use to anyone. Domain-driven-design makes sense to me - it's the only way to possibly make something that someone's going to be happy with and actually use.

So I already have a good handle on - and years of experience with - domain-driven-design. What I lack an intuition for is TDD - test-driven-development. I'm familiar with the theory, which I refreshed today, and have started to implement it in baby-steps: trying to code the example and then checking out the code provided by the book to see how close it is, if I have the idea right, what's missing, what's totally wrong, what I've failed to understand or succeeded in getting right.

That made today a fun day. Just in time for the weekend.

Wednesday, December 4, 2013

Day 15: way too many problems

First of all: @Dmitry Dulepov saves the (first part of the) day. Thank you, Mr. Dulepov.

"There is a question that I see several times monthly in TYPO3 mailing lists: "I see an empty (blank) page after XXX. How do I fix it?". Here is the step by step answer:

Go to the Install tool
Select "All configuration"
Set displayErrors to 2
Add your IP address to devIPmask
Now you will see PHP errors that happen. By default these errors are hidden by TYPO3 for security reasons and it causes blank pages. Changing settings above allows to see these errors on your IP address only.

So fix these PHP errors and your site will be back."

Source: http://www.dmitry-dulepov.com/2009/03/blank-empty-page-in-typo3.html

I had this problem, namely, after installing Xdebug as instructed in the "Reliable Extensions" book project.

In the Install Tool, "Configuration All", the "displayErrors" parameter has a value of "1", which means:

"Default setting. With this option, you can override the PHP setting 'display_errors'. If devIPmask matches the users IP address the configured 'debugExceptionHandler' is used for exceptions, if not 'productionExceptionHandler' will be used."

We need to change it to "2", which means:

"Display errors only if client matches [SYS][devIPmask]. If devIPmask matches the users IP address the configured 'debugExceptionHandler' is used for exceptions, if not 'productionExceptionHandler' will be used".

Re-opening the "Extension Manager" / "Get Extensions" page, I feel so enlightened; here's my error:

"( ! ) Fatal error: Maximum function nesting level of '100' reached, aborting! in /var/www/buch/typo3_src-6.1.5/typo3/sysext/core/Classes/Utility/GeneralUtility.php on line 1125"

I fixed this - after some googling and detouring - by entering the following line of code in my php.ini file:

xdebug.max_nesting_level = 250

I had a hard time figuring this out because I assumed that this line would already be IN the php.ini, because that's what my phpinfo() was telling me. Apparently the default is used, without an explicit line of code in php.ini, so if you want to change it, you have to write it out yourself.

Next, I was forced to undergo an HOURS-LONG detour in that I returned my edition 1 of "Reliable Typo3 Extensions" and bought the 2nd edition from O'Reilly books. I love the English version of the O'Reilly books site, but unfortunately the German site - which has NO user registration - sucks, and I got the Ebook as link in an email to a PDF... which I was not able to bring over to join my Ebooks on the iPad.

Sigh.

So I settled for working with the book as a PDF on my laptop. But installing the "blog_example" (new, version 1.4) extension provided by the authors or "Reliable Extensions" (wow - the irony...) via download ended up killing my Typo3. I found out that this is because uploading the .zip file of extension as instructed writes the ".zip" part of the file AS PART OF THE EXTENSION KEY, which breaks EVERYTHING. After a LOT of cursing under my breath and combing through lines of code, I was able to get everything running again by:

1) renaming the directory under typo3conf/ext from "blog_example.zip" to "blog_example"
2) getting rid of all references to "blog_example.zip" in typo3conf/LocalConfiguration.php
3) forcibly clearing the cache by deleting the typo3temp directory

I only did all of this after first commenting out some lines of code in the UtilityManager.php so that I could get back into the backend and de-install the (shitty) extension and try to reinstall it from the unzipped version of the directory (which, of course, did not work).

Hi, writers of "Reliable Typos3 extensions": you might want to fix your "blog_example" code AND the typo on page 19 that reads "Um das Modul nutzen zu können, müssen Sie zunächst im TypoScript-Setup Ihrer root-Seite das statische Template BloxExample setup inkludieren". ("In order to use the module, you need to include 'BloxExample' (styles) in the static template of your root page." Because that's BlogExample. At least this crucial instruction is INCLUDED in the 2nd edition of the book: in the first, it was not, basically rendering the appropriate extension of "blog_example" (version 1.3) completely unusable.

Anyway... working with Eclipse and "projects" isn't really working for me today either. Why is it taking minutes to run the debugger on one line of code? Finally I got it working, but I'm irritable and annoyed so the fun of it will be hard to recover. Too many problems with software not written by oneself makes up 90% of the sucky part of programming, I think.

Day 14: Day 2 of (almost) nothing works

The log entry for Day 13 has been excised, since nothing worked yesterday when I tried to follow the "Praxiswissenschaft" tutorial for setting up editor permissions. The editors I set up can login to the backend and see the various modules I've allowed them to, but no pages. NO pages. Just an empty page-tree. I spent most of the day going over the tutorial again and again, without success. After a Git tutorial, I gave up on the permissions and moved on the preview the chapter on TemplaVoila, which is what I'm implementing today. I felt so unproductive yesterday that I went home early and did a Code School class at home on new features in HTML5 and CSS3. It was easy and fun, finally, as we say in German, an "Erfolgserlebniss".

Today I'm setting up my Typo3 site to work with TemplaVoila. I find it so complicated that I wonder how I will procede without the explicit instructions from the book. Also - guess what - it doesn't work. Where I'm supposed to see a site like the one I built, with no content, I just see a light blue page. Inside the body tags there is nothing. I wonder if I picked the wrong div tag at the beginning of the tutorial? The screenshot in the book showed three and I only had two: I picked the top one.

Two good things today, in any case, include getting to look at the models for someone else's project, and got to help someone with a mail problem in PHP (Erfolgserlebniss).

Going back to the beginning of the tutorial, I recheck my first selected <div> tag - the ID matches. In the preview within the "TemplaVoila" module, everything looks the way it should. WTF doesn't it work on the frontend, then?

Post-lunch: I found the problem in my TypoScript for the Template for the root page of the TemplaVoila site. I had a typo, namely an "l" where a "1" should have been:

page = PAGE
page {
  includeCSS.style = fileadmin/css/style.css
  config.doctype = xhtml_trans
  10 = USER

#false!
#10.userFunct = tx_templavoila_pil->main_page

#correct!!
  10.userFunc = tx_templavoila_pi1->main_page
}

Now the preview looks great. What a relief. Trying to do the same thing as demonstrated in "Praxiswissenschaft" for the left-hand menu, but for the breadcrumb-menu and time-dependent greeting, I went through the following steps. Note - this did not lead to success.

1) Under "Web", click on "TemplaVoila"
2) Click on the link to the saved Template Map under "Storage Folder"
3) Click on "Update Mapping" and then "Modify DS/TO" (Datastructure / Template Object); in the popup, click "OK"
4) In the "Enter a field name" input, enter (for the time-dependent greeting "field_greeting" and for the breadcrumb-menu "field_menu_breadcrumb")
5) Select "Element" from the dropdown, enter the title "Greeting" (or "Clickpath"), and for "Element Preset" the type "Typoscript Object Path".  Click "Add".
6) Now click "Map". Choose the div tag with the id "meta". It should be of type "INNER" (replacing only the content between the div tags, not the div tags themselves). Click "SET" and then "SAVE".

Now the Typoscript element "lib.field_greeting" and "lib.field_menu_breadcrumb" are available for coniguration with TypoScript in the Template for the TemplaVoila rootpage. I coded it assuming that I could use the same TypoScript I used in the template for the main (non TemplaVoila) root site. This, however, did not work. It didn't BREAK anything, but it didn't render anything, either, except for the "greeting" text:

#create breadcrumb menu
lib.field_greeting = TEXT
lib.field_greeting {
  value = You are here:&nbsp;
  lang.de = Sie sind hier:&nbsp;
}

lib.field_menu_breadcrumb = HMENU
lib.field_menu_breadcrumb {
  special = rootline
  special.range = 2|-1
         
  1 = TMENU
  1 {
    NO = 1
    NO.linkWrap = |&nbsp;&raquo;&nbsp; |*| |
  }
}

Because there is currently no internet access for me to be able to google at this time, I'm going to move on to "Zukunftsichere Typo3-Extensions mit Extbase und Fluid" ("Reliable Typo3 extensions with Extbase and Fluid"), by @Jochen Rau and @Sebastian Kurfürst. I ordered the second edition for my Kindle, but it looks like it went and gave me the first, from 2010. One of the first problems is that the book is unaware of the existence of Typo3 v6. I am annoyed. Life at sea Learning programming can be so inconvenient sometimes most of the time.

Thursday, November 28, 2013

Day 12: kiss my backend

The day of extensions:

Today I spent the first half of the day trying to make the mm_forum not suck, the front-end module suck less, and to extend the functionality of my self-built "Snowboard Teacher" extension. I used only online documentation, and now I am going to share my wisdom with you.

I discovered that with the front-end login extension ("felogin"), the extra sub-page "Login Status", which serves as a target for redirection after a successful login or failed login, did not only NOT work in a sensible way, but was also pretty much unecessary.

Clicking on the "Members Only" page and selecting the "List" module, you can click on the page content for the login form. There, under the "Plugin" tab, there is a subtab for messages. Why create extra pages and redirect to these pages after successful login, failed login, logout, etc., when you can just click on the "Messages" subtab of "Plugin" and write these messages in text? There are "Header" and "Text" fields for "Welcome", "Login Success", "Login Error", "Status", "Logout" and even "Forgot Password".

I entered values for these, deleted the "Login Status" subpage, and tried out the login anew. It works intuitively, unlike the previous workflow of redirecting to pages after these different events. Additionally, you can set up the same thing for the English-language version of the same page-content. Everything is in ONE place, on ONE page, and flows very logically. For this particular use-case, I can highly recommend using the "Messages" subtab of the Login plugin rather than setting up seperate pages for redirect.

I then edited the Login Form template, "felogin_template.html" in "user_uploads", so that it was a bit more orderly and not so... ugly. You can set which template is going to be used for the login formular from the "List" module by clicking on the page content, then the tab "Plugin", and then the subtab "General". Something I found out while editing the template file is that if you edit it directly, after saving, you need to re-select this template from the "General" tab before clearing the cache and refreshing the frontend. Whyever.

The second thing I worked on today was the missing moderator section of the mm_forum. The online documentation for it under http://typo3.org/extension-manuals/mm_forum isn't that great, but it gave me enough insight to figure out how to set this up. Namely, you need to set up either another page (as a sub-page of "Forum") or set a new content area in the "Forum" page itself.

In the content area, select as content type "Plugin". Then as plugin type, select "mm_forum::Forum". After this selection, you will be presented with a dropdown of what to display on this page. Pick "List post queue". If you've done this on the same page as the forum, as I did, and log on as a user with moderation rights (and the forum is set up to have comments moderated before they are published), you will now see an administrative area for moderators ABOVE the forum. This is kind of busy-looking, so I think that I will set up the admin area on its own page instead.

Something else I discovered is that the reason no users showed up in the "mm_forum" module in the "Install" / "User Administration" area is that users will only do so if they are marked as "ForumUser". It doesn't matter if they are also marked as "ForumMod" or "ForumAdmin"! Once you do this, they appear in the "User Administration" area of the forum and can be edited from there.

mm_forum offers several functionalities that apparently must all be set up in a similar way to what I just described: as a mm_forum plugin content area, either on its own site (a sub-site of "Forum"), or on the "Forum" site itself. I'm going to use this knowledge to try and set up all the functionalities as a way to practice.

The final thing I did (with the first half of the day) was to try to extend my self-made "Snowboard teacher" extension. I added a new property to the teacher model in the extension builder, changed the template for listing them out, and took a while to figure out that after saving all these changes, I needed to deactivate (not remove!) and reactivate the extenstion with the "Extension Manager".

Four hours later... 

Four insanity-inducing hours of trying to set up a user registration form for the mm_forum. Here's what I did right and wrong. So, so wrong:

First: you need to set up a new page for forum user registration. Hide it from the menu. Add the content type "Plugin" and then under the "Plugin" tab, give it a "mm_forum" type plugin. After saving this, you can choose what's to be shown on the page: "mm_forum::User Registration". That was the easy part. The hard part is remembering to set up an extension template for this page, "edit the whole template", and in the "includes" tab, to include the following styles in the following order (otherwise, you will get only a page with a title and nothing else):

mm_forum Javascript: Prototyp
mm_forum
mm_forum Stylesheets
Page browser

I had a huge problem with how to set up a link to the forum user registration from the forum logon page (for non-logged in users). I looked around the backend for a LONG time, thinking (illogically?) that this could be configured within the mm_forum module, just as it's possible to configure whether the "forgot password" and "change password" links show up in the forum login form. No such luck.

Another problem is that in the root template, thanks to the tutorial, I've overwritten the default functionality of page headers so that they can no longer display links through their configuration mask. I finally decided just to add a new type of page content underneath the forum login formular: plain old text. In the Rich Text Editor, I simply wrote "Register for the forum", highlighted it, and made it a link to the forum user registration page within the editor itself.

Problem solved. Next problem: in the forum user registration form, there's a whole bunch of labels, but no Captcha (which I specified should be shown), and NO TEXT FIELDS next to the labels! I searched for hours why this could be and eventually just went into the template and deleted 2 marks surrounding the input fields - ###DEFUSERFIELDS###. After deleting these marks, the input fields showed up and I could fill out the form and submit it. It takes forever to validate, but at least it works. I can't believe I spent the whole second half of the day on this, but now I know the backend pretty damn well, at least.

Quick update: the validation email that arrives after having filled out the forum user registration form has only the following text:

Hallo,
vielen Dank für deine Anmeldung auf

Wow - GREAT. Looks like I'll be working on this on Monday, too.

Kiss my backend, Typo3.

Wednesday, November 27, 2013

Day 11: Extensions galore

Today I worked throught the setup and configuration of two popular Typo3 extensions: Piwik, for statistical analysis of website traffic, and mm_forum, for integrating user forums within the Typo3 project site. I also created my own, first (very simple) extension - a frontend plugin for displaying data from a database - with Extension Builder and Fluid.

Piwik is pretty trivial to install. In the Extension Manager under "Get Extensions", type in "Piwik" and install both "piwik" and "piwikintegration". After restarting the backend, you'll see under "Web" a new module: "Pi (Statistics)". In order to use it, however, you have to do a little configuration. Don't worry - this isn't as bad as the News module.

Click on the root page and on "Template" under "Web". Select "edit the whole template" and then in the tab "Includes", from the box "Available Items", select "Piwik Integration (piwikintegration)" and save. Now you can click on the new "Pi (Statistics)" module and click on any page to see a whole BUNCH of possible data on who, how, when, from where, and why (just kidding) users have visited that page. At first it should be empty - you have to log off as the backend administrator and then surf around as some anonymous user on the front-end in order to generate some data.

The available information is pretty overwhelming: each top-level tab (Dashboard, Visitors, Actions, Reference, Goals) has a plethora of sub-tabs. The "Dashboard" is also pretty busy, with a Wordpress style collection of "widgets" that you can organise yourself.

There are two things I'd like to explore further in Piwik that go beyond the scope of the tutorial: which metrics are valuable, and how? Also, how could you simulate high traffic in order to explore meaningful theses about website visits?

The second extension I got to play around with today, mm_forum, did not offer me the relative satisfaction I had after installing Piwik. After finishing this part of the tutorial, I was left with a lot of WTF moments about the functionality and design. But first things first:

To prepare for mm_forum, you have to create a new system folder somewhere in the page-tree - let's call it "ForumData". If you need a refresher on how to do that, here it is: right-click on the "Typo3" logo at the top of the page-tree. Select "new" from the context menu and then, in the right-hand side mask, select the location where this new folder should appear. The location of the "ForumData" folder is unimportant, so I put it at the same level as the "User" folder. The mask that appears now is where you can enter the title of the new folder. Save.

Now, click on the "User" folder we created a few days ago. Click under "Web" on the "List" module. Here you should create three new user groups specifically for the forum: "ForumAdmin", "ForumUser", and "ForumMod". Save.

Finally, click on the "mm_forum" module under "Web" in order to configure it. The "assistant" will ask you to choose a data storage page - choose the "ForumData" folder - and a User storage page - choose our "User" folder. Now you'll be prompted to select a user group for "default" and "admin": choose "ForumUser" and "ForumAdmin", respectively. You'll be presented with yet another page with lots of tabs and a dropdown in the upper-right hand corner. In the dropdown are choices like "Install" (that's where we are right now), "Board Administration", "User Administration", "Templates", "Tools", "Import data", "Statistics", and "User ranks".

In the "Install" mask we can setup the configuration for user, forum, private messaging, search, file-paths, contact, and cron jobs. The "Board Administration" mask is where we set up forum categories and their message boards. Both category and message board can be configured separately, but a message board will inherit the configuration from its category by default.

For both category and message board you can enter a title, the order in which entries should appear, read-access, write-access and moderation-access. For these latter three, you select user groups - this is where the "ForumMod" user group comes into play. And does not quite work or rather, works so well, that no forum comments can *ever* be approved. Even by moderators.

In order for the forum to show up in your site, you now need to create a sub-page, "Forum", under the "Members Only" (login-form protected) page. Click on the "Page" module under "Web" in order to display the content area. Add a new content area to the "main" section and in the tabs that show up where you can pick out what type of content it should be, click on the "Plugin" tab. Select "mm_forum::Forum".

Click again on "Page" under "Web" and click on "Forum" in the page-tree. Click on the "edit" symbol for the new content. Under the "Plugin" tab, there's a section called "Plugin Options" with a tab (why another tab?) called "Forum Options" with a selection of "What to display". Select "Message Board" and save. To change the styles, click on the "Template" module under "Web", click on the "Includes" tab, and then from "Available Items" select "mm_forum Javascript Prototype", "mm_forum", "mm_forum Stylesheets" and "Page Browser" - in that order. Save.

NOW you will see on the front-end any forums you may have set up in the "mm_forum" module under "Board Administration". Playing around with the forum made a few things clear to me immediately:

I can't figure out how, if comment moderation is activated, the moderater is supposed to approve comments. I set up a user called "mod", categorised them under the "ForumMod" group, and set them up with a real email address (mine). In the "mm_forum" module under "Board Administration" I set up one of the categories to have "Moderation Access" for the "ForumMod" user group. In the front-end, when I'm logged on as a normal user, I can make forum entries and am informed that the comment is awaiting activation by moderation.

The thing is, though, that in NONE of the many places where I might, as moderator, theoretically be able to approve comments, is there a list of comments to approve. Notifications are not sent to the moderator's email (mine) either. Neither in the "mm_forum" module, the page module nor the list module for "Forum" is this a possiblity. Logged on to the front end as moderator also shows nothing different from what the normal user sees.

Another problem is that the styles for the forum suck. Trying to access the forum without having logged in does not prompt you to log in. The information provided by "Praxiswissenschaft" that the mm_forum documentation is available for download under the Extension Manager is not really true, so I'm going to have to devise a plan to fix all the stuff that's bugging me about my new forum.

But not today: the next chapter of "Praxiswissenschaft" is allll about creating your own extensions, and that's what I'm really excited about! I'll spend the rest of the day on that - tomorrow on optimising the forum - and writing about creating your own extensions with Extbase and Fluid, which is pretty cool.

Tuesday, November 26, 2013

Day 10: News with the tt_news extension, more language problems

Today we're going to experience the magic of tt_news: the Typo3 extension for adding a news module to your site with minimal fuss.

Start unter "Admin Tools" / "Extension Manager". From the dropdown on the upper left-hand side, pick "Get Extensions". Type in the search field "tt_news" and click on "Go". There are a lot of extentions with this as part of their name. At the top of the list, however, is the right extension - you can verify this by looking at the column called "key". The "key" of an extension is that extensions unique name.

If you click on the little down-pointing arrow next to "tt_news", you'll get a loooong list of all the versions of tt_news, ever, and their status. Perhaps you will be as astonished as I was to see that the latest "stable" version is from early 2005: "News 2.0.6". The latest of many "beta" versions is version 3.5.1, from late 2013. I picked this one to "import and install". (To import and install, click on the left-pointing arrow under the column "Actions").

After downloading the extension, log off the backend and then log back on. You'll see now on the left-hand side under the "Web" category, a new module "News Admin". Additionally, under "Admin Tools" / "Extension Manager" / "Manage Extensions", you'll see that our list of available extensions has been supplemented with the "News" module. If you click on it, you can configure it. In the tutorial for "Praxiswissenschaft Typo3", however, the default configurations are used.

Now comes the hard fun part. Setting up an actual news site in Typo3 requires a lot of really specific steps. However, it only takes about 10 minutes, and compared to programming a news module from scratch (which I've actually had to do way too many times), the Typo3 news module is actually totally awesome. Here are the steps for setting up a site to display a list of news headers with a short excerpt of text, with a link to another site where one can read the entire article. On the page with the entire article, there's a link to go back to the list of all news.

So, pick the page from the page-tree where we want the news list. I'm going to call mine "Current". Click on the "Web" / "Page" icon on the left-hand side. You'll see the template where you can add new content records to the page. In the "main" section, click on the icon for "add a new record". Now under the tab "Plugins", pick "General Plugin". The page will ask you if you want to reload - yeah, sure, why not.

Now under the tab called "General" you can give the news-page a header. I used "Today". In the tab "Plugin", there's a dropdown labeled "Selected Plugin". Pick "News" out of this dropdown. Save! The "Plugin" tab that's now available has several sub-tabs: "General Settings", "Templates", "Category Settings", and "Other Settings". Under "General Settings" there's a dropdown labeled "What to display". Pick "Standard list view (LIST)".

Now, on the left-hand side under "Web", click on the "List" module. Click on the page "Actual" in the page tree. At the upper left-hand side of the mask, click on the plus, "add a new record". A tree-type list appears where you can pick what kind of content you want to add. Under the header "News", you can pick either "news" or "news category". Pick "news".

This is where can enter actual news content: title, text, etc. Make sure to unclick the checkbox "hide" so that our content will be visible. Save your changes.

Now we need to make a static template for the content. Unter "Web", click on "Template" and the root page. Click on "edit whole template record". You'll see some tabs: pick the tab called "Includes". On the lower right-hand side there's an area called "Available Items" where you can make selections. Select "News Settings (tt_news)" and save.

If you look at the frontend now, you'll just see an error (or in my case, nothing). That's because you still have to go through about 8 more steps to get this thing up and running. In order to see the whole news article that we would theoretically pick from the as-yet not existing news list, we need to create a sub-page under the page called "Actual". Right-click on the "Actual" page and select "Page-actions" -> "add".

In the mask, check "hide in menu", pick from the "Type" dropdpown the type "Standard", and save. Click on "Web" / "Page" now and in the content template in the main content area, click on the plus icon to "add a new record".  Click on the "Plugins" tab. Select the "News" plugin. From the mask that now appears, pick the "Plugin" tab (again - I know that it's gotten confusing) and then the tab "General Settings". There in the dropdown "What to display" pick "Detail view - SINGLE". Remeber to save, otherwise you'll have to start all over again.

Now click on "Actual" again, and "Web" / "Page". In the main content area, click on the edit symbol (the pencil) for the news content item. Click the "Plugin" Tab and then on the "Other Settings" tab. Click on the "folder" symbol next to the label called "PageId for single news display" in order to pick the page we just created for the single-news item. Save!

Think we're done yet?  WRONG. Do the whole song-and-dance for the single-news item subpage under "Actual". For whatever reason, you have to specify in the single-news item page under "PageId for single news display" that the page it should refer to is itself (eye-roll). Additionally, click on the folder symbol near the label "PageId to return to" in order to pick the parent page, "Actual" in oder to generate a useful link that will allow us to return from the single-news item detail to the news list.

NOW we have a usable news module for our frontend whose content can now be easily maintained by editors who lack the insane desire to mess around with the backend. I know that the setup seems... awkward, but it would have taken longer (and been more tedious) to program the same thing from scratch. Typo3 takes care of the things we've done a hundred times before so that we have more time to program new and challenging functionality, refactor and explore! The day's only half done and, again, I've learned something quite useful.

It was really bugging me that the images for the "trailer" had disappeared on introduction of an English-language version of all pages. The disappearance of the static-right hand content (also only from the English-language pages) was bugging me too, so after a few minutes of googling, I found 2 useless suggestions and 1 good one. I'll spare you the former but share with you the secret of my success.

Namely, the root (and other helper-pages like "static-right hand") from which subpages are supposed to inherit, need to have an English-language version too. Copy the content of helper-pages, if there is any, and as far as inherited images go, you need to click on the "Resources" tab of the English-version of the page.

There you'll see a pale version of the image that appears under the "Resources" tab of the original-language version of the page. To the right of this image there's a barely discernable icon called "localize". Click on this, wait a minute, clear the cache and refresh the front-page. Voila... now the site behaves as it should.

This seems to be more of a feature than a bug, but it would have been nice for the "Praxiswissen Typo3" tutorial - WHICH USES A MULTI-LANGUAGE SITE AS ITS EXAMPLE - to have mentioned this tiny little detail.

Next up: configure an indexed-search without being deterred by the trauma left over from setting up the "simple" search form!

Monday, November 25, 2013

Day 9: Multilinguality in Typo3 sites (stupid flags...)

Day 9, chapter 9: let's dive right in, shall we?

Today I'm working through the rest of chapter 9 of "Praxiswissen Typo3", which involves providing various text-elements of the project site in both English and German. In order to do this, all "override" properties (which can be seen in the TypoScript Object Browser) need to be removed, and all properties that have access to the method "lang" need to be so set: "lang.de".

Some properties, such as "badMess" (Javascript error message) and "wrap", do not have access to the "lang" method, so need to be set explicitly in a conditional after all "page" properties have been set. Here is how the search form looks after transformation:

tt_content.search.30 {
#js error if user does not fill out required field (implemented below in dataArray.10)
  badMess = Bitte füllen Sie alle erforderlichen Felder aus.

#text input: required, name ="sword", size=15, maxsize=30, label = "Ihre Suche:"
  dataArray.10 {
    type = *sword=input, 15, 30

#previously: value.override = Suchwort
    value.override.lang.de = Suchwort

#previously: label.override = Ihre Suche:
    label.override.lang.de = Ihre Suche:
  }

...

#dynamically generated graphical submit button
  image = IMAGE
  image.file = GIFBUILDER
  image.file {
    XY = [10.w]+10,20
    backColor = #76001B
   
    10 = TEXT
    10 {
#previously: text = Suche
      text.lang.de = Suche

      fontFile = fileadmin/fonts/Ubuntu-C.ttf
      fontColor = white
      fontSize = 14
      #niceText = 1
      offset = 5,15
    }
  }
}

We have to explicitly set conditionals for the properties "badMess" (and "wrap"). This block of code comes after all page properties have been set:

page {
...
}

#Multilinguality
#if the GP (GET Parameter) is 1 (english), then set the system language id to 1,
#the configuration language to English,
#the local to G.B.

[globalVar = GP:L=1]
  config.sys_language_uid = 1
  config.language = en
  config.locale_all = gb_UK

#english translations for error message and wrap go here

#for our search field overhead on the right-hand side
  page.10.marks.SUCHE.badMess = Please fill in the following fields:
  page.10.marks.DATUM.10.wrap = |, today is the&nbsp;

#for our search form in a page
  tt_content.search.30.badMess = Please fill in the following fields:
  tt_content.search.30.image.file.10.text = Search
[global]

Is this all making sense? I find it logical TODAY, but it's all built on 5 days of non-stop intensive TypoScript-learning.

The next step is to replace the language menu, whose current values are links of the text "English" and "German", with two small images of flags (of England and Germany, of course). The mark for the language menu, "###SPRACHE###", needs to be initialised as an HMENU object whose first and only level is graphical (i.e., GMENU).

Note here that there is yet another type of menu defined by "special": we've seen "special = directory" for the classical menu and "special = rootline" for an inline menu, but now we have "special = language", for a language dependent menu.

#language menu    
      SPRACHE = HMENU
      SPRACHE {
        special = language
        special.value = 0,1
       
#normal status of first (and only) level of the language menu - it's graphical        
        1 = GMENU
        1.NO {
          XY = [10.w]+2, [10.h]+2
          backColor = white

#our language menu is made up of two images:
#the German and the English flag for German and English (duh)        
          10 = IMAGE
          10.file = fileadmin/flags/de.gif || fileadmin/flags/gb.gif
          10.offset = 2,2
        }
       
#active status, language menu      
        1.ACT = 1
       
#take properties from the normal status of the language menu
        1.ACT < .1.NO

#override the effect so that the active (currently selected) language shows is greyed out
        1.ACT.20 = EFFECT
        1.ACT.20.value = gray | gamma=1.5
      }

This sort of worked. On the homepage, the correct flag was greyed out depending on what language I had selected. On all other pages, however, only when "German" was selected was a flag greyed out at all (it was the correct one). The flag for "English" stayed bright an colorful on all pages, except the homepage, after being selected. WTF?

I decided to experiment and to create English versions for the other pages - at least the menu title should be translated, by my logic. This is done by clicking on "Page" under the "Web" module on the left-hand side. On the upper left-hand side of the mask that appears, there is a drop-down with the choices "Columns", "Languages" and "Quick-edit". Select "Languages". Another dropdown labelled "make a new translation of this page" allows you to select one of the languages that has been set for the site-root (represented in the page-tree with the Typo3 icon). Select "English".

You are now shown a page with the title "Create new Alternative Page Language". Enter a title in the textfield "Page Title" (obviously). Make sure that the visibility is enabled under the tab "Access" and then save your changes.

NOW, when you click on the page in the frontend of which you just created an English "translation", and pick the English flag icon - IT STAYS GREY! Logically, in order for the selected page to represent the selected language, you have to actually have a translation of that page in the selected language.

One problem with this is that now the header images are gone. (Cries). Do I have to set those up for the English-translation pages too? When I switch the language via flag to "German", yep... the images are still there. I think I'm going to work on setting up user-protected areas now: pages whose content is protected with a login form and a list of permitted users. Also: dynamically-generated print-versions of every page, with just a few lines of TypoScript in the root template.

Four hours later...

Stay tuned for tomorrow's Typo3 excitement, as I attempt to install the tt_news plugin, whose last stable, non-beta version was uploaded in 2005!

Thursday, November 21, 2013

Day 8: the search-form from hell, static-dynamic content, a customised backend

Part I: the Search-Form from Hell

I spent the first half of the day today trying to figure out why my search-form wouldn't work. Most of that time was spent wrong because I was searching for "indexed search function", whereas the functionality referred to in "Praxiswissenschaft" happens to be the normal, non-indexed one.  In the end, I did 3 things that possibly caused the form to eventually work:

1) I deinstalled the extension "indexed_search" that I had installed yesterday in the belief that it was needed.

2) in the file typo3_src/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php I changed line 732 of code from this:

$content .= $hookObj->cObjGetSingleExt($name, $conf, $TSkey, $this);

to this:

$content .= $hookObj->cObjGetSingleExt($name, (array) $conf, $TSkey, $this);

This change was based on a tip that I found via google that seems to address the error message I kept getting: that a second argument was expecting an array and receiving something else.

This change caused the page to go from displaying an exception error to displaying the page with the marks for the searchform, "###SUCHE###", instead of the actual search form itself.

3) Finally, the tip that Meyer's book gives, and also to be found in several pages via google, is to deinstall the "form" extension. When I did that yesterday, in place of an exception I got an internal server error instead, which is actually worse. Today was the same thing. Only after lunch, by following steps 1 and 2 again, and then (again) deinstalling the "form" extension, did the search form finally work.

Logically, this should have happened yesterday as I had followed steps one and two, before installing the indexed search. The ways of Typo3 are shrouded in mystery!

Now I am free to continue the "content" chapter of "Praxiswissenschaft".

I found out a way to supplement the root template TypoScript without literally typing it in the text area: under "Template" for the root page, select "TypoScript object browser" instead of "Info/Modify". Click on the TypoScript object you'd like to modify and a form comes up called "Edit object/property value". Enter the object property in the text field and click up "update". In the root template, the correct code for this property attribution can now to be seen. 

Using this method to change properties is a good way to avoid the typos and mistakes of typing code in by hand; however, it does not have the benefit of code-organisation that can be attained by doing the same thing manually. Additionally, clearing and reseting values in this way makes a mess of the TypoScript in the template textarea, much like creating HTML markup with a WYSIWYG editor. I'm going to decide for clean code and write my TypoScript by hand - I need the practice, anyway.

Part II: Static-Dynamic Content

In order to create a content area that appears on every page (for example, news items on the right-hand side of each page) whose content is dynamic, a mark within the template is necessary, but does not alone suffice. It's also necessary to, once again, set up a helper-page, just below the root page in the site structure. This new helper pages's properties include being of type "shortcut", redirecting to the homepage if called directly in the browser, having enabled visibility, and yet be hidden to the menu. This last property can be achieved by selecting the "Access" tab within the "Page" section and then checking the box "In Menus - hide". Finally, in order to bind this helper page's content into the template that is used by all pages, the following code needs to be implemented:

#make "RECHTS" (right-hand side) marker a content object array
      RECHTS = COA

#read out the content of right-hand column of the current page into the RECHTS marker in all positions
      RECHTS.10 < styles.content.getRight
      RECHTS.20 < styles.content.getRight

#the content of the right-hand-side column should, however, only be read from a list of pages whose page IDs are explicitly set below
      RECHTS.20.select.pidInList = 17

It's additionally suggested that in order to prevent the contents of this page from being cached, which would prevent new content from appearing without first manually emptying the cache, the object type COA_INT instead of COA can be used. 

Part III: customising your backend (ha!)

In order to create a customized backend layout to make content management for editors easier, click on the "List" module under "Web", and then click on the "root" page. In the upper left-hand corner to the new window, click "create new record". A list of possible types appears; select under "System records" the type "Backend layout". There, enter a name for the customised template and then click on the image next to the text field under the label "configure". This will open up a new window where columns and rows for a table can be defined: each cell of this table needs a name and a unique column number.

After saving this configuration in the new window AND in the opening window (otherwise, the work is lost - I had to find this out on my own), click on the root page and select "edit" from the context menu. Under the tab "Appearance", it's now possible to select the new template as "Backend Layout (this page only)" and "Backend Layout (subpages of this page)". Remeber to save! Clicking on the "Page" module under "Web" and selecting the root page will now show the new template for entering content, instead of the the default one. In this way, it's possible to customise content-entry forms and make them more user-friendly for editors.

Prologue

Today I got through one chapter of "Praxiswissen", with one major problem (the non-functionting, error-causing search form) and two minor ones: getting the dynamic right-hand area of every page to show the same content (I had initially put the new right-hand content area in the homepage instead of in the root document) and not being able to FIND the area for adding a customised backend layout (the instructions in the book skipped the step of getting to the "System records" list of choices). I was able to solve them with a little experimentation and a lot of googling. 

The seas have calmed, wind and weather are good, routine has entered the daily course of being on board the Hackership and I am actually learning somthing practical.

The first two weeks are over, four to go. Will I have time to immerse myself in test-driven development with PHPUnit? Will I be able to figure out how to configure my Jenkins CI server to run these tests as jobs? I think I'm going to have to invest in more resources (i.e. e-books). Without "Praxiswissen" my ship would have, by now, floundered on the rocks of bad documentation with no help in sight. 

Who's sick of the seagoing metaphores already? 
Too bad!


Wednesday, November 20, 2013

Day 7: ImageMagick, Navigation, lots and lots of TypoScript

Day 7: smooth sailing with "Praxiswissen Typo3"

It was really bugging me today that the dynamic graphical part of the project wasn't working. I rechecked the code and found, first of all, that some of my code was nested falsely.  After fixing that, it still didn't work, so I read through the chapter again and figured that my problems must be with ImageMagick: namely, the mask underneath the image, "nicetext", and image inheritance from the root page as defined by TypoScript IMAGE object properties were not working.

I checked out which version of ImageMagick is installed on my computer by typing on the command line:

identify -version

According to the output, I have ImageMagick version 6.7.7-10.  After some more googling (for "ImageMagick nicetext") I found the perfect solution. Pretty much, ImageMagick will only function on the root server with a certain Typo3 configuration:

[GFX][gdlib] = 1
[GFX][gdlib_png] = 1
[GFX][im] = 1
[GFX][im_version_5] = im6
[GFX][im_negate_mask] = 1
[GFX][im_imvMaskState] = 1
[GFX][im_no_effects] = 1
[GFX][im_v5effects] = 0
[GFX][im_mask_temp_ext_gif] = 1

Especially important is the configuration "[GFX][gdlib_png] = 1". I called up the Typo3 install tool in the browser, logged on, and under "All Configuration" searched for these values to see how they were set. Lo and behold, in my configuration, [GFX][gdlib_png] was set to 0.  I changed this and refreshed my Typo3 project and voilá - it is now working as it should.

On to creating the navigation menus, dynamically of course!

Something I've discovered today is that, in order for the menus to be shown, the "helper sites" I created yesterday need to be set to VISIBLE, not, as I interpreted from the tutorial, have the visibility deactivated.

In order to create my first menu - the single-layer, overhead text menu - I had to 1) specify an object of type HMENU, 2) set the properties of this new menu object so that it is a "directory" or classical menu, 3) set the root of this "directory" to the page ID of the root page and 4) specify that the first (and only) layer of the menu is a text menu with "normal" state activated.  The TypoScript code to do this is as follows, and is inserted within the "marks" section of the TypoScript:

marks {
...

#upper text-menu
  MENU_OBEN = HMENU
  MENU_OBEN {
         
#directory, or classic menu
    special = directory
       
#page-id of the menu root      
    special.value = 2

#this menu has only one level, which is a text-menu, with normal (NO) state activated    
    1 = TMENU
    1 {
      NO = 1
      NO.linkWrap = |
    }
  }
...
}

The pipe symbol | stands for dynamic content that can be, if desired, "wrapped" within html code, such as bold tags, or an empty space. To seperate individual links with an empty space, write in the place of "NO.linkWrap = |" the following line of code:

NO.linkWrap = &nbsp;|

For bolded content, write:

NO.linkWrap = <b>|</b>

In order, however, to use a stylesheet on the generated menu links, use the property "ATagParams" on the "normal" property of the textmenu, for example:

NO.ATagParams = class="left_white"

Building up the left-hand side graphical menu requires a bit more code in order to dynamically generate the text as images and to have a normal, rollover, and active state for each link. My TypoScript works for the normal and active states of the generated links, but rolling over the links with the mouse in the browser has no effect. When I look at the HTML source code, I see that on "onMouseover", the same image is being called as on "onMouseout". After a lot of googling, I'm not any further. Testing in Firefox gives the same results, so it's not necessarily related to the browser.

Here's the code for generating a graphical menu. It differs only slightly from the code for a text menu, in that the object GMENU (graphical menu) is used in place of TMENU (text menu) and that within the "1" section, there are also definitions for the rollover (RO) and active (ACT) states of the links.  This menu, too, is placed within the "marks" code section.

marks {
...
  MENU_LINKS = HMENU
  MENU_LINKS {
    special = directory
    special.value = 3  
    1 = GMENU  
    1 {
#describe normal state        
      NO = 1
...
#define rollover (RO) state
#copy normal (NO) properties
      RO < .NO
#redfine the properties for rollover only where they differ from the normal (NO)
...

#define active (ACT) state
      ACT < .RO
    }
  }
...
}

On to developing a second level for the graphical navigation. This requires the setting of a second GMENU and its properties, along with the descriptions for its normal (NO), rollover (RO) and active (ACT) states. It's possible to do this in TypoScript without redundant typing with the following line of code

2 < .1

which means: "2", or the second level, is also a GMENU object whose properties are exactly the same as the "1" GMENU object.  We are then free to overwrite only the properties that differ from those of GMENU object "1":

2.NO {
  XY = 230,25
       
#white background
  5 = BOX
  5 {
    color = white
    dimensions = 10,0,200,25
   }
         
#change text styles        
   10 {
#set text styles (case) back to nothing
     text.case >
     fontSize = 12
     offset = 20,16
   }
}
       
#rollover and active state
2.RO < .2.NO
2.RO.10.fontColor = #a90329
       
#active (ACT) state for level two in the same as the rollover (RO) state      
2.ACT < .2.RO
     
       
For setting up a breadcrumb trail, the process is similar, since it is also a type of menu. In order to differentiate between the breadcrumb-style and classic-style of menus, however, we need to set the "special" property to "rootline" instead of "directory". Here's the basic code which, you can see, is similar to the syntax for the overhead text-menu:

KLICKPFAD = HMENU
KLICKPFAD {
  special = rootline
  1 = TMENU
  1 {
    NO = 1
...
  }
}

Blend the VISIBLE helper-pages out of the breadcrumb trail with a line of TypoScript which specifies from which level the page navigation should begin and where it should end:

special.range = 2|-1

Start at level 2, since the root helper page is at level 0 and the two helper pages for template inheritance can be found at level 1. "-1" ("forever") indicates that all remaining levels can be shown.

Changing the object type of "KLICKPFAD" from HMENU to COA (content object array) makes it additionally possible to set up a sequential list of multiple object types (like TEXT, IMAGE and, yes, HMENU) and their properties, instead of being limited to only the properties assignable to HMENU. This lends an enormous flexibility to scripting the display of a Typo3 site. Here's an example of that.

#create breadcrumb menu as content object array
KLICKPFAD = COA
KLICKPFAD {

#in first position, we want to see some text
  10 = TEXT
  10.value = You are here:&nbsp;
       
#in second position, we want a text menu
  20 = HMENU
  20 {
    special = rootline
    special.range = 2|-1
         
    1 = TMENU
    1 {
      NO = 1
...
    }
  }
}

These blog entries are getting longer (and more professional from a programming standpoint. Less so, from a literary one). I still have a few hours to go on with the tutorial, but I will continue with that tomorrow: chapter 8 of @Robert Meyer's "Praxiswissen Typo3" - "Content".

Tuesday, November 19, 2013

Day 6: like a beacon of light through the gloom

Day 6: working and getting things done with "Praxiswissen Typo3"

Feeling much more enthusiastic today, as last night I studied two chapters of @Robert Meyer's "Praxiswissen Typo3 Version 6.0": chapter 3 "Das Backend kennenlernen" and chapter 4 "Das Praxisbeispiel vorbereiten".  I got through about half of the fifth chapter, "TypoScript in der Praxis" before going to sleep.

Translation: @Robert Meyer's "Typo3 in practice" has been like a beacon of light through the gloom for me.  "Getting familiar with the backend" was review, but "preparing the practical project" once again gave me hope that I will soon be programming something useful. Namely he describes, in an acutal step-by-step manner, how to set up a Typo3 website for a fictional snowboarding school with the following features:


  • Layout in HTML and CSS, with dynamic elements written in TypoScript
  • Two dynamically-generated menus: one single-level text menu overhead and one double-level graphical menu on the left-hand side
  • A dynamically-generated grafical trailer, based on the site currently being browsed
  • A dynamically-generated information area, based on current site, with last 3 most current news items
  • Dynamically-generated news-items
  • A search function with the ability to search PDF and Word documents available through the site
  • A dynamically-generated sitemap
  • Bilinguality: each page of the site should be available in both English and German versions
  • Print-versions of every page
  • A breadcrumb-type display from which the user can always infer where they currently are within the site structure
  • Time-dependent greeting ("Good Morning", "Good Afternoon" or "Good Evening")
  • A protected area for authenticated users
  • A user-friendly backend interface for site-editors
  • Later - replacement of HTML templates with templates created by TemplaVoila


This practical project covers the basics of most Typo3 sites and gives me a concrete structure around which I can organise my learning. I'm so excited!

First steps: downloading and installing the dummy-site and source from Typo3, as well as configuring, was incredibly easy after the hellish first-run with the introductory package. After logging in to the new backend, under "File" - "Filelist", I then uploaded the directories "css", "fonts" and "css" under "fileadmin", as instructed by the tutorial.  The necessary image and css-files were available for download from the site for the book. Instead of downloading the html template with TypoScript already written, I downloaded only the static html template and made the changes demonstrated in the tutorial by hand, in order to get a feel for TypoScript "marks" in template construction.

Now it's time to build the navigation structure. In order to make a menu-tree that is as flexible as possible (for editors to supplement with additional pages), it's necessary to create a top-level menu item as a "helper page" for each menu that should appear in the website. In this case, we have two menus - one menu overhead, and one on the left-hand side. These top-level "helper pages" will not be seen by the user; rather, they serve as constructs on which to hang things (like templates, or other properties), which will be then be inherited by all sub-pages in the menu.

Because we want to avoid duplicating code, we will attach these two helper-pages not directly to the root page itself (to which templates can not be directly attached), but to a third helper site, directly attached to the root, from which both menu helper-pages will inherit. It is with this top helper page that we will associate the template to be inherited by each menu helper page and, in turn, their respective sub-pages.

Not only should these three helper-pages not be visible to the user, they should also not be callable to the user. In order to enable this, we need to set the types of these pages from "standard" to "shortcut". This ensures that, should the user call these pages explicitly (by ID), the user will be forwarded to a site that is OK to see: in this case, the homepage. I found out, though, that disabling the visibility of the root page will cause an error in the front end. I reverted it back to "visible", which allowed me to continue with the tutorial and also try out the various TypoScript examples provided by the author.

To elaborate on yesterday's puzzlement about WHERE to write TypoScript:

On the left-hand side navigation, click on "Template" under "WEB". Now click on a site you want to modify: in my case, this was the root document. A page will appear on the right-hand side with a dropdown at the top left corner of the page. From this dropdown, pick the selection "Info/Modify". Now click on the "pencil" symbol next to the word "Setup". A page will appear called "Template tools". Here, there is a textbox where you can write TypoScript! Here is a very simple example:

page = PAGE
page.10 = TEXT
page.10.value = Hello World!

After writing this TypoScript, you can save by clicking on the disk-symbol on top of the page, and then on the symbol of what looks like a page with an eye over it.

It's that simple. A real, step-by-step set of tasks that a Typo3 learner can go through, one by one.  Meyer's book even illustrates these instructions with screenshots, pretty much making the example idiot-proof.

Back to the project: the integration of the static html template (with TypoScript in certain areas) is also done via TypoScript, namely:

# Default PAGE object:
    page = PAGE
   
# Define output for typeNum=0, the default type.
page {
    page.config.doctype = html5

#Metatags
    meta.author = Robert Meyer, Martin Helmich
    meta.description = Hier steht eine Beschreibung
 
#integrate HTML Template
    10 = FILE
    10.file = fileadmin/vorlage.html
}

When I look at the generated html code for this page, I see correctly-formatted HTML tag for HTML 5 as well as meta-tags for "author" and "description". There is, however, a problem, and that is that the html template has its own html and body tags, which leads to a doubling of these tags in the source code, i.e., incorrect HTML.  Meyer goes on to explain how to solve this problem: namely, we need to work with "Teilbereiche", or... part-parts? Sub-parts, maybe. In order to do this, we need to insert a TEMPLATE object with TypoScript.  This TEMPLATE object receives a string from the FILE object and can use its property, "workOnSubpart", in order to extract the part within the html template that we have designated as being such. The code of this designation within the html template looks like this:

<!-- ###DOKUMENT### begin -->

<!-- ###DOKUMENT### end -->

with HTML code between these two designations.

Here's the TypoScript code we need to write in "Setup" text area (as described above):

# Default PAGE object:
page = PAGE
   
# Define output for typeNum=0, the default type.
page {
    page.config.doctype = html5

#Metatags
    meta.author = @Robert Meyer, @Martin Helmich
    meta.description = Hier steht eine Beschreibung
 
#integrate HTML Template
    10 = TEMPLATE
 
    10 {
        template = FILE
        template.file = fileadmin/vorlage.html
        workOnSubpart = DOKUMENT
    }
}

With the TypoScript PAGE object function "includeCSS", you can include a stylesheet uploaded previously into fileadmin/css:

page {
...

#include css stylesheets
    includeCSS {
        screen = fileadmin/css/style.css
        screen.title = display
        screen.media = screen
    }

...
}

which results in the inclusion of the following link in the HTML source-code:

<link rel="stylesheet" type="text/css" href="fileadmin/css/style.css?1384858913" media="screen" title="display">

It's only 3pm and I've accomplished more today up to this time than I did the entire day yesterday. @Robert Meyer has just become my new Typo3 hero.

Replacing the "marks" within the html template is as easy as calling the "marks" property (method, actually) within the PAGE element and setting its object type and its value:

page {
...
    10 {
        ...
        marks {
            DATUM = TEXT
            DATUM.value = 19. 11. 2013
        }
    }
}

The mark "DATUM" can be found in the HTML template within "div" tags as

###DATUM###

Later, the hard-coded value for the date will be replaced with a dynamic value, made possible by the use of TypoScript functions. TypoScript functions can also be used for, among other things, reading values from fields in the database or getting POST and GET values. In order to do this, the property of the mark needs to be "data" instead of "value". The syntax for  creating a dynamic date in TypoScript shares similarities with the syntax for formatting a date with the PHP date() function:

page {
...
        marks {
            DATUM = TEXT
            DATUM.data = date:d.m.Y
        }
...
}

For the rest of the day, I worked through chapter 6 - working with dynamic images in Typo3. Unfortunately, about 30% of the example code didn't work. Some of the hints for fixes for -older- versions of Typo3 worked for me, even though the version of Typo3 that I have is newer than that in the book. I know that there is little point in posting these questions on the Typo3 forum.  Instead, I'm going to move on to the next chapter tomorrow, about setting up dynamic navigation.

I accomplished so much more today and feel accordingly energetic and optimistic.  Thank you, @Robert Meyer!