Приветствую коллеги! Заморочился я тут с Inline Elements, как мы уже знаем там нет функционала как в Group и добавлять существующие записи уже невозможно, а хотелось бы.. можно конечно использовать Group c "+", но тогда если нам нужно создать, нас будет кидать на новую страницу.. что совсем не камильфо, нужно здесь и сейчас, т.е. нам все таки нужен функционал Inline.
Мне вот тут приперло, так что делюсь своим решением это задачи.. опять же у кого есть задумки лучше и проще, прошу в студию.
На выходе мы получим вот такую красоту, поиск с автокомплитом и доп кнопку на "Отсоединение элемента", так что бы старые элементы не удалялись, а отсоединялись. 
Поехали...
1. создаем новый ajaxRoute -> Cofiguration/Backend/AjaxRoutes.php
	PHP код:
	
		
			
<?php
use TYPO3\CMS\Backend\Controller;
return [
    'wizard_get_related' => [
        'path' => '/wizard/get-related',
        'target' => \Extension\Backend\Form\Wizard\GetRelatedWizard::class . '::searchAction'
    ],  
];
		
	
 В визард будем слать запросы на поиск.
2. в ext_tables.php добавляем иконку кнопки и Hook для InlineElements
	PHP код:
	
		
			
$iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class);
 $iconRegistry->registerIcon(
        'chain-broken',
        \TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider::class,
        ['source' => 'EXT:iconfont/Resources/Public/Image/font-awesome/chain-broken.png']
    );
// У меня стоит ext iconfont вы можете подгрузить любую свою (svg или png)
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms_inline.php']['tceformsInlineHook'][$_EXTKEY] =
            \Extension\Hooks\InlineElementHook::class;
// Этот Хук нужен для создания кнопки Unchain 
		
	
 3. Ищем FormInlineAjaxController в sysext и забираем его целиком (Можно конечно дописать свою функци, потом сделать extend.. но как по мне проще было просто скопировать)
его кладем сюда: Classes\Controller\FormInlineAjaxController.php
И меняем всего пару строк:
	PHP код:
	
		
			
...
//ищем вот это:
if ($childChildUid) {
            $formDataCompilerInput['inlineChildChildUid'] = $childChildUid;
        }
// далее эту строку:
$childData = $formDataCompiler->compile($formDataCompilerInput);
// меняем на  это:
if($parentConfig['addrelated'] && !$parentConfig['foreign_selector'] && $childChildUid)
            $childData = $this->compileChild($parentData, $parentFieldName, (int)$childChildUid, $inlineStackProcessor->getStructure());
        else
            $childData = $formDataCompiler->compile($formDataCompilerInput);
//$parentConfig['addrelated'] - это новый параметр в TCA config, что бы отсеивать рендеринг добавляем элементов. Обязательно при условии !$parentConfig['foreign_selector'] это условие что мы не рендерим все через вспомогательные таблицы и $childChildUid это что бы наверняка! 
		
	
 $childData = $this->compileChild -> тут получаем всю инфу по добавляемому элементу. Это позволит получить все напрямую, без foreign_selectorи т.д. в нашем случае мы работаем с таблицей напрямую, а не через Intermediate tables. 
4. Classes/Form/Wizard/GetRelatedWizard.php
Тут многое из SuggestWizard.. только в немного упрощенном виде
Думаю еще можно сократить... 
	PHP код:
	
		
			
