mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Resolve #849
This commit is contained in:
parent
49a63f37c9
commit
352ef98bc6
2 changed files with 109 additions and 214 deletions
|
|
@ -2,60 +2,30 @@
|
||||||
|
|
||||||
class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISuggestions
|
class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISuggestions
|
||||||
{
|
{
|
||||||
/**
|
private string $sLdapUri = 'ldap://localhost:389';
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sLdapUri = 'ldap://localhost:389';
|
|
||||||
|
|
||||||
/**
|
private bool $bUseStartTLS = true;
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $bUseStartTLS = True;
|
|
||||||
|
|
||||||
/**
|
private string $sBindDn = null;
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sBindDn = null;
|
|
||||||
|
|
||||||
/**
|
private string $sBindPassword = null;
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sBindPassword = null;
|
|
||||||
|
|
||||||
/**
|
private string $sBaseDn = 'ou=People,dc=example,dc=com';
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sBaseDn = 'ou=People,dc=example,dc=com';
|
|
||||||
|
|
||||||
/**
|
private string $sObjectClasses = 'inetOrgPerson';
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sObjectClasses = 'inetOrgPerson';
|
|
||||||
|
|
||||||
/**
|
private string $sUidAttributes = 'uid';
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sUidAttributes = 'uid';
|
|
||||||
|
|
||||||
/**
|
private string $sNameAttributes = 'displayName,cn,givenName,sn';
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sNameAttributes = 'displayName,cn,givenName,sn';
|
|
||||||
|
|
||||||
/**
|
private string $sEmailAttributes = 'mailAddress,mail,mailAlternateAddress,mailAlias';
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sEmailAttributes = 'mailAddress,mail,mailAlternateAddress,mailAlias';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \MailSo\Log\Logger
|
* @var \MailSo\Log\Logger
|
||||||
*/
|
*/
|
||||||
private $oLogger = null;
|
private $oLogger = null;
|
||||||
|
|
||||||
/**
|
private string $sAllowedEmails = '*';
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sAllowedEmails = '*';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $sLdapUri
|
* @param string $sLdapUri
|
||||||
|
|
@ -75,8 +45,7 @@ class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISugges
|
||||||
{
|
{
|
||||||
$this->sLdapUri = $sLdapUri;
|
$this->sLdapUri = $sLdapUri;
|
||||||
$this->bUseStartTLS = $bUseStartTLS;
|
$this->bUseStartTLS = $bUseStartTLS;
|
||||||
if (0 < \strlen($sBindDn))
|
if (\strlen($sBindDn)) {
|
||||||
{
|
|
||||||
$this->sBindDn = $sBindDn;
|
$this->sBindDn = $sBindDn;
|
||||||
$this->sBindPassword = $sBindPassword;
|
$this->sBindPassword = $sBindPassword;
|
||||||
}
|
}
|
||||||
|
|
@ -90,128 +59,37 @@ class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISugges
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function Process(\RainLoop\Model\Account $oAccount, string $sQuery, int $iLimit = 20): array
|
||||||
* @param \RainLoop\Model\Account $oAccount
|
|
||||||
* @param string $sQuery
|
|
||||||
* @param int $iLimit = 20
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function Process(RainLoop\Model\Account $oAccount, string $sQuery, int $iLimit = 20): array
|
|
||||||
{
|
{
|
||||||
$sQuery = \trim($sQuery);
|
$sQuery = \trim($sQuery);
|
||||||
|
|
||||||
if (2 > \strlen($sQuery))
|
if (2 > \strlen($sQuery)
|
||||||
{
|
|| !$oAccount
|
||||||
return array();
|
|| !\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails))
|
||||||
}
|
|
||||||
else if (!$oAccount || !\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails))
|
|
||||||
{
|
{
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
$aResult = $this->ldapSearch($oAccount, $sQuery);
|
|
||||||
|
|
||||||
$aResult = \RainLoop\Utils::RemoveSuggestionDuplicates($aResult);
|
|
||||||
if ($iLimit < \count($aResult))
|
|
||||||
{
|
|
||||||
$aResult = \array_slice($aResult, 0, $iLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $aResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $aLdapItem
|
|
||||||
* @param array $aEmailAttributes
|
|
||||||
* @param array $aNameAttributes
|
|
||||||
* @param array $aUidAttributes
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function findNameAndEmail($aLdapItem, $aEmailAttributes, $aNameAttributes, $aUidAttributes)
|
|
||||||
{
|
|
||||||
$sEmail = $sName = $sUid = '';
|
|
||||||
if ($aLdapItem)
|
|
||||||
{
|
|
||||||
foreach ($aEmailAttributes as $sField)
|
|
||||||
{
|
|
||||||
$sField = \strtolower($sField);
|
|
||||||
if (!empty($aLdapItem[$sField][0]))
|
|
||||||
{
|
|
||||||
$sEmail = \trim($aLdapItem[$sField][0]);
|
|
||||||
if (!empty($sEmail))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($aNameAttributes as $sField)
|
|
||||||
{
|
|
||||||
$sField = \strtolower($sField);
|
|
||||||
if (!empty($aLdapItem[$sField][0]))
|
|
||||||
{
|
|
||||||
$sName = \trim($aLdapItem[$sField][0]);
|
|
||||||
if (!empty($sName))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($aUidAttributes as $sField)
|
|
||||||
{
|
|
||||||
$sField = \strtolower($sField);
|
|
||||||
if (!empty($aLdapItem[$sField][0]))
|
|
||||||
{
|
|
||||||
$sUid = \trim($aLdapItem[$sField][0]);
|
|
||||||
if (!empty($sUid))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array($sEmail, $sName, $sUid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \RainLoop\Model\Account $oAccount
|
|
||||||
* @param string $sQuery
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function ldapSearch($oAccount, $sQuery)
|
|
||||||
{
|
|
||||||
$sSearchEscaped = $this->escape($sQuery);
|
$sSearchEscaped = $this->escape($sQuery);
|
||||||
|
|
||||||
$aResult = array();
|
$aResult = array();
|
||||||
$oCon = @\ldap_connect($this->sLdapUri);
|
$oCon = @\ldap_connect($this->sLdapUri);
|
||||||
if ($oCon)
|
if ($oCon) {
|
||||||
{
|
|
||||||
$this->oLogger->Write('ldap_connect: connected', \LOG_INFO, 'LDAP');
|
$this->oLogger->Write('ldap_connect: connected', \LOG_INFO, 'LDAP');
|
||||||
|
|
||||||
@\ldap_set_option($oCon, LDAP_OPT_PROTOCOL_VERSION, 3);
|
@\ldap_set_option($oCon, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||||
|
|
||||||
if ($this->bUseStartTLS && !@\ldap_start_tls($oCon))
|
if ($this->bUseStartTLS && !@\ldap_start_tls($oCon)) {
|
||||||
{
|
|
||||||
$this->logLdapError($oCon, 'ldap_start_tls');
|
$this->logLdapError($oCon, 'ldap_start_tls');
|
||||||
return $aResult;
|
return $aResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!@\ldap_bind($oCon, $this->sBindDn, $this->sBindPassword))
|
if (!@\ldap_bind($oCon, $this->sBindDn, $this->sBindPassword)) {
|
||||||
{
|
if (is_null($this->sBindDn)) {
|
||||||
if (is_null($this->sBindDn))
|
|
||||||
{
|
|
||||||
$this->logLdapError($oCon, 'ldap_bind (anonymous)');
|
$this->logLdapError($oCon, 'ldap_bind (anonymous)');
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->logLdapError($oCon, 'ldap_bind');
|
$this->logLdapError($oCon, 'ldap_bind');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $aResult;
|
return $aResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,11 +120,9 @@ class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISugges
|
||||||
|
|
||||||
$iObjCount = 0;
|
$iObjCount = 0;
|
||||||
$sObjFilter = '';
|
$sObjFilter = '';
|
||||||
foreach ($aObjectClasses as $sItem)
|
foreach ($aObjectClasses as $sItem) {
|
||||||
{
|
if (!empty($sItem)) {
|
||||||
if (!empty($sItem))
|
++$iObjCount;
|
||||||
{
|
|
||||||
$iObjCount++;
|
|
||||||
$sObjFilter .= '(objectClass='.$sItem.')';
|
$sObjFilter .= '(objectClass='.$sItem.')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,10 +130,8 @@ class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISugges
|
||||||
|
|
||||||
$aItems = array();
|
$aItems = array();
|
||||||
$sSubFilter = '';
|
$sSubFilter = '';
|
||||||
foreach ($aFields as $sItem)
|
foreach ($aFields as $sItem) {
|
||||||
{
|
if (!empty($sItem)) {
|
||||||
if (!empty($sItem))
|
|
||||||
{
|
|
||||||
$aItems[] = $sItem;
|
$aItems[] = $sItem;
|
||||||
$sSubFilter .= '('.$sItem.'=*'.$sSearchEscaped.'*)';
|
$sSubFilter .= '('.$sItem.'=*'.$sSearchEscaped.'*)';
|
||||||
}
|
}
|
||||||
|
|
@ -270,45 +144,77 @@ class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISugges
|
||||||
|
|
||||||
$this->oLogger->Write('ldap_search: start: '.$sBaseDn.' / '.$sFilter, \LOG_INFO, 'LDAP');
|
$this->oLogger->Write('ldap_search: start: '.$sBaseDn.' / '.$sFilter, \LOG_INFO, 'LDAP');
|
||||||
$oS = @\ldap_search($oCon, $sBaseDn, $sFilter, $aItems, 0, 30, 30);
|
$oS = @\ldap_search($oCon, $sBaseDn, $sFilter, $aItems, 0, 30, 30);
|
||||||
if ($oS)
|
if ($oS) {
|
||||||
{
|
|
||||||
$aEntries = @\ldap_get_entries($oCon, $oS);
|
$aEntries = @\ldap_get_entries($oCon, $oS);
|
||||||
if (is_array($aEntries))
|
if (is_array($aEntries)) {
|
||||||
{
|
if (isset($aEntries['count'])) {
|
||||||
if (isset($aEntries['count']))
|
|
||||||
{
|
|
||||||
unset($aEntries['count']);
|
unset($aEntries['count']);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($aEntries as $aItem)
|
foreach ($aEntries as $aItem) {
|
||||||
{
|
if ($aItem) {
|
||||||
if ($aItem)
|
|
||||||
{
|
|
||||||
$sName = $sEmail = '';
|
$sName = $sEmail = '';
|
||||||
list ($sEmail, $sName) = $this->findNameAndEmail($aItem, $aEmails, $aNames, $aUIDs);
|
list ($sEmail, $sName) = $this->findNameAndEmail($aItem, $aEmails, $aNames, $aUIDs);
|
||||||
if (!empty($sEmail))
|
if (!empty($sEmail)) {
|
||||||
{
|
|
||||||
$aResult[] = array($sEmail, $sName);
|
$aResult[] = array($sEmail, $sName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->logLdapError($oCon, 'ldap_get_entries');
|
$this->logLdapError($oCon, 'ldap_get_entries');
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->logLdapError($oCon, 'ldap_search');
|
$this->logLdapError($oCon, 'ldap_search');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return \array_slice($aResult, 0, $iLimit);
|
||||||
return $aResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $aResult;
|
/**
|
||||||
|
* @param array $aLdapItem
|
||||||
|
* @param array $aEmailAttributes
|
||||||
|
* @param array $aNameAttributes
|
||||||
|
* @param array $aUidAttributes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function findNameAndEmail($aLdapItem, $aEmailAttributes, $aNameAttributes, $aUidAttributes)
|
||||||
|
{
|
||||||
|
$sEmail = $sName = $sUid = '';
|
||||||
|
if ($aLdapItem) {
|
||||||
|
foreach ($aEmailAttributes as $sField) {
|
||||||
|
$sField = \strtolower($sField);
|
||||||
|
if (!empty($aLdapItem[$sField][0])) {
|
||||||
|
$sEmail = \trim($aLdapItem[$sField][0]);
|
||||||
|
if (!empty($sEmail)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($aNameAttributes as $sField) {
|
||||||
|
$sField = \strtolower($sField);
|
||||||
|
if (!empty($aLdapItem[$sField][0])) {
|
||||||
|
$sName = \trim($aLdapItem[$sField][0]);
|
||||||
|
if (!empty($sName)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($aUidAttributes as $sField) {
|
||||||
|
$sField = \strtolower($sField);
|
||||||
|
if (!empty($aLdapItem[$sField][0])) {
|
||||||
|
$sUid = \trim($aLdapItem[$sField][0]);
|
||||||
|
if (!empty($sUid)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($sEmail, $sName, $sUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -321,8 +227,7 @@ class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISugges
|
||||||
$aNewChars = array();
|
$aNewChars = array();
|
||||||
$aChars = array('\\', '*', '(', ')', \chr(0));
|
$aChars = array('\\', '*', '(', ')', \chr(0));
|
||||||
|
|
||||||
foreach ($aChars as $iIndex => $sValue)
|
foreach ($aChars as $iIndex => $sValue) {
|
||||||
{
|
|
||||||
$aNewChars[$iIndex] = '\\'.\str_pad(\dechex(\ord($sValue)), 2, '0');
|
$aNewChars[$iIndex] = '\\'.\str_pad(\dechex(\ord($sValue)), 2, '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,8 +242,7 @@ class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISugges
|
||||||
*/
|
*/
|
||||||
public function logLdapError($oCon, $sCmd)
|
public function logLdapError($oCon, $sCmd)
|
||||||
{
|
{
|
||||||
if ($this->oLogger)
|
if ($this->oLogger) {
|
||||||
{
|
|
||||||
$sError = $oCon ? @\ldap_error($oCon) : '';
|
$sError = $oCon ? @\ldap_error($oCon) : '';
|
||||||
$iErrno = $oCon ? @\ldap_errno($oCon) : 0;
|
$iErrno = $oCon ? @\ldap_errno($oCon) : 0;
|
||||||
|
|
||||||
|
|
@ -354,8 +258,7 @@ class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISugges
|
||||||
*/
|
*/
|
||||||
public function SetLogger($oLogger)
|
public function SetLogger($oLogger)
|
||||||
{
|
{
|
||||||
if ($oLogger instanceof \MailSo\Log\Logger)
|
if ($oLogger instanceof \MailSo\Log\Logger) {
|
||||||
{
|
|
||||||
$this->oLogger = $oLogger;
|
$this->oLogger = $oLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ class LdapContactsSuggestionsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
{
|
{
|
||||||
const
|
const
|
||||||
NAME = 'Contacts suggestions (LDAP)',
|
NAME = 'Contacts suggestions (LDAP)',
|
||||||
VERSION = '2.10',
|
VERSION = '2.11',
|
||||||
RELEASE = '2022-12-08',
|
RELEASE = '2023-01-27',
|
||||||
REQUIRED = '2.23.0',
|
REQUIRED = '2.23.0',
|
||||||
CATEGORY = 'Contacts',
|
CATEGORY = 'Contacts',
|
||||||
DESCRIPTION = 'Get contacts suggestions from LDAP.';
|
DESCRIPTION = 'Get contacts suggestions from LDAP.';
|
||||||
|
|
@ -15,9 +15,6 @@ class LdapContactsSuggestionsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$this->addHook('main.fabrica', 'MainFabrica');
|
$this->addHook('main.fabrica', 'MainFabrica');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function Supported() : string
|
public function Supported() : string
|
||||||
{
|
{
|
||||||
if (!\function_exists('ldap_connect'))
|
if (!\function_exists('ldap_connect'))
|
||||||
|
|
@ -34,43 +31,38 @@ class LdapContactsSuggestionsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
*/
|
*/
|
||||||
public function MainFabrica($sName, &$mResult)
|
public function MainFabrica($sName, &$mResult)
|
||||||
{
|
{
|
||||||
switch ($sName)
|
if ('suggestions' == $sName) {
|
||||||
{
|
if (!\is_array($mResult)) {
|
||||||
case 'suggestions':
|
|
||||||
|
|
||||||
if (!\is_array($mResult))
|
|
||||||
{
|
|
||||||
$mResult = array();
|
$mResult = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
$sLdapUri = \trim($this->Config()->Get('plugin', 'ldap_uri', ''));
|
$sLdapUri = \trim($this->Config()->Get('plugin', 'ldap_uri', ''));
|
||||||
$bUseStartTLS = (bool) $this->Config()->Get('plugin', 'use_start_tls', True);
|
|
||||||
$sBindDn = \trim($this->Config()->Get('plugin', 'bind_dn', ''));
|
|
||||||
$sBindPassword = \trim($this->Config()->Get('plugin', 'bind_password', ''));
|
|
||||||
$sBaseDn = \trim($this->Config()->Get('plugin', 'base_dn', ''));
|
$sBaseDn = \trim($this->Config()->Get('plugin', 'base_dn', ''));
|
||||||
$sObjectClasses = \trim($this->Config()->Get('plugin', 'object_classes', ''));
|
$sObjectClasses = \trim($this->Config()->Get('plugin', 'object_classes', ''));
|
||||||
$sUidAttributes = \trim($this->Config()->Get('plugin', 'uid_attributes', ''));
|
|
||||||
$sNameAttributes = \trim($this->Config()->Get('plugin', 'name_attributes', ''));
|
|
||||||
$sEmailAttributes = \trim($this->Config()->Get('plugin', 'mail_attributes', ''));
|
$sEmailAttributes = \trim($this->Config()->Get('plugin', 'mail_attributes', ''));
|
||||||
$sAllowedEmails = \trim($this->Config()->Get('plugin', 'allowed_emails', ''));
|
|
||||||
|
|
||||||
if (0 < \strlen($sLdapUri) && 0 < \strlen($sBaseDn) && 0 < \strlen($sObjectClasses) && 0 < \strlen($sEmailAttributes))
|
if (\strlen($sLdapUri) && \strlen($sBaseDn) && \strlen($sObjectClasses) && \strlen($sEmailAttributes)) {
|
||||||
{
|
require_once __DIR__.'/LdapContactsSuggestions.php';
|
||||||
include_once __DIR__.'/LdapContactsSuggestions.php';
|
|
||||||
|
|
||||||
$oProvider = new LdapContactsSuggestions();
|
$oProvider = new LdapContactsSuggestions();
|
||||||
$oProvider->SetConfig($sLdapUri, $bUseStartTLS, $sBindDn, $sBindPassword, $sBaseDn, $sObjectClasses, $sUidAttributes, $sNameAttributes, $sEmailAttributes, $sAllowedEmails);
|
$oProvider->SetConfig(
|
||||||
|
$sLdapUri,
|
||||||
|
(bool) $this->Config()->Get('plugin', 'use_start_tls', true),
|
||||||
|
\trim($this->Config()->Get('plugin', 'bind_dn', '')),
|
||||||
|
\trim($this->Config()->Get('plugin', 'bind_password', '')),
|
||||||
|
$sBaseDn,
|
||||||
|
$sObjectClasses,
|
||||||
|
\trim($this->Config()->Get('plugin', 'uid_attributes', '')),
|
||||||
|
\trim($this->Config()->Get('plugin', 'name_attributes', '')),
|
||||||
|
$sEmailAttributes,
|
||||||
|
\trim($this->Config()->Get('plugin', 'allowed_emails', ''))
|
||||||
|
);
|
||||||
|
|
||||||
$mResult[] = $oProvider;
|
$mResult[] = $oProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function configMapping() : array
|
protected function configMapping() : array
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue