Ja:Extension Developers Guide

From TYPO3Wiki

Jump to: navigation, search

<< Back to Developer manuals page

[edit]

document in progress. Feel free to add content.

Preface

The content of this document is related to TYPO3, a GNU/GPL CMS/Framework available from http://www.typo3.com

The document TYPO3 Extension Development is a guide mainly for extension developers, explaining the basic steps to create an extension and going further into advanced topics useful for TYPO3 extension development.

Contents

Introduction

What is an extension?

glossary-definition: An extension is basically a piece of software that extends or alters the functionality of TYPO3. The concept of extensions makes TYPO3 one of the most flexible CMS-Frameworks around enabling you to achieve virtually every function you need TYPO3 to take care of.

A wide variety of extensions can be downloaded from the TYPO3 extension repository, but being interested in an "Extension Developers Guide" I assume that you already have been there and downloaded some of the extensions to play around with.

Make sure you installed the following extensions for they are great helpers when developing your own code:

Extension Development Evaluator

Extension Development Evaluator (extdeveval) (contact: kasper)

The extension ExtDevEval gives you the APIs for extensions and a link list to documentation.

Image:ExtDevEvalLinks.png

Show TYPO3 Info

Show Typo3 Info (sg_showdoku) (contact: geithman)


Kickstarter

Extension Kickstarter (kickstarter) (contact: flyguide)

Tutorials and Videos

Also the following Tutorials and Videos are a great help for first steps:
- Backend Programming
- Creating a basic extension

I encourage you to follow the tutorial "Backend Programming" step by step, even if you will later create all the basic files with the Kickstarter. The reason is, that you get a feeling for what the different files and entries are for, especially when making mistakes that lead to misbehaviour of TYPO3. It's good to start from scratch once, although you'll be happy that most of the things can be achieved by using the kickstarter later on.

This should keep you busy for a while.

Extension Types

Explains the difference between user extensions and core extensions, and when you actually need either of those. Additional types are: Backend modules, frontend plugins, code libraries, services etc.

Required Knowledge

Information on the knowledge about concepts that matter when you write extensions. E.g. PHP, databases and database normalization, the concept of Typoscript, OOP etc. (possibly accompanied with links to online documents, articles and literature suggestions)

The TYPO3 architecture

Explains the overall architecture of TYPO3, possibly accompanied by diagrams. The "why" of things is also very important here. Pre/post-processing issues, the role (and boundaries!) of Typoscript, the philosophy behind the architecture, the TCA etc. (Kasper will be the best judge of the structure of this section)

??????????

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

?????????????? typo3conf/ext/ ????????????????

????
?????????????????? TYPO3 ??????????? ???????????????????????????????????????????????????????????

?????
1 ?? typo3_src ?????????? TYPO3 ?????????????????????????????????????????????????????????????????????

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

??????????????? (??? TYPO3 ??????????) typo3/ext ????????????????

????
1 ?? typo3_src ?????????? TYPO3 ?????????????????????? (??????????????????????) ????????????????????????????????????????????????????

?????
TYPO3 ??????????????????????? typo3 ?????????????????????????????????????????????????????????????????

???????

???????????????????????? (??????????????????????????????????????????) ??????????????????????????????????????????????????????????????????

PHP ?????

