How to (quickly) port a module to OXID eShop 6.0

This post describes the minimum changes necessary to make an existing module immediately compatible with OXID eShop 6.0. In a later blog post we will tell you how to fully port a module or write a new one from scratch so that it fits OXID eShop 6.0 and above.

UTF-8 only

As announced earlier, OXID eShop will only support the UTF-8 character set from version 6 on. This means, that all file types like language files, SQL files, the code itself as well as tests have to be converted to UTF-8. Please consider to use iconv for this task.

Required PHP version

The code must work with PHP 5.6 or higher. Check for documentation.

Removed functionality in OXID eShop

Make sure your module does not use any of the functionality that was deprecated in 5.3 and has been removed with OXID eShop 6.0. You can find a list of changes at OXIDforge.

Mind that from V6 on, OXID eShop is using namespaces, and that nearly all classes known from 5.3 and before have been marked as deprecated. A so called “backwards compatibility layer” (BC layer) ensures that the older class names still can be used via aliases. As long as existent, you may use the BC classes’ equivalent from virtual namespace (VNS).

Later, with another major release, we will drop the BC layer. At this point you should have ported your module to the new classes. As mentioned above, a detailed blog post on how to do this will follow.

Explanatory remark: the virtual namespace (“OxidEsales\Eshop”) was introduced in OXID eShop to provide an edition independent namespace for module and core developers. No matter if the shop edition is CE, PE or EE: as long as the class name of the virtual namespace is used you will always end up with the correct edition specific code.

Make your module installable via composer

We recommend to make the module installable via composer. Modules that will be implemented in the shop compilation must be installable via composer (use composer.json).

Modules will be installed via composer by using the OXID eShop Composer Plugin. In order to install a module correctly this plugin requires two fields to be described in the module’s composer.json file:

  • type: The module must have the value “oxideshop-module” as type. This defines how the repository should be treated by the installer.
  • target-directory: The value “target-directory” will be used to create a folder inside modules/ . This new folder will be used to place all files of the module.

Example: composer.json file for the OXID eShop Extension PayPal (PayPal module)

       "name": "oxid-esales/paypal-module",
       "description": "This is the PayPal module for OXID eShop.",
       "type": "oxideshop-module",
       "keywords": ["oxid", "modules", "eShop"],
       "homepage": "",
       "license": [
       "extra": {
         "oxideshop": {
           "target-directory": "oe/oepaypal"

Stick to database interfaces

Please especially have an eye on the changes in database layer. AdoDBLite (in OXID eShop 4/5.x) was exchanged in favour of Doctrine/DBAL which might lead to a slightly different behavior in some cases. We had to introduce some BC breaks. Please check the 5.3 code for what will be deprecated:

New equivalents:

In ADODB lite there was actually nothing like a “ResultSetInterface”. This interface was introduced in v5.3.0 in order to have an upgrade path to v6.0.

IMPORTANT: The return values of for example oxDb::getDb()->select() and oxDb::getDb()->selectLimit() were changed, now an instance of ResultSet (implementing ResultSetInterface) will be returned.

Deprecated (5.3) logic, does not work in 6.0 and higher any more:

        $rs = oxDb::getDb()->select($sQuery);
        if ($rs != false && $rs->recordCount() > 0) {
            while (!$rs->EOF) {
                //do something

Example: new (since 6.0) logic

         $resultSet = \OxidEsales\Eshop\Core\DatabaseProvider::getDb()->select($query);
         //Fetch the results row by row
         if ($resultSet != false && $resultSet->count() > 0) {
             while (!$resultSet->EOF) {
                 $row = $resultSet->getFields();
                 //do something

Example: new (since 6.0) logic

         $resultSet = \OxidEsales\Eshop\Core\DatabaseProvider::getDb()->select($query);
         //Fetch all at once (beware of big arrays)
         $allResults = $resultSet->fetchAll()
         foreach($allResults as $row) {
            //do something

VERY IMPORTANT: do not try something like this, you will lose the first result row:

         $resultSet = \OxidEsales\Eshop\Core\DatabaseProvider::getDb()->select($query);
         while ($row = $resultSet->fetchRow()) {
                //do something

The point is: the ResultSet immediately executes the first call to ResultSet::fetchRow() in its constructor, and each following call to ResultSet::fetchRow() advances the content of ResultSet::fields to the next row. Do always access ResultSet::fields before calling ResultSet::fetchRow() again.

That’s it for now, happy coding 🙂 In case you experience any difficulties to get you modules up and running with OXID eShop 6.0, please drop us a note either in comments or via dev-general mailing list.

[UPDATE] Yesterday, we announced OXID eShop v6 RC1 “partner release”. Please find more information about the changes and on how to fetch and install this version in this blog post.

5 replies
  1. Ray Ehrhardt
    Ray Ehrhardt says:

    > VERY IMPORTANT: do not try something like this, you will lose the first result row
    How do I preserve it then, without loading all result rows into the RAM and risk running into the memory limit?

  2. HR
    HR says:

    Look at the first example for how you should use the ResultSet in 6.0. It’s for iterating over all rows without losing anything.


Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published.