Setup a working Neos CMS environment

This article is for Neos 2.0 and thing migt have changed in the meantime. At least the software packages are required in newer versions.

Neos is well known for its well designed interface for editors who quickly fall in love with the system. On the other hand, it’s also infamous for being hard to set up by starters due to its high demands towards the hosting environment. Someone also compared it to walking on a slack line: It’s easy to stumble and to get frustrated.

Neos error page

This article focuses on creating a hosting environment suited for Neos so you will be able to finish the Neos setup and get a running instance afterwards. I’m using Ubuntu 14.04 as reference but it also applies to other Linux distributions like Fedora, only the path names might differ a bit (/etc/apache2/ vs. /etc/httpd/).

Required software

At first, you need to make sure that the required software is installed. Apache, MySQL and PHP might be obvious but that’s not enough. Especially the additional Apache and PHP modules are important to get it running at all. You will have a good start with these packages:

  • Apache 2.2+
  • MySQL 5.1+
  • PHP 5.3.2+
    • mbstring
    • tokenizer
    • pdo_mysql

Even if the minimum requirement for PHP is version 5.3.2, it’s better to use newer versions for performance reasons. Also, the requirements for Neos will be PHP 5.5+ for Neos 2.0.

You can install the required packages via the package manager of your distribution (apt-get for Ubuntu/Debian, rpm for Fedora/SuSE):

  1. sudo apt-get install apache2 mysql-server libapache2-mod-php5 php5 php5-mysql

To check if all required PHP extensions are available, the easiest way is to place a short PHP file named info.php in your Apache document root directory (usually /var/www/) containing this content:

  1. <?php phpinfo();

If you open http://localhost/info.php in your browser, the output will contain the environment, the configuration settings and the installed modules available in your installation. Search for the strings “mbstring”, “tokenizer” and “pdo_mysql”. There should be sections with this names in the rendered page.

Apache configuration

Most often, the first problems occur due to an insufficient Apache configuration. Neos uses .htaccess files and needs some modules that are not activated by default all the times. The “mod_rewrite” and “mod_env” modules are the best examples for this. To enable them in your Apache configuration, you need to execute these commands on the command line:

  1. sudo a2enmod rewrite
  2. sudo a2enmod env

If you got the message that one or both modules had been already enabled then this was set up correctly before.

The VHost configuration is another common source of problems and you have to adapt it for sure. The default configuration is located in /etc/apache2/sites-enabled/000-default.conf (in Fedora or other Linux distributions the files might be located somewhere else). In this file, change the DocumentRoot to the Neos ./Web/ directory, e.g.

  1. DocumentRoot /var/www/Neos/Web

Furthermore, you need to add a “Directory” directive below the “DocumentRoot” line to allow the Neos .htaccess file to add rewrite rules and some settings:

  1. <Directory /var/www/Neos/Web/ >
  2. 	AllowOverride All
  3. </Directory>

If there’s already a “Directory” section available, replace it with the lines above.

Keep care that the named directory in the “Directory” directive is exactly the same as in the “DocumentRoot” AND contains a trailing slash (/).

The last task is to restart Apache:

  1. sudo service apache2 restart

Now you should be at able to open at least http://localhost/setup in your browser but beware: http://localhost/index.php/setup still won’t work!

PHP configuration

There are various PHP settings that can cause your Neos installation to fail. First of all you should have a look into the output of the info.php file again and check if one of the required PHP functions is disabled. This is often the case for security reasons in shared hosting environments and this leads to errors afterwards. Especially check the disable_functions line in the core section for:

  • system
  • shell_exec
  • escapeshellcmd
  • escapeshellarg

If non of these function is listed there, then you are on the safe side.

The next problems are lurking in your PHP configuration but that can be fixed either by adding a few lines to your /etc/php5/apache2/php.ini or to the .htaccess file in the Neos ./Web/ directory. When using the php.ini file you should add these lines at the end of the file:

  1. memory_limit = 256M
  2. magic_quotes_gpc = off # only for PHP 5.3 to be sure
  3. date.timezone = Europe/Berlin # or any other valid timezone
  4. xdebug.max_nesting_level = 500 # only if XDebug extension is installed

