Merge remote-tracking branch 'remotes/origin/feature/perf-serialization' into develop

This commit is contained in:
odain
2020-08-10 11:10:44 +02:00
2 changed files with 260 additions and 35 deletions

View File

@@ -126,6 +126,13 @@ abstract class MetaModel
/** @var string */
protected static $m_sEnvironment = 'production';
/**
* MetaModel constructor.
*/
public function __construct()
{
}
/**
* @return array
*/
@@ -2757,7 +2764,7 @@ abstract class MetaModel
$aInterfaces = array('iApplicationUIExtension', 'iPreferencesExtension', 'iApplicationObjectExtension', 'iLoginFSMExtension', 'iLoginUIExtension', 'iLogoutExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension', 'iPageUIExtension', 'iPortalUIExtension', 'ModuleHandlerApiInterface', 'iNewsroomProvider', 'iModuleExtension');
foreach($aInterfaces as $sInterface)
{
self::$m_aExtensionClasses[$sInterface] = array();
self::$m_aExtensionClassNames[$sInterface] = array();
}
foreach(get_declared_classes() as $sPHPClass)
@@ -2768,11 +2775,7 @@ abstract class MetaModel
{
if ($oRefClass->implementsInterface($sInterface) && $oRefClass->isInstantiable())
{
if (is_null($oExtensionInstance))
{
$oExtensionInstance = new $sPHPClass;
}
self::$m_aExtensionClasses[$sInterface][$sPHPClass] = $oExtensionInstance;
self::$m_aExtensionClassNames[$sInterface][$sPHPClass] = $sPHPClass;
}
}
}
@@ -6357,7 +6360,7 @@ abstract class MetaModel
if (is_array($result))
{
// todo - verifier que toutes les classes mentionnees ici sont chargees dans InitClasses()
self::$m_aExtensionClasses = $result['m_aExtensionClasses'];
self::$m_aExtensionClassNames = $result['m_aExtensionClassNames'];
self::$m_Category2Class = $result['m_Category2Class'];
self::$m_aRootClasses = $result['m_aRootClasses'];
self::$m_aParentClasses = $result['m_aParentClasses'];
@@ -6394,7 +6397,7 @@ abstract class MetaModel
$oKPI = new ExecutionKPI();
$aCache = array();
$aCache['m_aExtensionClasses'] = self::$m_aExtensionClasses;
$aCache['m_aExtensionClassNames'] = self::$m_aExtensionClassNames;
$aCache['m_Category2Class'] = self::$m_Category2Class;
$aCache['m_aRootClasses'] = self::$m_aRootClasses; // array of "classname" => "rootclass"
$aCache['m_aParentClasses'] = self::$m_aParentClasses; // array of ("classname" => array of "parentclass")
@@ -6480,6 +6483,8 @@ abstract class MetaModel
/** @var array */
protected static $m_aExtensionClasses = array();
/** @var array */
protected static $m_aExtensionClassNames = array();
/**
* @param string $sToInclude
@@ -7274,25 +7279,9 @@ abstract class MetaModel
*/
public static function EnumPlugins($sInterface, $sFilterInstanceOf = null)
{
if (!array_key_exists($sInterface, self::$m_aExtensionClasses))
{
return array();
}
$pluginManager = new PluginManager(self::$m_aExtensionClassNames, self::$m_aExtensionClasses);
if (is_null($sFilterInstanceOf))
{
return self::$m_aExtensionClasses[$sInterface];
}
$fFilterCallback = function ($instance) use ($sFilterInstanceOf)
{
return $instance instanceof $sFilterInstanceOf;
};
return array_filter(
self::$m_aExtensionClasses[$sInterface],
$fFilterCallback
);
return $pluginManager->EnumPlugins($sInterface, $sFilterInstanceOf);
}
/**
@@ -7303,16 +7292,9 @@ abstract class MetaModel
*/
public static function GetPlugins($sInterface, $sClassName)
{
$oInstance = null;
if (array_key_exists($sInterface, self::$m_aExtensionClasses))
{
if (array_key_exists($sClassName, self::$m_aExtensionClasses[$sInterface]))
{
return self::$m_aExtensionClasses[$sInterface][$sClassName];
}
}
$pluginManager = new PluginManager(self::$m_aExtensionClassNames, self::$m_aExtensionClasses);
return $oInstance;
return $pluginManager->GetPlugins($sInterface, $sClassName);
}
/**
@@ -7462,6 +7444,119 @@ abstract class MetaModel
}
}
class PluginManager
{
private $m_aExtensionClassNames;
private $m_aExtensionClasses;
private $m_pluginInstantiationManager ;
public function __construct($m_aExtensionClassNames, $m_aExtensionClasses, $m_pluginInstanciationManager=null)
{
$this->m_aExtensionClasses = $m_aExtensionClasses;
$this->m_aExtensionClassNames = $m_aExtensionClassNames;
if ($m_pluginInstanciationManager==null)
{
$this->m_pluginInstantiationManager = new PluginInstanciationManager();
}
else
{
$this->m_pluginInstantiationManager = $m_pluginInstanciationManager;
}
}
/**
* @param string $sInterface
* @param bool $bCanInstantiatePlugins internal use, let this value to true
* @param string|null $sFilterInstanceOf [optional] if given, only instance of this string will be returned
* @return array classes=>instance implementing the given interface
*/
public function EnumPlugins($sInterface, $sFilterInstanceOf = null, $bCanInstantiatePlugins = true)
{
$aPlugins = array();
if (array_key_exists($sInterface, $this->m_aExtensionClasses))
{
$aAllPlugins = array_values($this->m_aExtensionClasses[$sInterface]);
if (is_null($sFilterInstanceOf))
{
return $aAllPlugins;
};
$aPlugins = array();
foreach ($aAllPlugins as $instance)
{
if ($instance instanceof $sFilterInstanceOf)
{
$aPlugins[] = $instance;
}
}
}
else if ($bCanInstantiatePlugins && array_key_exists($sInterface, $this->m_aExtensionClassNames))
{
$this->InstantiatePlugins($sInterface);
return $this->EnumPlugins($sInterface, $sFilterInstanceOf, false);
}
return $aPlugins;
}
public function InstantiatePlugins($sInterface)
{
$this->m_aExtensionClasses[$sInterface] = $this->m_pluginInstantiationManager->InstantiatePlugins($this->m_aExtensionClassNames, $sInterface);
}
/**
* @param string $sInterface
* @param string $sClassName
* @param bool $bCanInstantiatePlugins internal use, let this value to true
*
* @return mixed the instance of the specified plug-ins for the given interface
*/
public function GetPlugins($sInterface, $sClassName, $bCanInstantiatePlugins = true)
{
$oInstance = null;
if (array_key_exists($sInterface, $this->m_aExtensionClasses))
{
if (array_key_exists($sClassName, $this->m_aExtensionClasses[$sInterface]))
{
return $this->m_aExtensionClasses[$sInterface][$sClassName];
}
}
else if ($bCanInstantiatePlugins && array_key_exists($sInterface, $this->m_aExtensionClassNames))
{
$this->InstantiatePlugins($sInterface);
return $this->GetPlugins($sInterface, $sClassName, false);
}
return $oInstance;
}
} //PluginManager class
class PluginInstanciationManager
{
public function InstantiatePlugins($m_aExtensionClassNames, $sInterface)
{
$newPerInstanceClasses = array();
if (array_key_exists($sInterface, $m_aExtensionClassNames))
{
foreach ($m_aExtensionClassNames[$sInterface] as $sClassName)
{
if (class_exists($sClassName))
{
$class = new ReflectionClass($sClassName);
if ($class->isInstantiable())
{
$newPerInstanceClasses[$sClassName] = new $sClassName();
}
}
}
}
return $newPerInstanceClasses;
}
}
// Standard attribute lists
MetaModel::RegisterZList("noneditable", array("description" => "non editable fields", "type" => "attributes"));