????????????????????????????(like the register_globals thing, explaining the distribution's .htaccess file that sets PHP flags, PHP version compatibility, etc.)

Programming Extensions

(??: ?????????????????????????kickstarter ??????????????????????????????????????????)

One base for all

(tslib_pibase ??????????????????????????????????????????? "???" ???????????)

TYPO3 ????????????????????????????Kasper Ska*rh?j ??????????????????????? PHP ????????????? PHP ???????“pi_base”????“plugin base”?????????

kickstarter ???????????????????????????????????????????????????? hello world ???????????????????? uses pi_base ????????????????????????????? PHP ????????????

??????? pibase ???? CMS ?????????????? typo3/sysext/cms/tslib/class.tslib_pibase.php ???????????????????????????????????????????????????????????????????

class.tslib_pibase.php ????????????????????????????????????? 'pibase' ??????????????? API ?????????????

  • pivars ??????????? ????????
  •  ??????????????? ????????
  •  ?????????????????? ????????????????
  • ?????????? CSS ?????,
  • ?????????????????,
  • FlexForms ?????,
  • ???????????: pi_RTEcssText()

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

???????????? pibase ??????????????????????????????????????????????????????????????????????????????

// include the pibase
require_once(PATH_tslib.'class.tslib_pibase.php');

// extend tslib_pibase
class tx_photoblog_pi1 extends tslib_pibase {
  // Your functions go here
}

???????????????????????????????????????????????? 'pibase' ????????????????????pi_setPiVarDefaults ????????????????????????????????

kickstarter ?????????? tslib_pibase ????????????

Things you must use

????????????? TYPO3???? RealURL ???????????????????????????????????????? TYPO3 API ??????????


t3lib_div

makeInstance

?????????????????????makeInstanceClassName ??????????? new ????????????? makeInstance ????????????

$treeView = &t3lib_div::makeInstance('tx_treelib_treeView');
getUserObj

?????????????????????makeInstance ???? getUserObj ??????? Description:

  • Creates and returns reference to a user defined object.

This function can return an object reference if you like. Just prefix the function call with "&": "$objRef = &t3lib_div::getUserObj('EXT:myext/class.tx_myext_myclass.php:&tx_myext_myclass');". This will work ONLY if you prefix the class name with "&" as well. See description of function arguments.

  • @param string Class reference, '[file-reference":"]["&"]class-name'. You can prefix the class name with "[file-reference]:" and t3lib_div::getFileAbsFileName() will then be used to resolve the filename and subsequently include it by "require_once()" which means you don't have to worry about including the class file either! Example: "EXT:realurl/class.tx_realurl.php:&tx_realurl". Finally; for the class name you can prefix it with "&" and you will reuse the previous instance of the object identified by the full reference string (meaning; if you ask for the same $classRef later in another place in the code you will get a reference to the first created one!).
  • @param string Required prefix of class name. By default "tx_" is allowed.
  • @param boolean If set, no debug() error message is shown if class/function is not present.
  • @return object The instance of the class asked for. Instance is created with t3lib_div::makeInstance
  • @see callUserFunction()
function &getUserObj($classRef,$checkPrefix='user_',$silent=0)

Things you should use

Typolinks in FE-plugins for RealURL-support

  • $this->pi_getPageLink for internal links (parameter: id)
  • $this->pi_linkToPage for internal links (parameters: title, id)

See

Things you can use

???????????? ?????????tslib_pibase (tslib/class.tslib_pibase.php) ??? tslib_cObj (class.tslib_content.php) ??????? API ????????

tslib_cObj

tslib_cObj ???? API ??????????

tslib_cObj ????????????????????????????????????????????????????????:

tslib_cObj ???? API ?????????????????????

???PHP ??????????????????????????:

 doSomething($parameter);

???????tslib_cObj ???? API ?????????????????????????????????

?????IMAGE ?????????????? $conf ??????????:

 $conf = array(
   'file' => 'fileadmin/my_image.jpg',
   'alttext' => 'This image is an example!',
 );

??????????????????????????? TSRef ??????????????

???????

tslib_pibase

Description of the class tslib_pibase

 ???/???????

Typo3 ??????????????????????????????????????????????????????????????:

  •  ??? API ??????????? full-API ????????????????doxygen ?????????????????? API ???????????????????
  • GLOBALS ????????????????????????????????????...
  •  ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????:
t3lib_extMgm::extRelPath($_EXTKEY)
                         ^------ ?????????? ;)
              ^------ ???????????????
      ^------ ???? class.t3lib_extmgm.php
^----- ???? 't3lib' (t3lib = TYPO3 Library)

class.t3lib_extmgm.php ??????? extRelPath ??????????????

Types of user extensions

Backend

All kind of BE-related extensions for extending or replacing backend-functions. The extensions in this category do not create a new link in the main menu on the left side, they implement or extend functions of other backend areas. For example, an extension extending the clickmenu with more items or an extension implementing a new RTE should be put in this section.

Backend Modules

A backend module is an extension that has a link in the main menu below one of the main menu items "web", "file", "doc", "tools" or "help". Backend modules are usually closed sections of their own, this means their functions are not used anywhere else. Examples: visitor tracking system, AWStats, Backup