In case you are allowed to overwrite settings also via the .htaccess file, you can add these lines to the ./Web/.htaccess of your Neos installation:

  1. php_value memory_limit = 256M
  2. php_flag magic_quotes_gpc off # only for PHP 5.3 to be sure
  3. php_value date.timezone Europe/Berlin # or any other valid timezone
  4. php_value xdebug.max_nesting_level 500 # only if XDebug extension is installed

Neos can be very memory consuming so even the standard memory limit of 128MB can be to low. Errors due to an insufficient memory limit are written to the Apache error log file (usually in /var/log/apache2/error.log) so it’s a good idea to keep an eye on the content of that file.

The magic_quotes_gpc directive has been removed in PHP 5.4 and was already deprecated before. To disable it for PHP 5.3 is only a safety measure for installations that have been constantly updated during the last years.

For the timezone value you can use any valid timezone if it fits better for your location. A list of valid timezones is available at the PHP web site.

When you’ve installed the PHP XDebug extension you might run into error messages like Maximum function nesting level of '...' reached. Only in this case you need to increase the XDebug nesting level for functions.

Done!

Finally, you should be able to open the Neos setup page in your browser, that is available at http://localhost/setup. The rest of the installation is usually a non-brainer due to the nice setup routine provided by the Neos installer.

Afterwards you can enjoy Neos. Happy editing! 🙂

First Stable Aimeos Web Shop Bundle For The Symfony PHP Framework

After months of development we’ve felt ready to release the first stable version of our Open Source web shop bundle for the Symfony PHP framework.

The shop bundle enables software developers to integrate e-commerce functionality into their applications immediately. Pre-configured pages and a complete demo data set reduces the time to the first working shop down to a few minutes, increasing productivity. And the best thing: It integrates well with existing bundles like FOSUserBundle for user registration and management!

Our attention has been laid on creating a high-performance shop bundle that scales up to 100 000+ products on a standard Linux/Apache/MySQL/PHP stack. With additional software such as ElasticSearch, several million products per installation are possible without performance loss and in optimized server setups, we’ve seen response times down to 40ms.

As usability is one of the key success factors of online shops today, we’ve continuously tested and improved the user experience. The Aimeos “elegance” theme is the result which we are very proud of. If you are a developers who would like to create new themes, you are also able to completely rework the front-end by adding, removing or reordering all aspects only via configuration settings.

We hope you enjoy the bundle as much as we do! The new version and additional information is available at the Symfony web shop bundle page

Steps to configure your TYPO3 extension automatically

Simplicity is key! I think nobody would oppose to this little sentence but in the TYPO3 ecosystem, many things are not very simple – at least not for new users. Even the most popular extensions need a deep knowledge of how to configure them before they can be used. And good documentation is most of time a rare thing!

So why not build an extension that works out of the box and configures itself as far as possible to give users an instant feeling of success? The constants.txt or setup.txt TypoScript files of the extensions can contain almost all default settings. But things get difficult if the required configuration depends on dynamic things like page IDs. Then, all hope of simplicity is lost and users have to add the necessary settings themselves again.

Is this really true?

The signal/slot mechanism described in the article about executing scripts after installing an extension provides the tools to get things done. Although, the article is very generic and I would like to go into more detail about how we’ve implemented things in the Aimeos web shop distribution.

The distribution imports some pages from the data.t3d file and the TYPO3 importer cares about avoiding conflicts with existing pages by reassigning the page IDs. Problems arose after we’ve added some required TypoScript settings for access restricted pages like the “MyAccount” page. In order to redirect to the login form when a user isn’t logged in, you have to configure its page ID. That seems to be impossible at the first glance when the page ID will differ in each TYPO3 installation.

The solution is to look up the page ID from the database dynamically after the extension is installed and generate a constants.txt file that will then contain the actual page ID. The constants in this file can be used in the TypoScript setup.txt file afterwards.

But first, you need to make sure your code will be executed automatically after the extension is installed. Remember the steps from the article about executing scripts? The first one was to register your extension for listening to the signal for extension installation:

  1. if (TYPO3_MODE === 'BE') {
  2.     $class = 'TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher';
  3.     $dispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($class);
  4.     $dispatcher->connect(
  5.         'TYPO3\\CMS\\Extensionmanager\\Service\\ExtensionManagementService',
  6.         'hasInstalledExtensions',
  7.         '<vendor>\\<extension>\\<classname>',
  8.         '<method>'
  9.     );
  10. }

Please replace <vendor>, <extension>, <classname> and <method> with the strings that fits for your extension. Afterwards, you must implement the method of your class you’ve registered for listening. We use the name of the Aimeos setup class in our example because you can have a look at it’s implementation for reference.

  1. <?php
  2.  
  3. namespace <vendor>\<extension>;
  4.  
  5. use \TYPO3\CMS\Core\Utility\GeneralUtility;
  6. use \TYPO3\CMS\Backend\Utility\BackendUtility;
  7.  
  8. class Setup
  9. {
  10.     public function process( $extname = null )
  11.     {
  12.         if( $extname !== '<extension>' ) {
  13.             return;
  14.         }
  15.  
  16.         $data = '';
  17.         $ds = DIRECTORY_SEPARATOR;
  18.         $filename = dirname( __DIR__ ) . $ds . 'Configuration' . $ds . 'TypoScript' . $ds . 'constants.txt';
  19.  
  20.         $records = BackendUtility::getRecordsByField( 'pages', 'title', 'My account' );
  21.  
  22. 	foreach( $records as $record ) {
  23.             $data .= 'config.typolinkLinkAccessRestrictedPages = ' . intval( $record['uid'] ) . "\n";
  24.         }
  25.  
  26.         GeneralUtility::writeFile( $filename, $data );
  27.     }
  28. }
The example contains placeholders for <vendor> and <extension> and you have to replace them with the names from your extension.

First we have to ensure that the constants.txt file is only created if our own extension is installed. Thus, we check for the extension name to filter out all other extension installations.

The TYPO3 backend utilities contains some nice methods to retrieve records from the database with only little effort. For example, you can use the getRecordsByField() method from the BackendUtility class to fetch all records from a table where a field matches a certain value. Here we want to get all records where the “title” equals “My account” from the “pages” table.

Searching for a page with a title only works as long as the page isn’t renamed! In the best case, your extension has added the page including the page name itself, so this won’t be a problem. It’s not bad if somebody renames the page afterwards because the page ID will stay the same in this case. The only problematic situation could be several pages with the same name.

Make sure you generate valid TypoScript afterwards, including new lines and keep an eye on security by enforcing the types you are expecting! The foreach() loop is a great way to deal with no records and several returned records too because both can an will happen sooner or later. Don’t throw an exception if something unexpected happens because it may lead to not being able to install your extension at all! It’s better to drop those records and add a message to the log file.

You don’t have to add all TypoScript statements to your constants.txt that contains a dynamic value. Instead, you can also define them like “page.myaccount.id = 123” and reference the constants in your setup.txt with “{$page.myaccount.id}”. This is especially handy to keep your constants.txt small and if you need the value several times.

At last, your extension has to write the TypoScript statements to the constants.txt file. The GeneralUtiltiy class from the TYPO3 core contains a little writeFile() helper function to get this done within one line.

Simple, isn’t it?

These few additional lines can make the difference between an easy installable extension and hours of frustrations bugging your users. I think the little effort during the development of your extension is worth the hours saved later on. Your users will thank you for your work by using your extension more often!

A special thanks for the inspiration to this tutorial goes to Stephan Schuler from netlogix.