<?php
namespace Extension\Backend\Form\Wizard;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
use TYPO3\CMS\Lang\LanguageService;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
class GetRelatedWizard
{
 /**
     * Renders an ajax-enabled text field. Also adds required JS
     *
     * @param string $fieldname The fieldname in the form
     * @param string $table The table we render this selector for
     * @param string $field The field we render this selector for
     * @param array $row The row which is currently edited
     * @param array $config The TSconfig of the field
     * @return string The HTML code for the selector
     */
    public function renderSuggestSelector($fieldname, $table, $field, array $row, array $config)
    {
        /** @var $iconFactory IconFactory */
        $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
        $languageService = $this->getLanguageService();
        $minChars = 2;
        $uids = $row[$field];
        // fetch the TCA field type to hand it over to the JS class
        $type = 'inline';
        $selector = '
        <div class="autocomplete t3-form-suggest-container">
            <div class="input-group">
                <span class="input-group-addon">' . $iconFactory->getIcon('actions-search', Icon::SIZE_SMALL)->render() . '</span>
                <input type="search" class="t3-form-suggest-inline form-control"
                    placeholder="' . $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.findRecord') . '"
                    data-fieldname="' . $fieldname . '"
                    data-table="' . $table . '"
                    data-field="' . $field . '"
                    data-uid="' . $row['uid'] . '"
                    data-pid="' . $row['pid'] . '"
                    data-uids="' . $row[$field] . '" // сюда добавляем все юиды элементов которые у нас уже есть
                    data-fieldtype="' . $type . '"
                    data-minchars="' . $minChars . '"
                    data-recorddata="' . htmlspecialchars($jsRow) . '"
                />
            </div>
        </div>';
        return $selector;
    }
     /**
     * Ajax handler for the "suggest" feature in FormEngine.
     *
     * @param ServerRequestInterface $request
     * @param ResponseInterface $response
     * @return ResponseInterface
     */
    public function searchAction(ServerRequestInterface $request, ResponseInterface $response)
    {
        $parsedBody = $request->getParsedBody();
        $queryParams = $request->getQueryParams();
        
        // Get parameters from $_GET/$_POST
        $search = isset($parsedBody['value']) ? $parsedBody['value'] : $queryParams['value'];
        $table = isset($parsedBody['table']) ? $parsedBody['table'] : $queryParams['table'];
        $field = isset($parsedBody['field']) ? $parsedBody['field'] : $queryParams['field'];
        $uid = isset($parsedBody['uid']) ? $parsedBody['uid'] : $queryParams['uid'];
        $pageId = (int)(isset($parsedBody['pid']) ? $parsedBody['pid'] : $queryParams['pid']);
        $uids =  isset($parsedBody['uids']) ? $parsedBody['uids'] : $queryParams['uids'];
        $newRecordRow = isset($parsedBody['newRecordRow']) ? $parsedBody['newRecordRow'] : $queryParams['newRecordRow'];
        
        
        $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
        $queryTables = $this->getTablesToQueryFromFieldConfiguration($fieldConfig);
        $whereClause = $this->getWhereClause($fieldConfig, $uids);
 
        $resultRows = array();
        foreach ($queryTables as $queryTable) {
            // if the table does not exist, skip it
            if (!is_array($GLOBALS['TCA'][$queryTable]) || empty($GLOBALS['TCA'][$queryTable])) {
                continue;
            }
            $config = array('searchWholePhrase'=> 1);
             // process addWhere
            if ($whereClause) {
                $config['addWhere'] = $whereClause;
            }
            $config['maxItemsInResultList'] = 10;
           $receiverClassName = \TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver::class;
           $receiverObj = GeneralUtility::makeInstance($receiverClassName, $queryTable, $config);
           $params = array('value' => $search);
           $rows = $receiverObj->queryTable($params);
        }
       $maxItems = $config['maxItemsInResultList'];
       $maxItems = min(count($rows), $maxItems);
        $listItems = $this->createListItemsFromResultRow($rows, $maxItems);
        $response->getBody()->write(json_encode($listItems));
        return $response;
    }
    /**
     * @return LanguageService
     */
    protected function getLanguageService()
    {
        return $GLOBALS['LANG'];
    }
    /**
     * Checks the given field configuration for the tables that should be used for querying and returns them as an
     * array.
     *
     * @param array $fieldConfig
     * @return array
     */
    protected function getTablesToQueryFromFieldConfiguration(array $fieldConfig)
    {
        $queryTables = array();
        if (isset($fieldConfig['allowed'])) {
            if ($fieldConfig['allowed'] !== '*') {
                // list of allowed tables
                $queryTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed']);
            } else {
                // all tables are allowed, if the user can access them
                foreach ($GLOBALS['TCA'] as $tableName => $tableConfig) {
                    if (!$this->isTableHidden($tableConfig) && $this->currentBackendUserMayAccessTable($tableConfig)) {
                        $queryTables[] = $tableName;
                    }
                }
                unset($tableName, $tableConfig);
            }
        } elseif (isset($fieldConfig['foreign_table'])) {
            // use the foreign table
            $queryTables = array($fieldConfig['foreign_table']);
        }
        return $queryTables;
    }
    /**
     * Returns the SQL WHERE clause to use for querying records. This is currently only relevant if a foreign_table
     * is configured and should be used; it could e.g. be used to limit to a certain subset of records from the
     * foreign table
     *
     * @param array $fieldConfig
     * @param string $usedUids
     * @return string
     */
    protected function getWhereClause(array $fieldConfig, $usedUids)
    {
        if(!empty($usedUids)){
           return 'AND uid NOT IN ('.$usedUids.')';
        } else {
            return '';
        }
       // показываем только те элементы которых нет в уже добавленных
    }
    /**
     * Creates a list of <li> elements from a list of results returned by the receiver.
     *
     * @param array $resultRows
     * @param int $maxItems
     * @param string $rowIdSuffix
     * @return array
     */
    protected function createListItemsFromResultRow(array $resultRows, $maxItems)
    {
        if (empty($resultRows)) {
            return array();
        }
        $listItems = array();
        // traverse all found records and sort them
        $rowsSort = array();
        foreach ($resultRows as $key => $row) {
            $rowsSort[$key] = $row['text'];
        }
        asort($rowsSort);
        $rowsSort = array_keys($rowsSort);
        // put together the selector entries
        for ($i = 0; $i < $maxItems; ++$i) {
            $listItems[] = $resultRows[$rowsSort[$i]];
        }
        return $listItems;
    }
}
		
	
 Комментировать тут особо нечего, убрал все что ненужно и не используется. 
