分享

1.2. The Basics

 淮橘为枳 2007-03-21

Introduction

This section will quickly introduce the newbee to how TYPO3‘s frontend works. What are TypoScript Templates, what are content objects, what are HTML-templates. If you know these basics well already, you can skip ahead to the next section, "Integration of an HTML template". However you will need to install the dummy-package and create a set of pages inside. This is discussed below.

Skill level

All developer newbees to TYPO3 regardless of experience in other fields.

Some parts will refer to technologies like SQL, HTML, CSS and PHP. The content is generally of a technical sort since it takes you through the installation of the dummy-package and explains the basics of the frontend template engine in TYPO3.

Getting started - install the "dummy" package

To get started real quickly we will install a blank file framework and database for TYPO3 and the best way to do this is by using the "dummy" package. A "package" consists of the general TYPO3 source code mixed with local site related files and possibly database content - altogether comprising a full website. In the case of the dummy-package this will be a empty website with no content. But that is highly useful for starting up new projects.

So get the dummy-package and install it on your webserver. After unzipping the package you just hit the index.php file and you will be guided through these steps.

Enter database information:

Create a new table:

Import the dummy database, "database.sql":

Go to the backend:

For these steps to complete nicely you will have to make localconf.php writable (you will be told if it isn‘t!) and have the database username and password at hand.

Creating a page structure

The first thing to do now is to create a page structure we can use for this tutorial. A good page structure contains pages on at least two levels. However we must start with a root page in any case:

Enter a page title, unhide the page and save it:

You could proceed in this way to create your page structure. However there is a great wizard for doing this much easier. Just go to the "Functions" module, select wizards and the "Create multiple pages" wizard, enter a bunch of page titles and press the "Create pages" button.

(The "Create multiple pages" wizard requires the extension "wizard_crpages" to be installed.)

This should result in this nice page tree:

Now, create a new more pages so you have something like this:

Page Tree and Template Records explained

Click a page icon and select "Show":

The result from viewing the "Licensing" page will be a screen something like this:

The page "Licensing" had the uid "5" and viewing the content of that page is done by sending the "id=5" parameter to the index.php script of the frontend.

Now, the message is "No template found". This means that the frontend engine did not find any template record in the rootline of the page tree from the page with id 5. This calls for a little theory to explain:

TYPO3 is a multi-site CMS which means that you can have any number of separate websites contained in the same page structure. Each website in the page tree must have a root page which is indicated by placing a template record on that page. This template record must have the "Rootlevel" flag set. So when a template record with the "Rootlevel" flag set is attached to a page it simply means that "from this point and outwards starts a new website in the page tree".

The root line is another word for "path". For instance you might say that the page "License A" in my page structure has the path "TYPO3 > Root page > Licensing > License A". And if we send the id of the "License A" page to the index.php script, the frontend template engine will search the root line from the "License A" back to the page tree root for a template record that will define how this branch of the page tree should be rendered.

Creating a Template Record

So what we will do now is to create a template record on the page "Root page". The most easy way is to use the "Template" module:

The next screen will show you this view from the "Template" module. You will use this for editing the template record later:

For now, look at the "Root page" with the "List" module instead:

As you can see there is a "Template" record located on the page "Root page".

This template record will contain the basic instructions to the frontend engine about how the website beginning from this point should be rendered, which features it has, how it is configured, etc. A template record is always needed to start any new website in TYPO3 (using the default frontend engine). However you can personally balance how much of your website design the template record will control directly; you can program a whole website directly inside a template record. You could also instruct the template record to immediately call a PHP function you have created which will render and return all the page content (based on XML, XSLT or other databases - whatever you fancy). You can also choose a middleway mixing the best of both worlds. This is what we do in this tutorial.

Looking at the content you will see these fields of specific interest:

The "Template title" is just the title of your template record - not displayed anywhere.

The "Website title" will be a prefix of the page title as found between the <title> tags of any page.

The "Setup" field is where you enter the instructions that make the frontend engine react in a certain way. These instructions are contained in a hierarchical information structure defined by the TypoScript syntax. Since the instructions from the "Setup" field is defined by the TypoScript syntax you will often find template records referred to as "TypoScript templates".

The "Clear constants" and "Clear setup" flags means that no TypoScript configuration code is inherited from template records earlier in the tree (closer to the root), if any. These flags should always be set for template records serving as main templates ("Rootlevel").

The "Rootlevel" flag simply means: "This template records marks the start of a new website".

Now, back to the viewing of the page "Licensing":

