Maps2 Registry 

Available since version 3.0.0

This is a pretty cool feature to extend your own extension with a new field which will hold the reference UID to a PoiCollection record of maps2. So, if you have a location record or something similar, then you can use our Maps2 registry to create a new field into a table of your extension. The default name of the column will be tx_maps2_uid, but you can change that, if you want.

Our Maps2 registry is adapted from System categories API

Create a new file in [yourExt]/Configuration/TCA/Overrides/[yourTableName].php and add the individually needed lines of code. Following is a slightly example for events2 with all possible properties:

\JWeiland\Maps2\Tca\Maps2Registry::getInstance()->add(
    'events2', // Extension key of your extension
    'tx_events2_domain_model_location', // tablename of your location table
    [
        // add all columns to build a valid address as array
        // Add country only, if it is a string like "Germany". Else, see next options
        'addressColumns' => ['street', 'house_number', 'zip', 'city', 'country'],

        // You can define a hard-coded country for all addresses.
        'defaultCountry' => 'France',

        // Best option for country. If it is an INT and static_info_tables is loaded, it will
        // get country name from static_country.
        // If country could not be fetched, it will fallback to defaultCountry from above.
        'countryColumn' => 'country',

        // Optional: If you want to assign a PoiCollection only to a reduced set of records, you should use
        // ``columnMatch`` property. Internally this is a very simple array value comparison. No DB! If
        // you need more than simple comparison you can use SignalSlot in ``CreateMaps2RecordHook``.
        'columnMatch' => [
            // Simple match
            'pid' => '12',
            'title' => 'jweiland.net',

            // More complex examples:

            // Same as above: equals
            'pid' => [
                'expr' => 'eq',
                'value' => '12',
            ]

            // pid is in list of comma separated values
            'pid' => [
                'expr' => 'in',
                'value' => '11,12,13',
            ]

            // pid is greater than 8
            'pid' => [
                'expr' => 'gt',
                'value' => '8',
            ]

            // pid is greater than or equals 12
            'pid' => [
                'expr' => 'gte',
                'value' => '12',
            ]

            // pid is less than 15
            'pid' => [
                'expr' => 'lt',
                'value' => '15',
            ]

            // pid is less than or equals 12
            'pid' => [
                'expr' => 'lte',
                'value' => '12',
            ]
        ],

        // With defaultStoragePid you can define where our maps2 record should be saved.
        // defaultStoragePid has following priority from low to high:
        // PID of your location record, Configuration of Maps2Registry, pageTSconfig (ext.maps2.defaultStoragePid)
        // This order is hardcoded and can not be changed.
        // So, if a PID with help of Maps2Registry was found, it will be overwritten with value of pageTSconfig.

        // Within the Maps2Registry we have following ordering from low to high:
        // A fixed value, an extension configuration value, a pageTSconfig value.

        // Define a fixed storage PID where to save our maps2 PoiCollection record.
        // Useful for small websites. Single domain instances.
        // Keep in mind that this value will be overwritten with pageTSconfig (ext.maps2.pid)
        'defaultStoragePid' => 414,

        // Do not configure "defaultStoragePid" if you want to save maps2 PoiCollection records
        // in same storage as your location record. But, be careful: As a fallback we are using
        // pageTSconfig path "ext.maps2.defaultStoragePid" which has a higher priority than PID of your location record.
        // So, keep that in mind, remove "ext.maps2.defaultStoragePid" from pageTSconfig to save maps2 record in same storage
        // of your records.

        // Read an extension manager configuration from ext_conf_template.txt of a given extension
        'defaultStoragePid' => [
            'extKey' => 'events2', // extension to read $EXTCONF from
            'property' => 'poiCollectionPid', // Property with storage UID
            'type' => 'extensionmanager' // If type is not given, we will use "extensionmanager" as default.
        ],

        // Read storage PID from pageTSconfig
        // You can configure that path to your needs. In example below we try to get storage PID
        // from pageTSconfig: ext.events2.poiCollectionPid = 4324
        // Do not forget: If pageTSconfig (ext.maps2.defaultStoragePid) is set, it will overwrite this configuration.
        'defaultStoragePid' => [
            'extKey' => 'events2', // Extension key to read storage PID from
            'property' => 'poiCollectionPid', // Property key to read storage PID from
            'type' => 'pagetsconfig'
        ],

        // Priority ordered version
        // We will read all these entries from array key 0 until array key 3. If a PID was found in f.e.
        // array key 2 (after entry 0 and 1 have not returned a valid PID) we will use it and will not
        // process further entries (entry 3)
        'defaultStoragePid' => [
            0 => [
                'extKey' => 'news',
                'property' => 'pid_of_maps2',
                'type' => 'pagetsconfig'
            ],
            1 => [
                'extKey' => 'my_ext',
                'property' => 'specialConfiguredPidForMaps2',
                'type' => 'pagetsconfig'
            ],
            2 => [
                'extKey' => 'my_ext',
                'property' => 'mapsPid',
                'type' => 'extensionmanager'
            ],
            3 => [
                'extKey' => 'events2',
                'property' => 'poiCollectionPid',
                'type' => 'extensionmanager'
            ],
        ],

        // You can synchronize additional fields of your record with maps2 PoiCollection
        // Please only use fields of type String or int.
        // 1:N, N:1 and N:M relations are not supported. Please use SignalSlot postUpdatePoiCollection
        // and synchronize them on your own.
        'synchronizeColumns' => [
            [
                'foreignColumnName' => 'location', // column name of your extension
                'poiCollectionColumnName' => 'title' // column name of maps2 PoiCollection record
            ]
        ]
    ]
);
Copied!