5. Classes\Hooks\InlineElementHook.php
Тут добавим нашу новую кнопку Unchain
	PHP код:
	
		
			
<?php
namespace Extension\Hooks;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Lang\LanguageService;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Backend\Form\InlineStackProcessor;
/**
 * Inline Element Hook
 *
 */
class InlineElementHook implements \TYPO3\CMS\Backend\Form\Element\InlineElementHookInterface
{
    /**
     * Initializes this hook object.
     *
     * @param \TYPO3\CMS\Backend\Form\Element\InlineElement $parentObject
     * @return void
     */
    public function init(&$parentObject)
    {
    }
    /**
     * Pre-processing to define which control items are enabled or disabled.
     *
     * @param string $parentUid The uid of the parent (embedding) record (uid or NEW...)
     * @param string $foreignTable The table (foreign_table) we create control-icons for
     * @param array $childRecord The current record of that foreign_table
     * @param array $childConfig TCA configuration of the current field of the child record
     * @param bool $isVirtual Defines whether the current records is only virtually shown and not physically part of the parent record
     * @param array &$enabledControls (reference) Associative array with the enabled control items
     * @return void
     */
    public function renderForeignRecordHeaderControl_preProcess(
        $parentUid,
        $foreignTable,
        array $childRecord,
        array $childConfig,
        $isVirtual,
        array &$enabledControls
    ) {
    }
    /**
     * Post-processing to define which control items to show. Possibly own icons can be added here.
     *
     * @param string $parentUid The uid of the parent (embedding) record (uid or NEW...)
     * @param string $foreignTable The table (foreign_table) we create control-icons for
     * @param array $childRecord The current record of that foreign_table
     * @param array $childConfig TCA configuration of the current field of the child record
     * @param bool $isVirtual Defines whether the current records is only virtually shown and not physically part of the parent record
     * @param array &$cells (reference) Associative array with the currently available control items
     * @return void
     */
    public function renderForeignRecordHeaderControl_postProcess(
        $parentUid,
        $foreignTable,
        array $childRecord,
        array $childConfig,
        $isVirtual,
        array &$cells
    ) {
       \\ кнопку можно убрать и вернуть старый добрый делит.. 
        if($childConfig['appearance']['enabledControls']['unchain']){
;
            $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
            $languageService = GeneralUtility::makeInstance(LanguageService::class);
            $title = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.remove_selected', true);
            $unchain = '
                    <a class="btn btn-default t3js-editform-unchain-inline-record" href="#" >
                        ' . '<span title="' . $title . '">' . $iconFactory->getIcon('chain-broken', Icon::SIZE_SMALL)->render() . '</span>' . '
                    </a>'; 
            $cells = array_slice($cells, 0, 0, true) + array('unchain' => $unchain) + array_slice($cells, 0, count($cells), true);
            //' . htmlspecialchars($nameObjectFtId) . '
        }
        
    }
}
		
	
 6. Classes\UserFunc\ExetndControls.php
