TYPO3 extension oelib 

Extension key

oelib

Package name

oliverklee/oelib

Version

main

Language

en

Author

Oliver Klee

License

This extension is published under the GNU General Public License v2.0.

Rendered

Thu, 25 Dec 2025 09:39:14 +0000

The content of this document is related to TYPO3 - a GNU/GPL CMS/Framework available from www.typo3.org

Table of Contents:

What does it do? 

This extension provides a library of functions useful for front-end plug-ins as well as for back-end modules. It currently is mostly used in extensions by Oliver Klee, but it is free to be used by every extension author.

Key features 

  • functions for easy handling of marker-based HTML templates
  • feature to easily remove subparts from a HTML template while hiding the subpart markers for non-removed subparts
  • get data from flexforms and from TS setup with one function call
  • automatic configuration checks
  • provides a proxy to access the EM configuration values and also to fake them for unit tests
  • provides a price view helper
  • the code follows the TYPO3 coding guidelines
  • the extension is actively developed

Examples 

These are some of the extensions that make use of these libraries:

  • BZD Staff Directory
  • Contacts List
  • One-time FE Account
  • Realty Manager
  • Seminar Manager

Credits 

Thanks go to the following persons for contributing bug fixes or for doing code reviews:

  • Benjamin Schulte
  • Bernd Schönbach
  • Mario Rimann (testing framework)
  • Niels Pardon
  • Oliver Klee
  • Ralph Brugger
  • Saskia Metzler (configuration proxy, email abstraction)
  • Sebastian Wittig (icons)
  • Thomas Pforte

This extension also uses code from other sources:

  • Emogrifier by the Pelago Corporation

Using domain models 

This extension already provides ready-to-use domain model and data mapper classes for the following:

  • back-end users
  • back-end user groups
  • front-end users
  • front-end user groups
  • countries (readonly)
  • languages (readonly)
  • currencies (readonly)

Models 

All models need to inherit from AbstractModel and be located in the Model/ directory of your extension. Have a look at the front-end user model in oelib as an example:

class FrontEndUser extends AbstractModel implements MailRole, Address
{
      /**
     * Gets this user's user name.
     *
     * @return string this user's user name, will not be empty for valid users
     */
      public function getUserName() {
              return $this->getAsString('username');
    }

      /**
     * Gets this user's user groups.
     *
     * @return Collection this user's FE user groups, will not be empty if
     *                       the user data is valid
     */
      public function getUserGroups() {
              return $this->getAsList('usergroup');
    }
}
Copied!

For accessing the model data, you need to use the getAs*/setAs* functions so the type checking/conversion and lazy loading works. Using member variables directly will circumvent this and is not recommended.

That’s pretty much all you need to know how to build your own models. Please read the other provided model classes for examples.

Writing data mappers 

Data mappers allow reading models from the database and writing them again. Relations are also automatically handled (the relation details are read from TCA). Please have a look at the provided data mappers for examples:

class FrontEndUserMapper extends AbstractDataMapper {
      /**
     * @var string the name of the database table for this mapper
     */
      protected $tableName = 'fe_users';

      /**
     * @var class-string<M> the model class name for this mapper, must not be empty
     */
      protected $modelClassName = FrontEndUser::class;

      /**
     * @var array the (possible) relations of the created models in the format
     *            DB column name => mapper name
     */
      protected $relations = array(
              'usergroup' => FrontEndUserGroupMapper::class,
    );
}
Copied!

Please note that you explicitly need to list all relations that should be supported (because you might want to omit some unneeded relations for performance reasons). For all relations, you also need to write the corresponding getters in the model class.

Using data mappers 

To ensure object identity, you need to access all data mappers through the mapper registry:

$realtyObject = tx_oelib_MapperRegistry
   ::get('tx_realty_Mapper_RealtyObject')->find($this->getUid());
Copied!

A model that is retrieved through a data mapper can have several states:

  • virgin: has neither any data nor a UID yet
  • ghost: already has a UID (which is not checked yet to actually exist in the DB), but the data has not been (lazily) loaded from the DB yet; will be loaded the first time a data item is accessed
  • loading: the data currently is being loaded from the DB; this is a transient state between ghost and loaded/dead
  • loaded: the model’s data has been successfully loaded from the DB
  • dead: the data mapper has tried to load this model from the DB, but has failed (because there is not record with that UID in the DB)

When working with mappers and model in unit tests, you can often skip accessing the DB by using ghosts (when only a UID is needed and the model’s data is never expected to be loaded or saved):

$realtyObject = MapperRegistry::get('tx_realty_Mapper_RealtyObject')
    ->getNewGhost();
Copied!

If you need a model with data and you’re not testing any m:n or 1:n relations, you can fill the model with data:

$realtyObject = MapperRegistry::get('tx_realty_Mapper_RealtyObject')
    ->getLoadedTestingModel(array(‘title’ => ‘nice house’, ‘city’ => $cityUid));

Copied!

Mocking a data mapper 

The mapper registry class provides a public function which you can use to pre-set a particular mapper. You can even replace it with a mock mapper:

$mapper = $this->getMock(
      'tx_realty_Mapper_District', array('findAllByCityUidOrUnassigned')
);
$mapper->expects($this->once())
      ->method('findAllByCityUidOrUnassigned')->with(42)
      ->will($this->returnValue($cities));
