TL;DR

  • You should use composer
  • It is very simple
  • You should register your extensions at packagist.org
  • You should prefer the registered vendor name over typo3-ter
  • You can require any extensions that is available in TER with composer
  • You have to add autoload information for extensions that are not required by composer to your root composer.json
  • You should use the dedicated document root folder (web)

Install TYPO3 with composer

Composer is a PHP package manager or (as it calls itself) dependency resolver. You basically have a root config file for your project that contains all the dependencies. For composer this is the file composer.json. So to start a TYPO3 project based on composer you can either create this root composer.json yourself or use the composer command create-project.

Composer fetches its packages per default from packagist.org where TYPO3 has registered a base distribution package. And this is the one you use with the create-project command:

composer create-project typo3/cms-base-distribution target-folder

This will download the TYPO3 core as well as all its dependencies. This is because the TYPO3 core itself has a composer.json (see on github ) and composer resolves dependencies recursively.

Top

The composer.json

Lets have a look a the composer.json the create-project command put you in your target-folder. We gonna leave out the "autoload-dev" section for now and focus on the essential things.

Require section - The Extensions

The section "require". This is a list of all required packages for the project. Each package is specified by its composer known name (vendor/project) and a version constraint that follows a certain syntax. This is for now only the TYPO3 core:

"require": {
    "typo3/cms": "~7.6.0"
}

To add more packages to our "require" section we can simply edit our composer.json or we could use the composer command require. Let's add the news extension from TER. Whenever you want to add a TER extension to your dependencies you can simply use the vendor name typo3-ter. The extension key is then added with dashes instead of underscores. So if you want to install static_info_tables the composer name for that package would be "typo3-ter/static-info-tables". But we want to add the news extension. It has no underscores in its extension key, so easy peasy:

composer require typo3-ter/news

We could specify a version here. If we don't composer will look for the most recent tag that is compatible with the other packages required by our composer.json.This will result in an updated composer.json:

"require": {
    "typo3/cms": "~7.6.0",
    "typo3-ter/news": "^4.0"
}

As I mentioned above composer looks per default only for packages that are registered at packagist.org.

That being said, it is highly recommended for extension authors to register their extensions on packagist as well. When doing so, the most important thing is, that the typo3-ter vendor name must not be used. Extension authors must use their own vendor name on packagist! Read more about this on my article Good Practices in TYPO3 Extensions. The extension "news" is rgistered with its own vendor name at packagist as georgringer/news and can therefore also be required with

composer require georgringer/news

The goal is that some day every TYPO3 extension is registeres at packagist, so that the vendor name typo3-ter is not needed anymore. Until then the typo3-ter vendor name allows us to require extensions that are not registered on packagist but that are available in TER.

We learned that composer won't find any extensions with the vendor name typo3-ter at packagist. So to make the typo3-ter vendor name work nevertheless we need one more thing:

Top

Repositories section - The Magic

The "repositories" section. This is where you can tell composer where else to look for packages (by default composer only checks for packages registered at packagist.org). You can go as far as registering single git repositories and if the PHP package located there has a valid composer.json, composer will find and download it. For the TER TYPO3 adapted and improved an approach originally started by Lightwerk that fetches all TER extensions as composer packages at composer.typo3.org. And that is why you have to add the following to the composer.json of your TYPO3 project if you want to use the vendor name typo3-ter.

"repositories": [
  { "type": "composer", "url": "https://composer.typo3.org/" }
]

This tells composer to also check composer.typo3.org when looking for packages. All TER extensions are listed here automatically with the typo3-ter vendor namespace. So the inclusion of the TYPO3 composer repository allows us to require TER extensions as composer packages, e.g. composer require typo3-ter/news.

To sum this up: TYPO3 extensions can be required with their registered vendor name on packagist or with the typo3-ter vendor name. For the latter to work composer.typo3.org has to be added as a repository in the composer.json. The former should always be preferred, so if an extension is listed on packagist, we require it from there and do not use the typo3-ter vendor name although both would work.

But at least one question remains:

Why aren't TYPO3 extension packages downloaded to the vendor folder like every other composer package?

There is a component that makes sure that extensions will be downloaded to their dedicated folder in typo3conf/ext/: The TYPO3 CMS composer installers (view on github ). This is a dependency of the core, so you don't need to require it yourself. TYPO3 extensions are identified by the composer installers through their unique type, which is "typo3-cms-extension". This is automatically added to all TER extensions on composer.typo3.org. But if you provide a TYPO3 extension that is not uploaded to TER but should be installable via composer you have to add "type": "typo3-cms-extension" to the composer.json of your extension. Then it will be recognized by the TYPO3 composer installers and downloaded to typo3conf/ext/.

But talking of where things are downloaded to, lets have a look at the next big thing for TYPO3 that comes with composer:

Top

Extra section - The web folder

"extra": {
  "typo3/cms": {
    "cms-package-dir": "{$vendor-dir}/typo3/cms",
    "web-dir": "web"
  }
}

In the "extra" section we can specify where the core should go to ("cms-package-dir") and whether or not we want to use a web folder ("web-dir"). If we leave it as it comes with the base-distribution the core will be installed in vendor/typo3/cms. vendor/ is where composer puts all the packages (except for TER extensions, those are handled by the TYPO3 composer installers and put to typo3conf/ext/ as mentionend above) so the TYPO3 core is "just another composer package".