Тут мы срендерим  наш инпут поиска
	PHP код:
	
		
			
<?php
namespace Extension\UserFunc;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Lang\LanguageService;
 class ExtendControls {
     /**
       * Return standard host name for the local machine
       *
     * @param array $params
     * @param array $ref
     * @return void
       */
     public function searchRelated(array &$params, &$ref){
        
        $languageService = GeneralUtility::makeInstance(LanguageService::class);
        
        $table = $params['table'];
        $filedname = $params['nameForm'];
        $field = $params['field'];
        $row = $params['row'];
        $title = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:cm.createNewRelation', true);
        $suggestProcessor = GeneralUtility::makeInstance(\ER\ErPlaces\Backend\Form\Wizard\GetRelatedWizard::class);
        $suggest = $suggestProcessor->renderSuggestSelector($filedname, $table, $field, $row, $params);
        
        // По умолчанию extended config появится под всеми полями.. так что просто убираем поиск вверх через position:absolute
        $html = '<div style="width:300px; position: absolute; right:0; top: 23px; margin-right: 15px;" ' . ($className ? ' class="' . $className . '"' : '') . 'title="' . $title . '">' . $suggest . '</div>';
       // скрипты пока не придумал как добавить по нормальному, т.к. &$ref -> resultArray (Protected) и добавить туда что либо из юзерфунка не выйдет.. так что пока вот по глупому все будет копироваться, два инпута два скрипта.. 
       
       // ! можно конечно напрямую Backend/Classes/Form/Container/InlineControlContainer.php меняем protected $requireJsModules на public и добавляем скрипт.
      //  $ref->requireJsModules[] = array(
      //       '../typo3conf/ext/service/Resources/Public/JavaScript/GetRelated' => 'function(GetRelatedInit){GetRelatedInit(".t3-form-suggest-inline")}'
      //  );
        $html .= '
            <script type="text/javascript">
            /*<![CDATA[*/
            require(["../typo3conf/ext/er_places/Resources/Public/JavaScript/GetRelated"], function(GetRelatedInit){GetRelatedInit(".t3-form-suggest-inline")});
            /*]]>*/
            </script>
        ';
        return $html;
  
     }
 }
		
	
 7. Resources/Public/JavaScript/GetRelated.js