Frontend

What's the difference between Frontend and Frontend Plugins? I have no Idea.

Frontend Plugins

A Frontend Plugin is the part of an extension that outputs content to the frontend web site.

Sometimes they are just called 'pi'...

One extension can contain more than one Frontend Plugin.

It is suggested to put each Frontend Plugin into a separat folder called pi1, pi2, etc...

Clickmenu items

A clickmenu item is added to the BE clickmenu.

Miscellaneous

Mostly some libaries.

Services

Templates

Examples

Skins

Skins for the TYPO3 backend.

Required extension files

Most of the content of this list is taken from T3Doc/TYPO3 Core APIs: "files and locations".

All these files are either marked (optional) or (required).

ext_emconf.php (required)

The term "emconf" stands for "Extension Manager/Repository config file". This file holds general information about the extension in an array called $EM_CONF[$_EXTKEY]. It is auto-written from Extension Manager when extensions are imported from the repository.

If this file is missing, the Extension Manager won't find the extension.

ext_localconf.php (optional)

Addition to localconf.php which is included if found. Should contain additional configuration of $TYPO3_CONF_VARS and may include additional PHP class files. All 'ext_localconf.php' files of included extensions are included right after the typo3conf/localconf.php file has been included and database constants defined. Therefore you cannot setup database name, username, password though, because database constants are defined already at this point.

ext_tables.sql (optional)

This file contains the sql-statement that will update or create tables in your typo3-database.

This file should contain a table-structure dump of the tables used by the extension. It is used for evaluation of the database structure and is therefore important to check and update the database when an extension is enabled. If you add additional fields (or depend on certain fields) to existing tables you can also put them here. In that case insert a CREATE TABLE structure for that table, but remove all lines except the ones defining the fields you need. The ext_tables.sql file may not necessarily be dumpable directly to MySQL (because of the semi-complete table definitions allowed defining only required fields, see above). But the EM or Install Tool can handle this. The only very important thing is that the syntax of the content is exactly like MySQL made it so that the parsing and analysis of the file is done correctly by the EM.

ext_tables.php (optional)

This file works hand in hand with the above by telling TYPO3 how to display and handle the data from the sql file.

Addition to tables.php which is included if found. Should contain configuration of tables, modules, backend styles etc. Everything which can be done in an extTables file is allowed here. All 'ext_tables.php' files of loaded extensions are included right after the 'tables.php' file in the order they are defined in the global array TYPO3_LOADED_EXT but right before a general extTables file (defined with the var $typo_db_extTableDef_script in the typo3conf/localconf.php file, later set as the constant TYPO3_extTableDef_script). Thus a general extTables file in typo3conf/ may overrule any settings made by loaded extensions. You should not use this file for setting up $TYPO3_CONF_VARS. See ext_localconf.php .

ext_tables_static+adt.sql (optional)

Static SQL tables and their data. If the extension requires static data you can dump it into a sql-file by this name. Example for dumping mysql data from bash (being in the extension directory):

mysqldump --password=[password] [database name] [tablename] --add-drop-table > ./ext_tables_static.sql

--add-drop-table will make sure to include a DROP TABLE statement so any data is inserted in a fresh table. You can also drop the table content using the EM in the backend.

The table structure of static tables needs to be in the ext_tables.sql file as well - otherwise an installed static table will be reported as being in excess in the EM!

locallang_db.php (optional)

The language file with translations for every row - used for displaying them in the backend.

locallang.php (optional)

The language file with translations available in the extension-scripts.

ext_typoscript_setup.txt (optional)

Contains some TypoScript for the extension.

ext_icon.gif (optional?)

The extension icon displayed in the EM.


--murphy 18:36, 14 May 2004 (UTC)

Extending an extension

Actions that are required to extend an extension, and the implications this has for future compatibility. A case study would be useful here. Core hooks: How you would extend the core by requesting a hook from the core devs.


If you want to extend an existing extension TCA array:

1) Setup a simple extension with kickstarter

2) In the ext_tables.php file add these lines to the top:

  <?php
  if (!defined ('TYPO3_MODE')) 	die ('Access denied.');
  //Load the TCA array you want to modify
  t3lib_div::loadTCA("tt_news");
  $TCA['tt_news']['columns']['bodytext']['config']['rows'] = 15;