Example for tt_address 

<?php
if (!defined('TYPO3')) {
    die('Access denied.');
}

call_user_func(function() {
    if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('maps2')) {
        \JWeiland\Maps2\Tca\Maps2Registry::getInstance()->add(
            'tt_address',
            'tt_address',
            [
                'addressColumns' => ['address', 'zip', 'city'],
                'countryColumn' => 'country',
                'synchronizeColumns' => [
                    [
                        'foreignColumnName' => 'name',
                        'poiCollectionColumnName' => 'title'
                    ]
                ]
            ]
        );
    }
});
Copied!

Synchronize Composed Values (Coalesce/Concat) 

You can add multiple configurations to synchronizeColumns. foreignColumnName does not have to be a plain column name. It also accepts a structured configuration to combine several columns of your foreign table into a single value, which is resolved before it is written into the POI collection record.

Coalesce: Fall Back to Another Column 

Use type coalesce if you want maps2 to try several columns in order and use the first one that is not empty. This is useful if your table stores either a company name or a person name, for example:

EXT:my_ext/Configuration/TCA/Overrides/tt_address.php
'synchronizeColumns' => [
    [
        'foreignColumnName' => [
            'type' => 'coalesce',
            'columns' => [
                'company',
                'name',
            ],
        ],
        'poiCollectionColumnName' => 'title',
    ],
],
Copied!

Concat: Combine Multiple Columns 

Use type concat if you want maps2 to join several columns into a single value, separated by glue (defaults to a single space):

EXT:my_ext/Configuration/TCA/Overrides/tt_address.php
'synchronizeColumns' => [
    [
        'foreignColumnName' => [
            'type' => 'concat',
            'columns' => [
                'first_name',
                'last_name',
            ],
            'glue' => ' ',
        ],
        'poiCollectionColumnName' => 'title',
    ],
],
Copied!

Empty columns are skipped automatically, so a record with only a last_name will not end up with a leading glue in the synchronized value. See Value Resolution Rules below for the exact rules governing empty and blank columns.

Nesting Coalesce and Concat 

Every entry of columns may again be a plain column name or a nested coalesce/concat configuration. This allows you to combine both strategies, for example: prefer the company column, otherwise fall back to the concatenated first_name and last_name columns:

EXT:my_ext/Configuration/TCA/Overrides/tt_address.php
'synchronizeColumns' => [
    [
        'foreignColumnName' => [
            'type' => 'coalesce',
            'columns' => [
                'company',
                [
                    'type' => 'concat',
                    'columns' => [
                        'first_name',
                        'last_name',
                    ],
                    'glue' => ' ',
                ],
            ],
        ],
        'poiCollectionColumnName' => 'title',
    ],
],
Copied!

Nesting works symmetrically and at any depth: a concat may just as well contain a nested coalesce (e.g. concat(first_name, coalesce(company, last_name))), and that combination may again be nested inside another coalesce or concat. How an empty nested concat is treated by a surrounding coalesce is described in Value Resolution Rules below.

Shorthand: Plain List as Coalesce 

A plain, non-associative list of column names and/or nested configurations (i.e. without type/columns) is automatically treated as a coalesce: maps2 tries every entry in order and uses the first one that resolves to a non-empty value. This is handy to fall back from one combined strategy to another one, for example: prefer company or name, otherwise fall back to the concatenated first_name and last_name columns:

EXT:my_ext/Configuration/TCA/Overrides/tt_address.php
'synchronizeColumns' => [
    [
        'foreignColumnName' => [
            [
                'type' => 'coalesce',
                'columns' => ['company', 'name'],
            ],
            [
                'type' => 'concat',
                'columns' => ['first_name', 'last_name'],
            ],
        ],
        'poiCollectionColumnName' => 'title',
    ],
],
Copied!

type also accepts a JWeilandMaps2TcaForeignColumnResolveTypeEnum case directly instead of its string value, if you prefer a typed constant over a magic string.

Value Resolution Rules 

The following rules apply consistently to every example above, no matter how deeply coalesce and concat are nested:

  1. Every column value is trimmed before it is evaluated. A column that only contains whitespace (e.g. " " or a tab) is treated exactly like an empty column.
  2. concat filters out empty columns before joining them with glue, it does not join first and clean up afterwards. An empty column can therefore never produce a stray glue in the result, neither at the start, the end, nor in the middle. If every column of a concat is empty, the whole concat resolves to an empty string regardless of glue: a , glue with all columns empty results in '', not in ", , ,".
  3. coalesce only checks whether a candidate resolved to a non-empty string. A nested concat that resolves to an empty string (per rule 2) is therefore treated like any other empty candidate: coalesce simply moves on to the next entry of columns.