But the real deal is the web folder which is a dedicated document root for your webserver that is no longer identical to your git root. That means you dont have to worry anymore about your .git/ folder or your buildfiles (if you are yousing grunt or gulp) or the database dump you accidently pushed to master or any other thing you have in your project root directory being accessible through the web.

And this is how your TYPO3 base folder (git root) could look like:

$ ls -la
drwxr-xr-x  .git
-rw-r--r--  .gitignore
-rw-r--r--  composer.json
-rw-r--r--  composer.lock
drwxr-xr-x  vendor
drwxr-xr-x  web

And the web/ folder:

ls -la web
drwxrwsr-x  fileadmin
lrwxr-xr-x  index.php -> ../vendor/typo3/cms/index.php
lrwxr-xr-x  typo3 -> ../vendor/typo3/cms/typo3
drwxr-xr-x  typo3conf
drwxrwsr-x  typo3temp
drwxrwsr-x  uploads

But there is more.

Top

Autoload section - The Speed

With 7LTS TYPO3 dropped the old, dusty and expensive class loading mechanisms in favor of ... right: composer! Helmut said everything about this topic already (see here and here). So I just come straight to the point but I absolutely recommend everybody to read the posts from Helmut!

As a teaser, I quote his TL;DR from the first post:

tl;dr: This is a long post decribing why composer class loading is awesome and how you benefit from it in TYPO3 extension development - Helmut Hummel

That being said, if you require an extension via composer you are done in terms of class loading. The classes should be there - ready to use.

If you manually add an extension to your system by putting it in typo3conf/ext you will encounter the problem that its classes are not loaded. This is because composer does not know about the extension and though cannot load any classes (btw this is also the reason why the "download from TER" functionality is not available in the extension manager in composer mode). This is why you specifically have to tell composer how to load the classes. You can do so in the "autoload" section of your composer.json. The best way is to use the PSR-4 standard that maps the namespace of the class to the directory structure (as we already are used to in extbase extensions). But this is only possible if the extension makes use of namespaces and the namespaces match the directory structure of the extension. However, I find this true for most of the modern TER extensions.

This is how it would look like for an extension called my_extension that uses the vendor namespace DanielGoerz:

"autoload": {
  "psr-4": {
    "DanielGoerz\\MyExtension\\": "web/typo3conf/ext/my_extension/Classes/"
  }
}

This approach will give you the best performance (again: this is only needed for extensions that are not already loaded by composer). If you need to load classes of a legacy extension that does not use namespaces yet or that suffers from a messed up folder structure you can always go with a "classmap". This will make composer look recursively in any specified directory and collect every class it finds for autoloading. An example:

"autoload": {
  "classmap": [
    "web/typo3conf/ext/my_legacy_ext/"
  ]
}

This will however not be executed on every request as the information is stored in the vendor/composer folder. So if you add new classes you can tell composer to regather the class information with the dumpautoload command.

composer dumpautoload

Extension authors should add the autoload information in their own composer.json.

Top

All in one - A TYPO3 projects composer.json

This is a (minimal) version of the complete composer.json to set up a TYPO3 project with composer. The project uses TYPO3 7 LTS as well as the extension news from the TER and a custom etensions named mx_extension.

{
  "repositories": [
    { "type": "composer", "url": "https://composer.typo3.org/" }
  ],
  "name": "DanielGoerz/composer-example",
  "description" : "A TYPO3 7 LTS example project with news.",
  "license": "GPL-2.0+",
  "require": {
    "typo3/cms": "^7.6",
    "typo3-ter/news": "^4.0"
  },
  "extra": {
    "typo3/cms": {
      "cms-package-dir": "{$vendor-dir}/typo3/cms",
      "web-dir": "web"
    }
  },
  "autoload": {
    "psr-4": {
      "DanielGoerz\\MyExtension\\": "web/typo3conf/ext/my_extension/Classes/"
    }
  }
}

Preferable the original vendor name of the extension is used (if available on packagist). If no extension is required with the typo3-ter vendor name the additional composer repository is not needed at all:

{
  "name": "DanielGoerz/composer-example",
  "description" : "A TYPO3 7 LTS example project with news.",
  "license": "GPL-2.0+",
  "require": {
    "typo3/cms": "^7.6",
    "georgringer/news": "^4.0"
  },
  "extra": {
    "typo3/cms": {
      "cms-package-dir": "{$vendor-dir}/typo3/cms",
      "web-dir": "web"
    }
  },
  "autoload": {
    "psr-4": {
      "DanielGoerz\\MyExtension\\": "web/typo3conf/ext/my_extension/Classes/"
    }
  }
}

One last thing: When you run a composer based installation of TYPO3, your beloved CMS will run in composer mode. It will no longer be possible to download extensions from TER through the extension manager in the backend. Because downloading is handled solely by composer. However, you still have to install and uninstall extensions via the extension manager. Despite the most popular composer command being composer installit will not install the extension in TYPO3 but "only" download it to the correct place. An installation with composer will maybe be possible in future versions of TYPO3 but it is not in 7LTS!

Top

Further Information