Remark: Be careful with this. To let this work your new extension containing this must be after "tt_news" in $TYPO3_CONF_VARS['EXT']['extList'] (in typo3conf/localconf.php). On updates (of single extensions) or uninstall/install (of extensions) this order can mess up (My experience with Typo3 3.8.1).

3) In BE > Tools > Configuration > Menu $TCA (tables.php)

4) Here you can select the changes and copy this config to your ext_table.php file

Quality standards

Explains the reviewing guidelines which are the official standard for a quality extension. How to get a Cohiba?

Common practices

Handling user data

Examples along with descriptions on how to handle incoming GET/POST data

Dealing with Typoscript

Explains when to use Typoscript for your extensions and how to read it inside the extensions

WARNING: You will only be able to understand this chapter, if you have read the documentation TypoScript Syntax and In-depth Study.

Handling file uploads

Examples of dealing with file uploads in extensions

Using sessions

Sessions are used to carry userdata along the visit without having to post them over and over again. The data is available as long as the session is valid, usually until all (!) browserwindows are closed.

Since TYPO3 has already a session running you can use the existing session to read/write data into it. However you must first understand that Sessions in Frontend and Backend are handeled differently.

The routine on the other hand is always the same.

  • Recover your Data from the session
  • Add values (possibly into an array that holds all the sessiondata)
  • Save your Data to the session

When writing all your data into a single array you can be sure that no data gets lost.


Backend

In Backendmodules Sessions are called by using:

$my_vars = $GLOBALS["BE_USER"]->getSessionData("tx_myextension");

you then will add your own values:

$my_vars['somevalue'] = "Hello World";

Don't forget to save the data to the session in the end:

$GLOBALS["BE_USER"]->setAndSaveSessionData ('tx_myextension', $my_vars);

Of cause $my_vars can be in a classwide context with $this->my_vars


Frontend

In Frontendmodules Sessions are called slightly differently by using:

$my_vars = $GLOBALS["TSFE"]->fe_user->getKey('ses','tx_myextension');

you then will add your own values the same way:

$my_vars['somevalue'] = "Hello World";

Again, Don't forget to save the data to the session in the end:

$GLOBALS["TSFE"]->fe_user->setKey('ses','tx_myextension',$my_vars);

Of course $my_vars can be in a classwide context with $this->my_vars

This is all you need to know to manage Sessions with extensions.

TIP: Good Editors (see tools section) offer templates or stationaries for code. If you save these statements as templates, you can access them without the hassle of checking this document. Just make shure you can tell the frontend from the backend statements.

Using databases

Introduction

The DBAL consists of a t3lib_DB class in the GLOBALS array $GLOBALS['TYPO3_DB'] (used as 'global $TYPO3_DB' in the declaration section of each function).
It offers methods for building queries for inserting, updating, deleting and of course selecting records from tables in the db: INSERTquery, DELETEquery, UPDATEquery and SELECTquery. Each of these methods has as similar method that executes the statement: exec_INSERTquery, exec_DELETEquery, exec_UPDATEquery and exec_SELECTquery. These are the functions that will be used for retrieving the resultset. This resultset can be browsed by methods in the class. These methods will be familiar to people knowing the php mysql functions. For instance the php function mysql_num_rows is called sql_num_rows, mysql_fetch_assoc is sql_fetch_assoc etc.

many-to-many relations

There are also methods for retrieving many-to-many relations from tables that adhere to the standard TYPO3 way of mm relations. So take care to name your table fields in the following way.

  • Use $mm_table together with $local_table or $foreign_table to select over two tables. Or use all three tables to select the full MM-relation.
  • The JOIN is done with [$local_table].uid <--> [$mm_table].uid_local / [$mm_table].uid_foreign <--> [$foreign_table].uid
  • The functions are for selecting MM-relations between tables adhering to the MM-format used by TCE (TYPO3 Core Engine). See the section on $TCA in Inside TYPO3 for more details.

Function Overview