Now, something different popped up. This is what happend:

  • Request page with uid "5" (#1)

  • Select the first template record on this page (pid=5); Nothing found!

  • Since no template record on page with uid "5" was found, check the previous page in the root line.... (#2)

  • Select the first template record on this page, "Root page", (pid=1); A template record was found!

  • Since a template record was found on page with uid "1", check if the "Rootlevel" flag was set...

  • Yes, the "Rootlevel" flag was set. Fine, this is the start of a website. So...

    • Parse the TypoScript configuration of the Setup field.

    • Begin executing the instructions from the Setup field.

Basics of "Setup-field" instructions

When a template record is in place the main point of interest now is the "Setup" field of that template. In this field you enter a set of instructions that will determine what happens when we hit a page in the frontend.

The best way editing this field is by the Template module using the Info/Modify view:

Click the edit icon and lets go:

Here comes a short explanation:

The PAGE object (#1)

First we define a new "Toplevel Object" (TLO) called "page". Object type is "PAGE" (you can also define a FRAMESET, see TSref). Instead of "page" you could use other strings except a list of reserved TLO‘s, see TSref about Toplevel Objects.As a property for the "page" object we define the obligatory property, "typeNum", and set its value to 0 (zero).

What all this means is that the Toplevel Object "page" will now be the default handler of any request sent to a page within the branch of the page tree where our template record marks the beginning of a website.

Now we want to instruct the "page" object what to do. Basically we need to look up the possible properties for PAGE objects in the TSref. Some properties are meta properties like the "config" or "includeLibs" property. Others are there to define what HTML output this PAGE object will generate.

The most significant set of properties for PAGE objects is the numerical array of content objects (cObjects). Each of these content objects can render a string of HTML-content which altogether makes up the content between the body-tags of the page.

The Content Object (#2)

In the example above there is a very simple content object  - TEXT - defined for the index "10" of the numerical array of content objects  in the PAGE object, "page". This cObject has the property "value" set to "HELLO WORLD!". The effect is that this string is returned from the cObject and becomes the content between the page bodytags:

You can see the set of properties for the TEXT cObject here.

TypoScript - no programming language

Before we move on; please notice that TypoScript is not a procedural programming language. You might easily be lead to think this and if you have experience with other programming languages and how they work this is a dangerous cocktail since you will be quite confused. In reality, TypoScript merely configures the system to act in a certain way.

In order to explain what TypoScript really is and point you to the difference between this and how it is used in TYPO3, you can look in this document explaining the basics.

More examples of PAGE and cObjects

This section will just take a few more examples of PAGE and cObjects in order to let you grasp the concept fully. Understanding this allows you to understand "TypoScript templates" when the structures become more complex.

Two cObjects?

What happens if you enter another content object:

# Default PAGE object:
page = PAGE
page.typeNum = 0
# Content object one:
page.10 = TEXT
page.10.value = HELLO WORLD!
# Content object two:
page.20 = TEXT
page.20.value = HELLO UNIVERSE!

(BTW, lines starting with "#" or "/" are comments.)

Output:

<body bgcolor="#FFFFFF">
HELLO WORLD!HELLO UNIVERSE!
</body>

So - as expected more content objects will just be concatenated!

Changing order?

What if the order of definition is changed?

# Default PAGE object:
page = PAGE
page.typeNum = 0
# Content object two:
page.20 = TEXT
page.20.value = HELLO UNIVERSE!
# Content object one:
page.10 = TEXT
page.10.value = HELLO WORLD!

Output:

<body bgcolor="#FFFFFF">
HELLO WORLD!HELLO UNIVERSE!
</body>

The same - the order of rendering is according to the index in the array.

Dynamic content?

What if we want the TEXT cObject to insert the page title?

Then you will have to look up in the TSref to see if the TEXT cObject has any properties that allows you to instruct it to do so. It seems that it has. Apart from the "value" property on the same level the TEXT object also has "stdWrap" properties (click here) which can be used to fetch and process data dynamically.

Since the rendering of the cObject TEXT is done in the main scope of the PAGE Object the current record will be the current page record. So referring to a fieldname with the stdWrap property "field" will fetch content from the current page‘s record. Here the field named "title" will carry the page name (this of course requires knowledge about what fields are available in the pages table!):

# Default PAGE object:
page = PAGE
page.typeNum = 0
# Content object outputting current page title:
page.10 = TEXT
page.10.field = title

Output:

<body bgcolor="#FFFFFF">
Licensing
</body>

Since the current page was the "Licensing" page, that was the title in the output!

stdWrap properties

Now that we are playing with the "stdWrap" properties we can wrap the value, process it in different ways etc:

# Default PAGE object:
page = PAGE
page.typeNum = 0
# Content object outputting current page title:
page.10 = TEXT
page.10 {
  field = title
  crop = 8 | ...
  case = upper
  wrap = This is the truncated page title: <b> | </b>
}

(Notice how I changed the formatting in TypoScript so the properties was encapsulated in curly braces. This syntax of TypoScript makes it easier to assign many properties on the same level but the end result is no different from prefixing all the properties with the full object path "page.10".)

Output:

<body bgcolor="#FFFFFF">
This is the truncated page title: <b>LICENSIN...</b>
</body>

Notice how the wrapping string was wrapped around the page title which was further set in uppercase and truncated to max. 8 chars with "..." appended!

We could have achieved the same output by another cObject called "HTML" - the only difference is that all the stdWrap properties are properties to the "value" property of the HTML cObject - not properties of the cObject itself:

# Default PAGE object:
page = PAGE
page.typeNum = 0
# Content object outputting current page title:
page.10 = HTML
page.10.value {
  field = title
  crop = 8 | ...
  case = upper
  wrap = This is the truncated page title: <b> | </b>
}

It‘s a question of personal preference and style whether you use TEXT or HTML cObjects.

Content from PHP scripts

You can easily insert content from PHP scripts if you like to. This is a very recommended practice if you need conditional output just a little above the most basic level since the cObjects and their properties doesn‘t offer "procedural programming" at all - remember they are just pre-programmed objects reacting on a set of properties, nothing more.

So the USER cObject is what you need.

First, lets create a PHP-file in fileadmin/userfunctions.php:

<?php
class user_functions {
/**
 * Multiplies the current page ID with $conf["factor"]
 */
function multiplyTest($content,$conf){
$currentPageUid = $GLOBALS[‘TSFE‘]->id;
$factor = intval($conf[‘factor‘]);
return $currentPageUid * $factor;
}
}
?>

Then lets configure a cObject of the type USER to call this function with a single parameter, "factor":

# Default PAGE object:
page = PAGE
page.typeNum = 0

page.includeLibs.some_random_id_string = fileadmin/userfunctions.php

page.config.admPanel = 1
# Content object outputting current page title:
page.10 = HTML
page.10.value = The page ID, {field:uid}, multiplied with 15 is:
page.10.value.insertData = 1
page.10.value.wrap = <b> |</b> <br />

page.20 = USER

page.20.userFunc = user_functions->multiplyTest

page.20.factor = 15

And the output should be:

As you can see we defined a few "meta-properties" not directly related to content output:

page.includeLibs.some_random_id_string = fileadmin/userfunctions.php
page.config.admPanel = 1

"includeLibs" is a property that allows you to configure a list of PHP-files (classes and function libraries!) to be included before starting the rendering of the page. "config" allows for a whole lot of configuration options about general behaviour of this PAGE object. In this case the Admin Panel was added in the bottom of the page.

You really should take a few minutes to look at this example. Notice how the property "factor" of the USER object was available in the PHP-function. Notice how the PHP-function retrieves the page ID. Notice how the "admin panel" was included. You can learn a lot from playing a little with this example. Let your fantasy loose for a while since this can give you a good feeling of control.

The Object Browser

The Object Browser in the Template module is an indispensable tool for verifying the hierarchical information structure of your template records:

As you can see the TypoScript values are parsed into this nicely organized tree. This lets you verify if every property you have set is at the correct place and even allows you to edit a single value if you make sure "Enable object links" is checked:

Going back to "Info/Modify" you can see that the template Setup field has been modified:

The Object Browser is not intelligent enough to go and change the line with "page.20.factor = 15" - it just inserts a new line in the end which will override any previously set value. You can clean it up manually. The whole point is that the Object Browser provides a fool-proof way of setting these values since the correct object path will always be used.

Try a condition?

We could in fact use this situation to demonstrate "conditions". A very basic condition is to check for the browser:

# Default PAGE object:
page = PAGE
page.typeNum = 0
page.includeLibs.some_random_id_string = fileadmin/userfunctions.php
page.config.admPanel = 1
# Content object outputting current page title:
page.10 = HTML
page.10.value = The page ID, {field:uid}, multiplied with 15 is:
page.10.value.insertData = 1
page.10.value.wrap = <b> |</b> <br />
page.20 = USER
page.20.userFunc = user_functions->multiplyTest
page.20.factor = 15

[browser = msie]

page.20.factor = 30

page.10.value = The page ID, {field:uid}, multiplied with 30 is:

[global]

In Microsoft Internet Explorer this will look like:

In all other browsers it looks like:

PAGE object revisited

Well, this should not be a full fledged course in making template solely by cObjects - in this manual we will mainly use the TEMPLATE, USER and HMENU cObjects and combine them with predefined TypoScript code from static templates to meet our objectives. The final autority on objects and properties is the TSref and if you want examples of usage for each object-type please look in TypoScript by Example.

However I would like to finish off with two points:

The significance of "&type="

In this example below there is not only one PAGE object defined. Also the TLO "another_page" is defined as a PAGE object but the "typeNum" property is set to "1". This means that the "page" PAGE object is the handler of default page requests while the "another_page" PAGE object becomes the handler of page requests where the "&type=1" parameter is set in addition to the id-parameter:

page = PAGE
page.typeNum = 0
page.10 = TEXT
page.10.value = HELLO WORLD!
another_page = PAGE
another_page.typeNum = 1
another_page.10 = TEXT
another_page.10.value = HELLO UNIVERSE

The output will be:

And the object tree:

Copying objects

Quickly it becomes very practical to divide the TypoScript configuration code of your templates into related units and then assemble them all in the end of the template by copying them into the right positions. This might even include separation of the units into a hierarchy of included template records or static templates thus allowing for reuse of TypoScript. You will learn about that later.

The main feature of TypoScript that allows this is the syntax for copying one branch of the object tree to another. Consider this example:

# Make temporary version of the first cObject:
temp.world = TEXT
temp.world.value = HELLO WORLD!
# Make temporary version of the second cObject:
temp.universe = TEXT
temp.universe.value = HELLO UNIVERSE!
# Default PAGE object:
page = PAGE
page.typeNum = 0
page.10 < temp.world
page.20 < temp.universe

The result is - of course - this:

<body bgcolor="#FFFFFF">
HELLO WORLD!HELLO UNIVERSE!
</body>

If you look in the object browser you can see, that the objects from "temp. ..." has been copied to the paths "page.10" and "page.20". However we might expect seeing the "temp." TLO in the tree, but we don‘t. The reason is that the TLOs named "temp." and "styles." are unset again after parsing the TypoScript since they are reserved as temporary object spaces available only during parsing - not after parsing.

If we wanted our objects to stay in the tree we could do that by using another TLO:

# Make temporary version of the first cObject:
MY_TLO.world = TEXT
MY_TLO.world.value = HELLO WORLD!
# Make temporary version of the second cObject:
MY_TLO.universe = TEXT
MY_TLO.universe.value = HELLO UNIVERSE!
# Default PAGE object:
page = PAGE
page.typeNum = 0
page.10 < MY_TLO.world
page.20 < MY_TLO.universe

... and the TLO "MY_TLO" is still there:

References - not copies

This also means that we can create a reference to the objects at MY_TLO.* since references to cObjects requires them to exist in the structure during after parsing is done (opposite to the "temp" and "styles" TLOs). Thus the script can be rewritten to this:

# Make temporary version of the first cObject:
MY_TLO.world = TEXT
MY_TLO.world.value = HELLO WORLD!
# Make temporary version of the second cObject:
MY_TLO.universe = TEXT
MY_TLO.universe.value = HELLO UNIVERSE!
# Default PAGE object:
page = PAGE
page.typeNum = 0
page.10 =< MY_TLO.world
page.20 =< MY_TLO.universe

It seems like a little change but the impact is huge since objects are NOT copied, merely referered to:

There are some practical consequences and drawbacks to this method. However the upside to references is that a cObject defined at one path in the object tree can be used multiple times by references from within the structure without spending memory on duplicates - which also becomes hard to manage if you want to override properties of all duplicates in the tree. An example of this problem is found in the end of Part 2 in this tutorial.

Notice: References like this are not a part of the TypoScript syntax as such. It‘s a feature provided internally by the cObjects and thus references can be used only when refering to cObjects, not any other kind of objects or properties (unless noted).

Clearing the cache

Finally you must be aware that when you make changes to a template record through the Template module the "Cache-all" is cleared. This must be done because when TYPO3 parses a TypoScript template the resulting structure is saved in the cache so it can be quickly fetched again for the next page delivery. However this means that changes made to template records directly through the List module for instance will not clear the cache - and then you must do it manually with the link under the menu in the left frame.

Generally, before you announce any strange behavior as a bug, please make sure that it wasn‘t caching of either templates or extension files that bugged you!


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多