View File

@@ -179,4 +179,134 @@ class MetaModelTest extends ItopDataTestCase
}
}
/**
* @dataProvider enumPluginsProvider
*
* @param $expectedResults
* @param $m_aExtensionClassNames
* @param $m_aExtensionClasses
* @param $interface
* @param null $sFilterInstanceOf
*/
public function testEnumPlugins($expectedInstanciationCalls, $expectedResults, $m_aExtensionClassNames, $m_aExtensionClasses, $interface, $sFilterInstanceOf=null)
{
$pluginInstanciationManager = new \PluginInstanciationManager();
$res = $pluginInstanciationManager->InstantiatePlugins($m_aExtensionClassNames, $interface);
$mPluginInstanciationManager = $this->createMock(\PluginInstanciationManager::class);
$mPluginInstanciationManager->expects($this->exactly($expectedInstanciationCalls))
->method('InstantiatePlugins')
->willReturn($res);
$m_PluginManager = new \PluginManager($m_aExtensionClassNames, $m_aExtensionClasses, $mPluginInstanciationManager);
//warning: called twice on purpose
$m_PluginManager->EnumPlugins($interface, $sFilterInstanceOf);
$pluginInstances = $m_PluginManager->EnumPlugins($interface, $sFilterInstanceOf);
$this->assertCount(sizeof($expectedResults), $pluginInstances);
foreach($pluginInstances as $pluginInstance)
{
if ($sFilterInstanceOf!==null)
{
$this->assertTrue($pluginInstance instanceof $sFilterInstanceOf);
}
}
$index=0;
foreach($expectedResults as $expectedInterface)
{
$this->assertTrue(is_a($pluginInstances[$index], $expectedInterface));
$index++;
}
}
public function enumPluginsProvider(){
$aInterfaces = [
"empty conf" => [ 0, [], [], [], 'Wizzard'],
"simple instance retrieval" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class]], [], 'Wizzard'],
"check instanceof parameter" => [ 1, [Gryffindor::class, Slytherin::class], [ 'Wizzard' => [ Gryffindor::class, Slytherin::class]], [], 'Wizzard'],
"try to retrieve a non instanciable object" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class, Muggle::class]], [], 'Wizzard', Gryffindor::class ],
];
return $aInterfaces;
}
/**
* @dataProvider getPluginsProvider
*
* @param $expectedInstanciationCalls
* @param $expectedResults
* @param $m_aExtensionClassNames
* @param $m_aExtensionClasses
* @param $interface
* @param $className
*/
public function testGetPlugins($expectedInstanciationCalls, $expectedResults, $m_aExtensionClassNames, $m_aExtensionClasses, $interface, $className)
{
$pluginInstanciationManager = new \PluginInstanciationManager();
$res = $pluginInstanciationManager->InstantiatePlugins($m_aExtensionClassNames, $interface);
$mPluginInstanciationManager = $this->createMock(\PluginInstanciationManager::class);
$mPluginInstanciationManager->expects($this->exactly($expectedInstanciationCalls))
->method('InstantiatePlugins')
->willReturn($res);
$m_PluginManager = new \PluginManager($m_aExtensionClassNames, $m_aExtensionClasses, $mPluginInstanciationManager);
//warning: called twice on purpose
$m_PluginManager->GetPlugins($interface, $className);
$pluginInstance = $m_PluginManager->GetPlugins($interface, $className);
if (sizeof($expectedResults)==0)
{
$this->assertNull($pluginInstance);
return;
}
$this->assertTrue($pluginInstance instanceof $className);
$this->assertTrue(is_a($pluginInstance, $expectedResults[0]));
}
public function getPluginsProvider(){
$aInterfaces = [
"empty conf" => [ 0, [], [], [], 'Wizzard', Gryffindor::class],
"simple instance retrieval" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class]], [], 'Wizzard', Gryffindor::class],
"check instanceof parameter" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class, Slytherin::class]], [], 'Wizzard', Gryffindor::class],
"try to retrieve a non instanciable object" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class, Muggle::class]], [], 'Wizzard', Gryffindor::class ],
];
return $aInterfaces;
}
}
abstract class Wizzard
{
/**
* Wizzard constructor.
*/
public function __construct()
{
}
}
class Gryffindor extends Wizzard
{
}
class Hufflepuff extends Wizzard
{
}
class Ravenclaw extends Wizzard
{
}
class Slytherin extends Wizzard
{
}
class Muggle
{
}