Query execution
  • exec_INSERTquery($table,$fields_values)
  • exec_UPDATEquery($table,$where,$fields_values)
  • exec_DELETEquery($table,$where)
  • exec_SELECTquery($select_fields,$from_table,$where_clause,$groupBy=,$orderBy=,$limit=)
  • exec_SELECT_mm_query($select,$local_table,$mm_table,$foreign_table,$whereClause=,$groupBy=,$orderBy=,$limit=)
Creates and executes a SELECT query, selecting fields ($select) from two/three tables joined
  • exec_SELECT_queryArray($queryParts)
  • exec_SELECTgetRows($select_fields,$from_table,$where_clause,$groupBy=,$orderBy=,$limit=,$uidIndexField=)
SECTION: Query building
  • function INSERTquery($table,$fields_values)
  • function UPDATEquery($table,$where,$fields_values)
  • function DELETEquery($table,$where)
  • function SELECTquery($select_fields,$from_table,$where_clause,$groupBy=,$orderBy=,$limit=)
  • function listQuery($field, $value, $table)
  • function searchQuery($searchWords,$fields,$table)

I think there should be a note on the use of the query-building functions. If you have a query from a query-build function, is there a way to execute it? A function sql_query($query) exists, but is mentioned as deprecated in the file class.t3lib_db.php.

SECTION: Various helper functions
  • function quoteStr($str, $table)
  • function cleanIntArray($arr)
  • function cleanIntList($list)
  • function stripOrderBy($str)
  • function stripGroupBy($str)
  • function splitGroupOrderLimit($str)

SELECT

As an example, lets try to select the fields uid,name and email from the tt_address table. We only want to select records with a certain pid contained in the variable $id.

$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,name,email','tt_address','pid = '.$id);

This will return a recordset with all the tt_address records in the folder with uid $id. Actually the DBAL will not check the where clause (pid=$id), for SQL-injection, and if this variable is fetched from the browser, it will be a good idea to put it through intval since it is supposed to be an integer.

$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,name,email','tt_address','pid = '.intval($id));

You should use the enableFields method to exclude entries which have been deleted, are hidden or have been scheduled using {start,end}time. The function will return a string for your WHERE clause:

$where = 'pid = '.intval($id);
$where .= $this->cObj->enableFields('tt_address');
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,name,email','tt_address',$where);

If you don't already have a WHERE clause you will get a wrong mysql statement (SELECT * FROM tt_address WHERE AND ...), so you have to strip the leading AND in this case:

$where = preg_replace('/^ AND/', '', $where);


Generally speaking, TYPO3 has a method for escaping query parts:

string $GLOBALS['TYPO3_DB']->quoteStr(string);

Browsing the resultset can now be done like this:

while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
 do_something_with_the_data($row);
}
$GLOBALS['TYPO3_DB']->sql_free_result($res);

It is always a good idea to free the resultset when finished with it. This is done by the methods sql_free_result.

The exec_SELECTquery takes these parameters (taken from the docs in the source file):

/**
 * Creates and executes a SELECT SQL-statement
 * Using this function specifically allow us to handle the LIMIT feature independently of DB.
 * Usage count/core: 340
 *
 * @param	string	List of fields to select from the table. This is what comes right
 *                     after "SELECT ...". Required value.
 * @param	string	Table(s) from which to select. This is what comes right after "FROM ...".
 *                     Required value.
 * @param	string	Optional additional WHERE clauses put in the end of the query. NOTICE: You 
 *                     must escape values in this argument with $this->quoteStr() yourself! DO NOT
 *                     PUT IN GROUP BY, ORDER BY or LIMIT!
 * @param	string	Optional GROUP BY field(s), if none, supply blank string.
 * @param	string	Optional ORDER BY field(s), if none, supply blank string.
 * @param	string	Optional LIMIT value ([begin,]max), if none, supply blank string.
 * @return	pointer		MySQL result pointer / DBAL object
 */
function exec_SELECTquery($select_fields,$from_table,$where_clause,$groupBy=,$orderBy=,$limit=)

DELETE

Deleting records is done by the exec_DELETEquery, it takes two arguments, the table to delete from, and the WHERE clause to select which records to delete.

$GLOBALS['TYPO3_DB']->exec_DELETEquery('tt_address','uid='.intval($uid));

Again, make sure the input parameters are SQL-injection safe by running them through intval() or similar.

UPDATE