использовать обычный FormEngineSuggest.js не выйдет, у нас другой класс формы и инициализация немного по другому + тут слушаем нашу кнопку Unchain
	Код HTML:
	define(['jquery', 'jquery/autocomplete'], function ($) {
        var GetRelatedInit = function(searchField){
		var $searchField = $(searchField);
			$.each($searchField, function(key, value){
				GetRelated($(value));
			})
	};
	var GetRelated = function($searchField) {
	
		var $containerElement = $searchField.closest('.t3-form-suggest-container');
			$searchField.unbind();
		var table = $searchField.data('table'),
			field = $searchField.data('field'),
			uid = $searchField.data('uid'),
			uids = $searchField.data('uids'),
			pid = $searchField.data('pid'),
			newRecordRow = $searchField.data('recorddata'),
			minimumCharacters = $searchField.data('minchars'),
			url = TYPO3.settings.ajaxUrls['wizard_get_related'],
			params = {
				'table': table,
				'field': field,
				'uid': uid,
				'pid': pid,
				'newRecordRow': newRecordRow,
				'uids': uids
			};
		$searchField.autocomplete({
			// ajax options
			serviceUrl: url,
			params: params,
			type: 'POST',
			paramName: 'value',
			dataType: 'json',
			minChars: minimumCharacters,
			groupBy: 'typeLabel',
			containerClass: 'autocomplete-results',
			appendTo: $containerElement,
			forceFixPosition: false,
			preserveInput: true,
			showNoSuggestionNotice: true,
			noSuggestionNotice: '<div class="autocomplete-info">No results</div>',
			minLength: minimumCharacters,
			// put the AJAX results in the right format
			transformResult: function(response) {
				return {
					suggestions: $.map(response, function(dataItem) {
						return { value: dataItem.text, data: dataItem };
					})
				};
			},
			// Rendering of each item
			formatResult: function(suggestion, value) {
				console.log(suggestion);
				return $('<div>').append(
							$('<a class="autocomplete-suggestion-link" href="#">' +
								suggestion.data.sprite + suggestion.data.text +
							'</a></div>').attr({
								'data-label': suggestion.data.label,
								'data-table': suggestion.data.table,
								'data-uid': suggestion.data.uid
							})).html();
			},
			onSearchComplete: function() {
				$containerElement.addClass('open');
			},
			beforeRender: function(container) {
				// Unset height, width and z-index again, should be fixed by the plugin at a later point
				container.attr('style', ' width:300px');
				$containerElement.addClass('open');
			},
			onHide: function() {
				$containerElement.removeClass('open');
			}
		});
		// set up the events
		$containerElement.on('click', '.autocomplete-suggestion-link', function(evt) {
			evt.preventDefault();
			var insertData = $(this).data('uid'),
				objectidPart1 = $(this).parents('.form-group').attr('id'),
				table = $(this).data('table'),
				objectid = $(this).parents('.form-group').attr('id')+'-'+table;
			inline.importElement(objectid, table, insertData, 'db');
			// используем import раз уж он есть
		});
			require(['jquery', 'TYPO3/CMS/Backend/Modal'], function ($, Modal) {
				$(document).on('click', '.t3js-editform-unchain-inline-record', function(e) {
					e.preventDefault();
						
						var $objectid = $(this).parents('.panel-heading').attr('id').slice(0, -7), 
							shortName = inline.parseObjectId('parts', $objectid, 2, 0, true);,
							title = 'Unchain this record?',
							content = 'Are you sure you want to unchain this record?';
	
						var $modal = Modal.confirm(title, content, top.TYPO3.Severity.warning, [
							{
								text: TYPO3.lang['buttons.confirm.delete_record.no'] || 'Cancel',
								active: true,
								btnClass: 'btn-default',
								name: 'no'
							},
							{
								text: 'Yes, unchain this record',
								btnClass: 'btn-warning',
								name: 'yes'
							}
						]);
						$modal.on('button.clicked', function(e) {
							if (e.target.name === 'no') {
								Modal.dismiss();
							} else if (e.target.name === 'yes') {
								inline.deleteRecord($objectid);
								if(document.getElementsByName('cmd' + shortName + '[delete]').length){
									$(document.getElementsByName('cmd' + shortName + '[delete]')).attr('disabled', 'disabled');
								}
								Modal.dismiss();
							}
						});
					});
				});
		
	}
	return GetRelatedInit;
});
 По JS да же не знаю что комментировать, так что если будут вопросы спрашивайте.. а на этом вроде все.
Чуть не забыл, вот пример TCA:
	PHP код:
	
		
			
...
'type' => 'inline',
'foreign_table' => 'tx_example_domain_model_object',
'MM' => 'tx_example_domain_model_object_contacts_mm',
// Special Field for additional search
'addrelated' => true,
...
'enabledControls' => array(
// our button UNCHAIN
'unchain' => TRUE,
'delete' => 0,
),
... 
		
	
 P.S. 
Мой вам совет, что бы в поиске иконка всплывала нужно в TCA для каждой таблицы указывать
'ctrl' => array (
...
'typeicon_classes' => array(
            'default' => 'ext-example-icon'
        ),
..
)
с добавлением в ext_tables.php