How to execute scripts after installing TYPO3 extensions

Extensions are a great way to add features to the TYPO3 CMS and there are extension for virtually everything! Simply download them from the TYPO3 extension repository and install them via the Extension Manager in the TYPO3 back-end. So far so good …

Often, the remaining tasks of configuring the extension, adding new pages with the plug-ins from the extension or importing required data into the database becomes much more cumbersome. Why can’t life be not as easy as in other CMS? Just click and everything works?

Yes, we can!

The infrastructure for performing additional tasks after installing extensions is part of TYPO3 since some time. At least since TYPO3 6.2 it works flawlessly, before your way may vary. The trick is to utilize the signal/slot mechanism to connect to the Extension Management service and listen for signals emitted after an extension was installed.

In the Aimeos TYPO3 web shop extension we’ve added the following code to the ext_localconf.php:

  1. if (TYPO3_MODE === 'BE') {
  2.     $class = 'TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher';
  3.     $dispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($class);
  4.     $dispatcher->connect(
  5.         'TYPO3\\CMS\\Extensionmanager\\Service\\ExtensionManagementService',
  6.         'hasInstalledExtensions',
  7.         'Aimeos\\Aimeos\\Setup',
  8.         'executeOnSignal'
  9.     );
  10. }

The first line ensures that we are connecting only to the Extension Management service if we are in the back-end. If you leave this line out, your script would connect at every front-end request too, which would only slow down response times. The next two lines instantiates the signal/slot dispatcher class and the makeInstance() method of the GeneralUtility class does a good job.

Don’t use the PHP “new” operator for creating the class instance! This would create one instance each time the code is executed instead of sharing a common instance during the request.

The remaining lines connect your method executeOnSignal() of your namespaced class Aimeos\Aimeos\Setup to the Extension Management service whose class name is handed over as first parameter. Here we are listening to the hasInstalledExtensions signal, that is emitted by the service after an extension has been installed. The key of the installed extension will be passed as first parameter to our method.

There’s another signal that is emitted by the Extension Management service named willInstallExtensions. By listening to this signal, your script can be informed about which extensions are going to be installed next. An array of extension keys is given in this case.

Do what you need

At last, you need to create a class that contains the code to be executed after an extension is installed. The Aimeos TYPO3 extension contains a Setup class in the Classes/ directory of the extension with a method named executeOnSignal() to care about this. The basic code of this class is:

  1. <?php
  2.  
  3. namespace Aimeos\Aimeos;
  4.  
  5. class Setup
  6. {
  7.     public function executeOnSignal( $extname = null )
  8.     {
  9.         if( $extname !== 'aimeos' ) {
  10.             return;
  11.         }
  12.  
  13.         // your code
  14.     }
  15. }

The namespace declaration is important but must be adapted to your extension. The first namespace part is the vendor name, e.g. the name of your company. The second part is the extension key with the first letter uppercased. If your extension key contains an underscore, then the underscore is removed and the next character transformed to uppercase as well, e.g. the boostrap_package uses BootstrapPackage as the second namespace part.

You are free to use any valid class and method name in your extension. Only make sure that the third and fourth parameter of the connect() method call are named appropriately. Also, ensure that your class and method are neither abstract nor static so an instance can be created. Like said above, the key name of the extension that has been installed is given as first parameter to your method. For compatibility reasons, you should make that parameter optional by assigning a default value of null.

Use the given extension key name to filter for your one! The Extension Management service will inform your script about every extension that is installed, not only your own one. Otherwise, you would execute your script code for every installed extension and this may slow down the installation process depending on how much your code does.

What’s next?

Pretty simple, isn’t it? Now it’s time to pimp your TYPO3 extension to remove as much burden as possible from the user! In a second article we will go into more detail how this can save your users day when your extension imports pages and depending TypoScript configuration.

A special thanks goes to Benjamin Kott for his bootstrap_package because it was the first that provided a working example that the signal/slot infrastructure can be used for these kind of use cases.