When updating records use the exec_UPDATEquery command. It takes the table name, where clause and an associative array of fieldnames => values pairs. The values are run through t3lib_db->quotestr which will make sure that they are injection safe (see the section on cleaning functions).

$GLOBALS['TYPO3_DB']->exec_UPDATEquery('tt_address','uid='.intval($uid),array('email'=>$email,
                                                                              'name'=>$name));

Remember to make sure that the where clause,fieldnames at table name are run through addslashes or similar if they are fetched from variables.

INSERT

The insert command follows the same syntax as the update command, except there is no where clause.

$GLOBALS['TYPO3_DB']->exec_INSERTquery('tt_address',array('name'=>$name,
                                                          'email'=>$email));

When inserting a record, one can call the sql_insert_id() method to retrieve the id of the latest inserted record.

Debugging

One drawback of using the DBAL is that all database errors, like malformed queries, will look like they originated from the t3lib_db class. Debugging is done by setting

$GLOBALS['TYPO3_DB']->debugOutput = TRUE

This will save all built queries (not necessarily executed) in the debug_lastBuiltQuery parameters of the class. When debugOutput is set, all errors are output to screen by echo (at least in the MySQL implementation of DBAL).

Cleaning functions

The DBAL will check some of the variables, but when writing extension, you are responsible for making sure that there is no SQL injection exploits. Several helper functions exists for this. Use intval when you know that the field is supposed to be an integer. DBAL offers two other functions for cleaning lists and arrays of integers:

$GLOBALS['TYPO3_DB']->cleanIntList($list);
$GLOBALS['TYPO3_DB']->cleanIntArray($arr);

They will make sure that you list or array only contains integers.

For escaping strings use the method quoteStr($str,$table) of the DBAL. This will escape your string according to which table you want to insert into. In the MySQL implementation it is equivalent to calling addslashes, but use quotestr instead.

Handling User Authentication

Examples on what exactly should happen for e.g. logging a user into TYPO3

constants

You should use the BACK_PATH constant in your modules to set the relative path from your script to the typo3 folder of your installation.

$this->backPath = $GLOBALS['BACK_PATH'];	// Setting backpath.

Set your own PATH constants in the ext_localconf.php file of your extension.

if (!defined ('PATH_txcommerce')) {
    define('PATH_txcommerce', t3lib_extMgm::extPath('commerce'));
}
if (!defined ('PATH_txcommerce_rel')) {
    define('PATH_txcommerce_rel', t3lib_extMgm::extRelPath('commerce'));
}

Structural practices

Coding conventions

TYPO3 Coding Standards

Make sure to read the complete guide of the TYPO3 coding standards.

When developing TYPO3 core, the style guide has to be followed. When you write your own extensions, you can follow it, although it is highly recommended to follow the guidelines in extensions, too.

General Style

  • XHTML (transitional) / CSS compliance
Paragraphs will probably make up a majority of your (X)HTML code. Some authors were taught the closing paragraph tag (</p>) is unnecessary, however when standards are of importance, which they are, text should be enclosed in p tags like this:
<p>Creating paragraph numero uno is simple.</p>
<p>Starting a new paragraph after numero uno is just as easy.</p>
Note: Those not well-versed in the separation of style from content may be inclined to use several empty paragraphs to create hard returns in a document. This is not recommended, as visual appearance can be easily controlled with CSS, as you will soon see.
  • use quotes for attribute values
  • prevent XSS and SQL injection by usage of htmlspecialchars(), addslashes(), intval()
  • comment all functions and classes fully with parameters and return values
  • Classes have to have @package/@subpackage tags, contain a function index and have the CVS keyword "$Id$" in the header comment of the document.
  • use English words or abbrevations for class/function names, variables, comments, database table and field names, ...

Filenames

  • All filenames have to be shorter than 31 characters
  • filenames should be in lowercase as long as possible

Handling content

Examples of how to use the markers, TemplaVoila, Smarty etc.

Writing larger extensions

Suggestions on how to structure your code when writing larger extensions (explanation of Front Controller style structures)

Porting third party applications to TYPO3

Things to keep in mind when porting third party applications to TYPO3 such as database migration, user integration, etc.

Accessibility

Hints on accessible forms and more...

Personal tools