tx_oelib_MapperRegistry::set('tx_realty_Mapper_District', $mapper);
Copied!

Using the automatic configuration check for extensions 

You can use oelib to let your extension warn users about configuration annoyances in your extensions. This already is used in the following extensions:

  • One-time FE account
  • Realty Manager
  • Seminar Manager

Using the testing framework for unit tests 

While testing new features in the Seminar Manager extension, we were in need of tools that allow us to easily create and delete dummy records in the database. We designed a small “testing framework” as we call it.

Overview 

The testing framework enables you to easily

  • Add and change dummy records with defined record data that uses real UIDs
  • Remove single records from a database table
  • Add dummy relations to an m:n table
  • Remove single relations from a database table
  • Add dummy FE pages, FE user groups, FE users, system folders, content elements, TS templates and page cache entries
  • Create a fake front end for testing front-end plugins
  • Count records

Before you start 

You need the following stuff before you start:

  • This extension (tx_oelib) must be installed
  • You'll have to write your own test suite for your extension

Write a test suite 

Now write your test suite. Keep in mind that the file must be located under /tests/ in your extension's directory, the filename must end with “testcase.php” and the names of all test methods must start with “test”.

The testing framework must be instantiated once per extension that you're about to write tests. This is mainly for security reasons! If you instantiate it for “tx_seminars”, it will not allow you to add/remove any record on any table outside of the tx_seminars scope (this means all table names must start with “tx_seminars” in that case).

Here's a very short example that might help you to integrate our testing framework into your tests. It's taken 1:1 from the tests for the Seminar Manager extension.We're not able to provide a full introduction about unit testing and PHPUnit at all. So please read one of the many good documentations regarding this topic.

<?php
class tx_seminars_categoryTest extends tx_phpunit_testcase {
  private $fixture;
  private $testingFramework;

  /** UID of the fixture's data in the DB */
  private $fixtureUid = 0;

  public function setUp() {
          $this->testingFramework = new tx_oelib_testingFramework('tx_seminars');
          $this->fixtureUid = $this->testingFramework->createRecord(
                  SEMINARS_TABLE_CATEGORIES,
                  array('title' => 'Test category')
                );
        }

  public function tearDown() {
          $this->testingFramework->cleanUp();
          unset($this->fixture, $this->testingFramework);
        }

  public function testGetTitle() {
          $this->fixture = new tx_seminars_category($this->fixtureUid);

          $this->assertEquals(
                  'Test category',
                  $this->fixture->getTitle()
                );
        }
}
?>
Copied!

You can have a deeper look into our example in the subdirectory “tests/” of oelib: All methods of this testing framework are covered with at least one unit test. So it will be easy to see how these tools can be used for your own unit tests.

Using the configuration proxy 

The configuration proxy provides access to the EM configuration, which is done when installing/updating an extension and defined in an extension's “ext_conf_template.txt”.Apart from getting configuration values easily, the proxy can fake configuration values. This feature is supposed to testing purposes.The configuration proxy is a singleton and is implemented lazily.

Use the proxy in a class 

Get the instance of your extension's proxy. Pass the extension key without the prefix “tx” for this. There is no need for any further initialization as this is done automatically if necessary:

$proxyInstance = ConfigurationProxy::getInstance('extension');
Copied!

Now you can get configuration values. Therefore use the getter for the expected type of value and pass the configuration value's key:

$proxyInstance->getConfigurationValueString('configurationValue');
$proxyInstance->getConfigurationValueBoolean('otherConfigurationValue');
$proxyInstance->getConfigurationValueInteger('againAConfigurationValue');

Copied!

Use the proxy for unit tests 

In addition to the getters described above, the proxy provides setters to fake the configuration for testing purposes. The setters overwrite existing configuration values and can also set totally new values which are not defined in the “ext_conf_template.txt” if this is needed:

$proxyInstance->setConfigurationValueString('configurationValue', 'any string needed for tests');$proxyInstance->setConfigurationValueBoolean('newValue', true);
Copied!

To ensure an unchanged configuration, you can retrieve the original configuration. Usually this should not be necessary:

$proxyInstance->retrieveConfiguration();
Copied!

For debugging, it might be useful to get the complete configuration:

$proxyInstance->getCompleteConfiguration();
Copied!

Using the price view helper 

  1. Create a price view helper object:

    $priceViewHelper = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(PriceViewHelper::class);
    Copied!
  2. Set the currency of the price using the ISO 4217 alpha-3 code:

    $priceViewHelper->setCurrencyFromIsoAlpha3Code('EUR');
    Copied!
  3. Set the value of the price:

    $priceViewHelper->setValue(1234.567);
    Copied!
  4. Render the price in the currency and the format as defined in ISO 4217:

    // Returns “€ 1.234,57”.
    $priceViewHelper->render();
    Copied!

Configuration 

See the tutorial how to change your extension to use the Salutation Switcher. In your TS Setup, set the following option for your extension ( not the Salutation Switcher extension!):

salutation = formal
Copied!

or

salutation = informal
Copied!

Suffixes for localization string keys 

The suffixes are appended to the normal keys using an underscore as a separator.

  • _formal
  • _informal