From 1116653123f7a7099ba1c057ee34d8713701e490 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Thu, 21 Oct 2021 16:10:21 +0200 Subject: [PATCH 01/28] Remove deprecated on future feature... --- htdocs/core/db/DoliDB.class.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index 29ced10dc3518..9b299c7dc76e1 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -321,7 +321,6 @@ public function lastqueryerror() * Dont add LIMIT to your query, it will be added by this method * @param string $sql the sql query string * @return bool| object - * @deprecated */ public function getRow($sql) { @@ -341,7 +340,6 @@ public function getRow($sql) * be carefull with this method use it only with some limit of results to avoid performences loss * @param string $sql the sql query string * @return bool| array - * @deprecated */ public function getRows($sql) { From f10c6446e7d5dfd782de0ddf810b3aa55b1d6942 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Wed, 3 Aug 2022 11:59:06 +0200 Subject: [PATCH 02/28] free db --- htdocs/core/db/DoliDB.class.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index 9b299c7dc76e1..201a258a20ac7 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -351,6 +351,8 @@ public function getRows($sql) $results[] = $obj; } } + + $this->free($res); return $results; } From d34427ffd644a0aea0b40b0217c0429c353bc82c Mon Sep 17 00:00:00 2001 From: ATM john Date: Fri, 5 Aug 2022 18:36:13 +0200 Subject: [PATCH 03/28] Factoring fetch object from element --- htdocs/core/class/commonobject.class.php | 381 +++++++++++++++++------ 1 file changed, 282 insertions(+), 99 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 3c24b3c484fd9..817c05b230eb4 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3820,11 +3820,9 @@ public function add_object_linked($origin = null, $origin_id = null, $f_user = n $origin = 'order_supplier'; } - // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. - // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. - $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization', 'asset'); - // Add module part to target type if object has $module property and isn't in core modules. - $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; + + // Add module part to target type + $targettype = $this->getElementType(); $parameters = array('targettype'=>$targettype); // Hook for explicitly set the targettype if it must be differtent than $this->element @@ -3874,6 +3872,277 @@ public function add_object_linked($origin = null, $origin_id = null, $f_user = n } } + /** + * return element type string formated like element_element target_type and target_type + * @return string + */ + public function getElementType() + { + // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. + // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. + $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization', 'asset'); + // Add module part to target type if object has $module property and isn't in core modules. + return ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; + } + + + /** + * Create a new object instance based on the element type + * Fetch the object if id is provided + * Usage : to easily fetch element form element_element with cache + * + * @param DoliDB $db the DoliDB + * @param string $elementType Type of object ('invoice', 'order', 'expedition_bon', 'myobject@mymodule', ...) + * @param bool $elementId Id of element to provide if fetch is needed + * @param int $maxCacheByType max number of cached element by type + * @return CommonObject object of $elementType, fetched by $elementId + * @throws Exception + */ + public static function getObjectByElementType($db, $elementType, $elementId = false, $maxCacheByType = 10) + { + global $conf; + + $data = self::extractElementTypeInfosFromString($elementType); + + $module = $data->module; + $className = $data->className; + + if (!empty($conf->$module->enabled)) { + dol_syslog('Module not enabled', LOG_INFO); + return false; + } + + $fileToInclude = '/'.$data->classPath.'/'.$data->classFile.'.class.php'; + $res = dol_include_once($fileToInclude); + if (!$res) { + dol_syslog('class file not found : '.$fileToInclude, LOG_WARNING); + return false; + } + + if (!class_exists($className)) { + dol_syslog('class not found : '.$className, LOG_WARNING); + return false; + } + + if ($elementId === false) { + return new $className($db); + } else { + return self::getObjectFromCache($db, $className, $elementId, $maxCacheByType); + } + } + + /** + * return + * + * @param string $elementType formated like seft::getElementType + * @return stdClass + * { + * module, + * myObject, + * classpath, + * classfile, + * classname + * } + */ + public static function extractElementTypeInfosFromString($elementType) + { + + $data = new stdClass(); + + $regs = array(); + + // Parse $objecttype (ex: project_task) + $data->module = $data->element = $elementType; + + // If we ask an resource form external module (instead of default path) + if (preg_match('/^([^@]+)@([^@]+)$/i', $elementType, $regs)) { + $data->element = $regs[1]; + $data->module = $regs[2]; + } + + // If we ask an resource form external module (instead of default path) + if (preg_match('/^([^_]+)_([^_]+)/i', $elementType, $regs)) { + $data->module = $regs[1]; + $data->element = $regs[2]; + } + + // Generic case for $data->classPath + $data->classPath = $data->module.'/class'; + + // Special cases, to work with non standard path + if ($elementType == 'facture' || $elementType == 'invoice') { + $data->classPath = 'compta/facture/class'; + $data->module='facture'; + $data->element='facture'; + } elseif ($elementType == 'commande' || $elementType == 'order') { + $data->classPath = 'commande/class'; + $data->module='commande'; + $data->element='commande'; + } elseif ($elementType == 'contact') { + $data->module = 'societe'; + } elseif ($elementType == 'propal') { + $data->classPath = 'comm/propal/class'; + } elseif ($elementType == 'shipping') { + $data->classPath = 'expedition/class'; + $data->element = 'expedition'; + $data->module = 'expedition'; + } elseif ($elementType == 'delivery') { + $data->classPath = 'delivery/class'; + $data->element = 'delivery'; + $data->module = 'expedition'; + } elseif ($elementType == 'contract') { + $data->classPath = 'contrat/class'; + $data->module='contrat'; + $data->element='contrat'; + } elseif ($elementType == 'member') { + $data->classPath = 'adherents/class'; + $data->module='adherent'; + $data->element='adherent'; + } elseif ($elementType == 'cabinetmed_cons') { + $data->classPath = 'cabinetmed/class'; + $data->module='cabinetmed'; + $data->element='cabinetmedcons'; + } elseif ($elementType == 'fichinter') { + $data->classPath = 'fichinter/class'; + $data->module='ficheinter'; + $data->element='fichinter'; + } elseif ($elementType == 'task') { + $data->classPath = 'projet/class'; + $data->module='projet'; + $data->element='task'; + } elseif ($elementType == 'stock') { + $data->classPath = 'product/stock/class'; + $data->module='stock'; + $data->element='stock'; + } elseif ($elementType == 'inventory') { + $data->classPath = 'product/inventory/class'; + $data->module='stock'; + $data->element='inventory'; + } elseif ($elementType == 'mo') { + $data->classPath = 'mrp/class'; + $data->module='mrp'; + $data->element='mo'; + } elseif ($elementType == 'salary') { + $data->classPath = 'salaries/class'; + $data->module='salaries'; + } elseif ($elementType == 'chargesociales') { + $data->classPath = 'compta/sociales/class'; + $data->module='tax'; + } elseif ($elementType == 'tva') { + $data->classPath = 'compta/tva/class'; + $data->module='tax'; + } elseif ($elementType == 'widthdraw') { + $data->classPath = 'compta/prelevement/class'; + $data->module='prelevement'; + $data->element='bonprelevement'; + } elseif ($elementType == 'project') { + $data->classPath = 'projet/class'; + $data->module='projet'; + } elseif ($elementType == 'project_task') { + $data->classPath = 'projet/class'; + $data->module='projet'; + } elseif ($elementType == 'action') { + $data->classPath = 'comm/action/class'; + $data->module='agenda'; + $data->element = 'ActionComm'; + } elseif ($elementType == 'mailing') { + $data->classPath = 'comm/mailing/class'; + } elseif ($elementType == 'knowledgerecord') { + $data->classPath = 'knowledgemanagement/class'; + $data->module='knowledgemanagement'; + } elseif ($elementType == 'recruitmentjobposition') { + $data->classPath = 'recruitment/class'; + $data->module='recruitment'; + } elseif ($elementType == 'recruitmentcandidature') { + $data->classPath = 'recruitment/class'; + $data->module='recruitment'; + } + + // Generic case for $data->classFile and $data->className + $data->classFile = strtolower($data->element); $data->className = ucfirst($data->element); + + if ($elementType == 'invoice_supplier') { + $data->classFile = 'fournisseur.facture'; + $data->className = 'FactureFournisseur'; + $data->classPath = 'fourn/class'; + $data->module = 'fournisseur'; + } elseif ($elementType == 'order_supplier') { + $data->classFile = 'fournisseur.commande'; + $data->className = 'CommandeFournisseur'; + $data->classPath = 'fourn/class'; + $data->module = 'fournisseur'; + } elseif ($elementType == 'supplier_proposal') { + $data->classFile = 'supplier_proposal'; + $data->className = 'SupplierProposal'; + $data->classPath = 'supplier_proposal/class'; + $data->module = 'supplier_proposal'; + } elseif ($elementType == 'stock') { + $data->classPath = 'product/stock/class'; + $data->classFile = 'entrepot'; + $data->className = 'Entrepot'; + } elseif ($elementType == 'dolresource') { + $data->classPath = 'resource/class'; + $data->classFile = 'dolresource'; + $data->className = 'Dolresource'; + $data->module = 'resource'; + } elseif ($elementType == 'payment_various') { + $data->classPath = 'compta/bank/class'; + $data->module='tax'; + $data->classFile = 'paymentvarious'; + $data->className = 'PaymentVarious'; + } elseif ($elementType == 'bank_account') { + $data->classPath = 'compta/bank/class'; + $data->module='banque'; + $data->classFile = 'account'; + $data->className = 'Account'; + } elseif ($elementType == 'adherent_type') { + $data->classPath = 'adherents/class'; + $data->module = 'member'; + $data->classFile='adherent_type'; + $data->className='AdherentType'; + } + + // TODO : Add hook here but need to add cache for results if there is a hook (hook could add perfomence loss) + // OR store special elements in database in table like element_type and fetch it Once + + return $data; + } + + + /** + * return an object stored in memory cache + * + * @param DoliDB $db the DoliDB + * @param string $objetClassName object cs name + * @param int $objectId object Id + * @param int $maxCacheByType max number of storable object fore each type + * @return bool|CommonObject + */ + public static function getObjectFromCache($db, $objetClassName, $objectId, $maxCacheByType = 10) + { + global $globalCacheForCommonObjectGetObjectFromCache; + + if (!class_exists($objetClassName)) { + return false; + } + + if (empty($globalCacheForCommonObjectGetObjectFromCache[$objetClassName][$objectId])) { + $object = new $objetClassName($db); + if ($object->fetch($objectId, false) <= 0) { + return false; + } + + if (is_array($globalCacheForCommonObjectGetObjectFromCache[$objetClassName]) && count($globalCacheForCommonObjectGetObjectFromCache[$objetClassName]) >= $maxCacheByType) { + array_shift($globalCacheForCommonObjectGetObjectFromCache[$objetClassName]); + } + + $globalCacheForCommonObjectGetObjectFromCache[$objetClassName][$objectId] = $object; + } else { + $object = $globalCacheForCommonObjectGetObjectFromCache[$objetClassName][$objectId]; + } + + return $object; + } /** * Fetch array of objects linked to current object (object of enabled modules only). Links are loaded into * this->linkedObjectsIds array + @@ -3999,103 +4268,17 @@ public function fetchObjectLinked($sourceid = null, $sourcetype = '', $targetid if (!empty($this->linkedObjectsIds)) { $tmparray = $this->linkedObjectsIds; - foreach ($tmparray as $objecttype => $objectids) { // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...) - // Parse element/subelement (ex: project_task, cabinetmed_consultation, ...) - $module = $element = $subelement = $objecttype; - $regs = array(); - if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier' - && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) { - $module = $element = $regs[1]; - $subelement = $regs[2]; - } - - $classpath = $element.'/class'; - // To work with non standard classpath or module name - if ($objecttype == 'facture') { - $classpath = 'compta/facture/class'; - } elseif ($objecttype == 'facturerec') { - $classpath = 'compta/facture/class'; - $module = 'facture'; - } elseif ($objecttype == 'propal') { - $classpath = 'comm/propal/class'; - } elseif ($objecttype == 'supplier_proposal') { - $classpath = 'supplier_proposal/class'; - } elseif ($objecttype == 'shipping') { - $classpath = 'expedition/class'; - $subelement = 'expedition'; - $module = 'expedition_bon'; - } elseif ($objecttype == 'delivery') { - $classpath = 'delivery/class'; - $subelement = 'delivery'; - $module = 'delivery_note'; - } elseif ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier') { - $classpath = 'fourn/class'; - $module = 'fournisseur'; - } elseif ($objecttype == 'fichinter') { - $classpath = 'fichinter/class'; - $subelement = 'fichinter'; - $module = 'ficheinter'; - } elseif ($objecttype == 'subscription') { - $classpath = 'adherents/class'; - $module = 'adherent'; - } elseif ($objecttype == 'contact') { - $module = 'societe'; - } - // Set classfile - $classfile = strtolower($subelement); - $classname = ucfirst($subelement); - - if ($objecttype == 'order') { - $classfile = 'commande'; - $classname = 'Commande'; - } elseif ($objecttype == 'invoice_supplier') { - $classfile = 'fournisseur.facture'; - $classname = 'FactureFournisseur'; - } elseif ($objecttype == 'order_supplier') { - $classfile = 'fournisseur.commande'; - $classname = 'CommandeFournisseur'; - } elseif ($objecttype == 'supplier_proposal') { - $classfile = 'supplier_proposal'; - $classname = 'SupplierProposal'; - } elseif ($objecttype == 'facturerec') { - $classfile = 'facture-rec'; - $classname = 'FactureRec'; - } elseif ($objecttype == 'subscription') { - $classfile = 'subscription'; - $classname = 'Subscription'; - } elseif ($objecttype == 'project' || $objecttype == 'projet') { - $classpath = 'projet/class'; - $classfile = 'project'; - $classname = 'Project'; - } elseif ($objecttype == 'conferenceorboothattendee') { - $classpath = 'eventorganization/class'; - $classfile = 'conferenceorboothattendee'; - $classname = 'ConferenceOrBoothAttendee'; - $module = 'eventorganization'; - } elseif ($objecttype == 'conferenceorbooth') { - $classpath = 'eventorganization/class'; - $classfile = 'conferenceorbooth'; - $classname = 'ConferenceOrBooth'; - $module = 'eventorganization'; - } elseif ($objecttype == 'mo') { - $classpath = 'mrp/class'; - $classfile = 'mo'; - $classname = 'Mo'; - $module = 'mrp'; - } + foreach ($tmparray as $objecttype => $objectIds) { // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...) + $data = self::extractElementTypeInfosFromString($objecttype); + $module = $data->module; // Here $module, $classfile and $classname are set, we can use them. - if ($conf->$module->enabled && (($element != $this->element) || $alsosametype)) { + if ($conf->$module->enabled && (($data->element != $this->element) || $alsosametype)) { if ($loadalsoobjects && (is_numeric($loadalsoobjects) || ($loadalsoobjects === $objecttype))) { - dol_include_once('/'.$classpath.'/'.$classfile.'.class.php'); - //print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname); - if (class_exists($classname)) { - foreach ($objectids as $i => $objectid) { // $i is rowid into llx_element_element - $object = new $classname($this->db); - $ret = $object->fetch($objectid); - if ($ret >= 0) { - $this->linkedObjects[$objecttype][$i] = $object; - } + foreach ($objectIds as $i => $objectId) { // $i is rowid into llx_element_element + $object = self::getObjectByElementType($this->db, $objecttype, $objectId); + if ($object) { + $this->linkedObjects[$objecttype][$i] = $object; } } } From 4d3e89643c4744788fc42781473439ddb4c6901e Mon Sep 17 00:00:00 2001 From: ATM john Date: Fri, 5 Aug 2022 18:45:51 +0200 Subject: [PATCH 04/28] Fix mysql element element size for module builder --- htdocs/core/class/commonobject.class.php | 14 +++++++------- htdocs/install/mysql/migration/16.0.0-17.0.0.sql | 3 +++ .../install/mysql/tables/llx_element_element.sql | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 817c05b230eb4..39308f5a32737 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -4102,7 +4102,7 @@ public static function extractElementTypeInfosFromString($elementType) $data->className='AdherentType'; } - // TODO : Add hook here but need to add cache for results if there is a hook (hook could add perfomence loss) + // TODO : Add hook here but need to add cache for results if there is a hook (hook could add performance loss) // OR store special elements in database in table like element_type and fetch it Once return $data; @@ -4268,22 +4268,22 @@ public function fetchObjectLinked($sourceid = null, $sourcetype = '', $targetid if (!empty($this->linkedObjectsIds)) { $tmparray = $this->linkedObjectsIds; - foreach ($tmparray as $objecttype => $objectIds) { // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...) - $data = self::extractElementTypeInfosFromString($objecttype); + foreach ($tmparray as $objectType => $objectIds) { // $objectType is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...) + $data = self::extractElementTypeInfosFromString($objectType); $module = $data->module; // Here $module, $classfile and $classname are set, we can use them. if ($conf->$module->enabled && (($data->element != $this->element) || $alsosametype)) { - if ($loadalsoobjects && (is_numeric($loadalsoobjects) || ($loadalsoobjects === $objecttype))) { + if ($loadalsoobjects && (is_numeric($loadalsoobjects) || ($loadalsoobjects === $objectType))) { foreach ($objectIds as $i => $objectId) { // $i is rowid into llx_element_element - $object = self::getObjectByElementType($this->db, $objecttype, $objectId); + $object = self::getObjectByElementType($this->db, $objectType, $objectId); if ($object) { - $this->linkedObjects[$objecttype][$i] = $object; + $this->linkedObjects[$objectType][$i] = $object; } } } } else { - unset($this->linkedObjectsIds[$objecttype]); + unset($this->linkedObjectsIds[$objectType]); } } } diff --git a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql index e72fc1b8dcd89..2149aa44ce3b3 100644 --- a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql +++ b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql @@ -77,3 +77,6 @@ ALTER TABLE llx_recruitment_recruitmentcandidature ADD email_date datetime after ALTER TABLE llx_ticket ADD email_date datetime after email_msgid; INSERT INTO llx_const (name, entity, value, type, visible) VALUES ('MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT', 1, 1000, 'int', 0); + +ALTER TABLE llx_element_element CHANGE sourcetype sourcetype VARCHAR(64) NOT NULL; +ALTER TABLE llx_element_element CHANGE targettype targettype VARCHAR(64) NOT NULL; diff --git a/htdocs/install/mysql/tables/llx_element_element.sql b/htdocs/install/mysql/tables/llx_element_element.sql index 4c4567d89b271..25cc3e90a259b 100644 --- a/htdocs/install/mysql/tables/llx_element_element.sql +++ b/htdocs/install/mysql/tables/llx_element_element.sql @@ -24,8 +24,8 @@ create table llx_element_element ( rowid integer AUTO_INCREMENT PRIMARY KEY, fk_source integer NOT NULL, - sourcetype varchar(32) NOT NULL, + sourcetype varchar(64) NOT NULL, fk_target integer NOT NULL, - targettype varchar(32) NOT NULL + targettype varchar(64) NOT NULL ) ENGINE=innodb; From 89a154c8d6208cc0e38d42aa30143c026321e189 Mon Sep 17 00:00:00 2001 From: ATM john Date: Fri, 5 Aug 2022 18:56:17 +0200 Subject: [PATCH 05/28] Doc --- htdocs/core/class/commonobject.class.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 39308f5a32737..98c6fd9430ebd 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3934,14 +3934,14 @@ public static function getObjectByElementType($db, $elementType, $elementId = fa /** * return * - * @param string $elementType formated like seft::getElementType + * @param string $elementType formatted like seft::getElementType * @return stdClass * { * module, - * myObject, - * classpath, - * classfile, - * classname + * element, + * classPath, + * classFile, + * className * } */ public static function extractElementTypeInfosFromString($elementType) From 567b3ff445df1e18b7fadd01266444969fe33cbd Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Sat, 6 Aug 2022 10:18:54 +0200 Subject: [PATCH 06/28] Update htdocs/core/class/commonobject.class.php --- htdocs/core/class/commonobject.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 98c6fd9430ebd..f26f2f7e9f8b1 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3873,7 +3873,7 @@ public function add_object_linked($origin = null, $origin_id = null, $f_user = n } /** - * return element type string formated like element_element target_type and target_type + * return element type string formated like element_element target_type and source_type * @return string */ public function getElementType() From e9a2243cb545a1f450f4fd314930ab1e6594a744 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Mon, 8 Aug 2022 10:14:05 +0200 Subject: [PATCH 07/28] Use already existing function --- htdocs/core/class/commonobject.class.php | 288 ++--------------------- htdocs/core/lib/functions.lib.php | 63 ++++- 2 files changed, 76 insertions(+), 275 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index f26f2f7e9f8b1..a7c33e75773de 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3885,264 +3885,6 @@ public function getElementType() return ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; } - - /** - * Create a new object instance based on the element type - * Fetch the object if id is provided - * Usage : to easily fetch element form element_element with cache - * - * @param DoliDB $db the DoliDB - * @param string $elementType Type of object ('invoice', 'order', 'expedition_bon', 'myobject@mymodule', ...) - * @param bool $elementId Id of element to provide if fetch is needed - * @param int $maxCacheByType max number of cached element by type - * @return CommonObject object of $elementType, fetched by $elementId - * @throws Exception - */ - public static function getObjectByElementType($db, $elementType, $elementId = false, $maxCacheByType = 10) - { - global $conf; - - $data = self::extractElementTypeInfosFromString($elementType); - - $module = $data->module; - $className = $data->className; - - if (!empty($conf->$module->enabled)) { - dol_syslog('Module not enabled', LOG_INFO); - return false; - } - - $fileToInclude = '/'.$data->classPath.'/'.$data->classFile.'.class.php'; - $res = dol_include_once($fileToInclude); - if (!$res) { - dol_syslog('class file not found : '.$fileToInclude, LOG_WARNING); - return false; - } - - if (!class_exists($className)) { - dol_syslog('class not found : '.$className, LOG_WARNING); - return false; - } - - if ($elementId === false) { - return new $className($db); - } else { - return self::getObjectFromCache($db, $className, $elementId, $maxCacheByType); - } - } - - /** - * return - * - * @param string $elementType formatted like seft::getElementType - * @return stdClass - * { - * module, - * element, - * classPath, - * classFile, - * className - * } - */ - public static function extractElementTypeInfosFromString($elementType) - { - - $data = new stdClass(); - - $regs = array(); - - // Parse $objecttype (ex: project_task) - $data->module = $data->element = $elementType; - - // If we ask an resource form external module (instead of default path) - if (preg_match('/^([^@]+)@([^@]+)$/i', $elementType, $regs)) { - $data->element = $regs[1]; - $data->module = $regs[2]; - } - - // If we ask an resource form external module (instead of default path) - if (preg_match('/^([^_]+)_([^_]+)/i', $elementType, $regs)) { - $data->module = $regs[1]; - $data->element = $regs[2]; - } - - // Generic case for $data->classPath - $data->classPath = $data->module.'/class'; - - // Special cases, to work with non standard path - if ($elementType == 'facture' || $elementType == 'invoice') { - $data->classPath = 'compta/facture/class'; - $data->module='facture'; - $data->element='facture'; - } elseif ($elementType == 'commande' || $elementType == 'order') { - $data->classPath = 'commande/class'; - $data->module='commande'; - $data->element='commande'; - } elseif ($elementType == 'contact') { - $data->module = 'societe'; - } elseif ($elementType == 'propal') { - $data->classPath = 'comm/propal/class'; - } elseif ($elementType == 'shipping') { - $data->classPath = 'expedition/class'; - $data->element = 'expedition'; - $data->module = 'expedition'; - } elseif ($elementType == 'delivery') { - $data->classPath = 'delivery/class'; - $data->element = 'delivery'; - $data->module = 'expedition'; - } elseif ($elementType == 'contract') { - $data->classPath = 'contrat/class'; - $data->module='contrat'; - $data->element='contrat'; - } elseif ($elementType == 'member') { - $data->classPath = 'adherents/class'; - $data->module='adherent'; - $data->element='adherent'; - } elseif ($elementType == 'cabinetmed_cons') { - $data->classPath = 'cabinetmed/class'; - $data->module='cabinetmed'; - $data->element='cabinetmedcons'; - } elseif ($elementType == 'fichinter') { - $data->classPath = 'fichinter/class'; - $data->module='ficheinter'; - $data->element='fichinter'; - } elseif ($elementType == 'task') { - $data->classPath = 'projet/class'; - $data->module='projet'; - $data->element='task'; - } elseif ($elementType == 'stock') { - $data->classPath = 'product/stock/class'; - $data->module='stock'; - $data->element='stock'; - } elseif ($elementType == 'inventory') { - $data->classPath = 'product/inventory/class'; - $data->module='stock'; - $data->element='inventory'; - } elseif ($elementType == 'mo') { - $data->classPath = 'mrp/class'; - $data->module='mrp'; - $data->element='mo'; - } elseif ($elementType == 'salary') { - $data->classPath = 'salaries/class'; - $data->module='salaries'; - } elseif ($elementType == 'chargesociales') { - $data->classPath = 'compta/sociales/class'; - $data->module='tax'; - } elseif ($elementType == 'tva') { - $data->classPath = 'compta/tva/class'; - $data->module='tax'; - } elseif ($elementType == 'widthdraw') { - $data->classPath = 'compta/prelevement/class'; - $data->module='prelevement'; - $data->element='bonprelevement'; - } elseif ($elementType == 'project') { - $data->classPath = 'projet/class'; - $data->module='projet'; - } elseif ($elementType == 'project_task') { - $data->classPath = 'projet/class'; - $data->module='projet'; - } elseif ($elementType == 'action') { - $data->classPath = 'comm/action/class'; - $data->module='agenda'; - $data->element = 'ActionComm'; - } elseif ($elementType == 'mailing') { - $data->classPath = 'comm/mailing/class'; - } elseif ($elementType == 'knowledgerecord') { - $data->classPath = 'knowledgemanagement/class'; - $data->module='knowledgemanagement'; - } elseif ($elementType == 'recruitmentjobposition') { - $data->classPath = 'recruitment/class'; - $data->module='recruitment'; - } elseif ($elementType == 'recruitmentcandidature') { - $data->classPath = 'recruitment/class'; - $data->module='recruitment'; - } - - // Generic case for $data->classFile and $data->className - $data->classFile = strtolower($data->element); $data->className = ucfirst($data->element); - - if ($elementType == 'invoice_supplier') { - $data->classFile = 'fournisseur.facture'; - $data->className = 'FactureFournisseur'; - $data->classPath = 'fourn/class'; - $data->module = 'fournisseur'; - } elseif ($elementType == 'order_supplier') { - $data->classFile = 'fournisseur.commande'; - $data->className = 'CommandeFournisseur'; - $data->classPath = 'fourn/class'; - $data->module = 'fournisseur'; - } elseif ($elementType == 'supplier_proposal') { - $data->classFile = 'supplier_proposal'; - $data->className = 'SupplierProposal'; - $data->classPath = 'supplier_proposal/class'; - $data->module = 'supplier_proposal'; - } elseif ($elementType == 'stock') { - $data->classPath = 'product/stock/class'; - $data->classFile = 'entrepot'; - $data->className = 'Entrepot'; - } elseif ($elementType == 'dolresource') { - $data->classPath = 'resource/class'; - $data->classFile = 'dolresource'; - $data->className = 'Dolresource'; - $data->module = 'resource'; - } elseif ($elementType == 'payment_various') { - $data->classPath = 'compta/bank/class'; - $data->module='tax'; - $data->classFile = 'paymentvarious'; - $data->className = 'PaymentVarious'; - } elseif ($elementType == 'bank_account') { - $data->classPath = 'compta/bank/class'; - $data->module='banque'; - $data->classFile = 'account'; - $data->className = 'Account'; - } elseif ($elementType == 'adherent_type') { - $data->classPath = 'adherents/class'; - $data->module = 'member'; - $data->classFile='adherent_type'; - $data->className='AdherentType'; - } - - // TODO : Add hook here but need to add cache for results if there is a hook (hook could add performance loss) - // OR store special elements in database in table like element_type and fetch it Once - - return $data; - } - - - /** - * return an object stored in memory cache - * - * @param DoliDB $db the DoliDB - * @param string $objetClassName object cs name - * @param int $objectId object Id - * @param int $maxCacheByType max number of storable object fore each type - * @return bool|CommonObject - */ - public static function getObjectFromCache($db, $objetClassName, $objectId, $maxCacheByType = 10) - { - global $globalCacheForCommonObjectGetObjectFromCache; - - if (!class_exists($objetClassName)) { - return false; - } - - if (empty($globalCacheForCommonObjectGetObjectFromCache[$objetClassName][$objectId])) { - $object = new $objetClassName($db); - if ($object->fetch($objectId, false) <= 0) { - return false; - } - - if (is_array($globalCacheForCommonObjectGetObjectFromCache[$objetClassName]) && count($globalCacheForCommonObjectGetObjectFromCache[$objetClassName]) >= $maxCacheByType) { - array_shift($globalCacheForCommonObjectGetObjectFromCache[$objetClassName]); - } - - $globalCacheForCommonObjectGetObjectFromCache[$objetClassName][$objectId] = $object; - } else { - $object = $globalCacheForCommonObjectGetObjectFromCache[$objetClassName][$objectId]; - } - - return $object; - } /** * Fetch array of objects linked to current object (object of enabled modules only). Links are loaded into * this->linkedObjectsIds array + @@ -4268,22 +4010,32 @@ public function fetchObjectLinked($sourceid = null, $sourcetype = '', $targetid if (!empty($this->linkedObjectsIds)) { $tmparray = $this->linkedObjectsIds; - foreach ($tmparray as $objectType => $objectIds) { // $objectType is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...) - $data = self::extractElementTypeInfosFromString($objectType); - $module = $data->module; + foreach ($tmparray as $objecttype => $objectids) { // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...) + $element_properties = getElementProperties($objecttype); + $element = $element_properties['element']; + $classpath = $element_properties['classpath']; + $classfile = $element_properties['classfile']; + $classname = $element_properties['classname']; + $module = $element_properties['module']; + // Here $module, $classfile and $classname are set, we can use them. - if ($conf->$module->enabled && (($data->element != $this->element) || $alsosametype)) { - if ($loadalsoobjects && (is_numeric($loadalsoobjects) || ($loadalsoobjects === $objectType))) { - foreach ($objectIds as $i => $objectId) { // $i is rowid into llx_element_element - $object = self::getObjectByElementType($this->db, $objectType, $objectId); - if ($object) { - $this->linkedObjects[$objectType][$i] = $object; + if ($conf->$module->enabled && (($element != $this->element) || $alsosametype)) { + if ($loadalsoobjects && (is_numeric($loadalsoobjects) || ($loadalsoobjects === $objecttype))) { + dol_include_once('/'.$classpath.'/'.$classfile.'.class.php'); + + if (class_exists($classname)) { + foreach ($objectids as $i => $objectid) { // $i is rowid into llx_element_element + $object = new $classname($this->db); + $ret = $object->fetch($objectid); + if ($ret >= 0) { + $this->linkedObjects[$objecttype][$i] = $object; + } } } } } else { - unset($this->linkedObjectsIds[$objectType]); + unset($this->linkedObjectsIds[$objecttype]); } } } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 90698c95f80dc..2e85800003334 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10808,6 +10808,11 @@ function getElementProperties($element_type) 'classfile' => $classfile, 'classname' => $classname ); + + // TODO : Add hook here but need to add cache for results if there is a hook (hook could add performance loss) + // OR **store special elements in database in table like element_type and fetch it Once** + + return $element_properties; } @@ -10815,12 +10820,14 @@ function getElementProperties($element_type) * Fetch an object from its id and element_type * Inclusion of classes is automatic * - * @param int $element_id Element id - * @param string $element_type Element type - * @param string $element_ref Element ref (Use this or element_id but not both) - * @return int|object object || 0 || -1 if error + * @param int $element_id Element id + * @param string $element_type Element type + * @param string $element_ref Element ref (Use this or element_id but not both) + * @param bool $useCache if you want to store object in cache + * @param int $maxCacheByType number of object in cache for this element type + * @return int|object object || 0 || -1 if error */ -function fetchObjectByElement($element_id, $element_type, $element_ref = '') +function fetchObjectByElement($element_id, $element_type, $element_ref = '', $useCache = false, $maxCacheByType = 10) { global $conf, $db; @@ -10828,8 +10835,13 @@ function fetchObjectByElement($element_id, $element_type, $element_ref = '') if (is_array($element_prop) && $conf->{$element_prop['module']}->enabled) { dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php'); - $objecttmp = new $element_prop['classname']($db); - $ret = $objecttmp->fetch($element_id, $element_ref); + if ($useCache) { + getObjectFromCache($element_prop['classname'], $element_id, $element_ref, $maxCacheByType); + } else { + $objecttmp = new $element_prop['classname']($db); + $ret = $objecttmp->fetch($element_id, $element_ref); + } + if ($ret >= 0) { return $objecttmp; } @@ -10837,6 +10849,43 @@ function fetchObjectByElement($element_id, $element_type, $element_ref = '') return 0; } + + +/** + * return an object stored in memory cache + * + * @param string $objetClassName object cs name + * @param int $objectId object Id + * @param string $objectRef object ref + * @param int $maxCacheByType max number of storable object fore each type + * @return bool|CommonObject + */ +function getObjectFromCache($objetClassName, $objectId, $objectRef = false, $maxCacheByType = 10) +{ + global $db,$globalCacheForGetObjectFromCache; + + if (!class_exists($objetClassName)) { + return false; + } + + if (empty($globalCacheForGetObjectFromCache[$objetClassName][$objectId])) { + $object = new $objetClassName($db); + if ($object->fetch($objectId, $objectRef) <= 0) { + return false; + } + + if (is_array($globalCacheForGetObjectFromCache[$objetClassName]) && count($globalCacheForGetObjectFromCache[$objetClassName]) >= $maxCacheByType) { + array_shift($globalCacheForGetObjectFromCache[$objetClassName]); + } + + $globalCacheForGetObjectFromCache[$objetClassName][$objectId] = $object; + } else { + $object = $globalCacheForGetObjectFromCache[$objetClassName][$objectId]; + } + + return $object; +} + /** * Return if a file can contains executable content * From 3ebc54852ad72636a878189da62f825daaec583a Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Mon, 8 Aug 2022 10:16:44 +0200 Subject: [PATCH 08/28] Use already existing function --- htdocs/core/lib/functions.lib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 2e85800003334..522b9c03f85c5 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10836,7 +10836,7 @@ function fetchObjectByElement($element_id, $element_type, $element_ref = '', $us dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php'); if ($useCache) { - getObjectFromCache($element_prop['classname'], $element_id, $element_ref, $maxCacheByType); + $objecttmp = fetchObjectFromCache($element_prop['classname'], $element_id, $element_ref, $maxCacheByType); } else { $objecttmp = new $element_prop['classname']($db); $ret = $objecttmp->fetch($element_id, $element_ref); @@ -10860,7 +10860,7 @@ function fetchObjectByElement($element_id, $element_type, $element_ref = '', $us * @param int $maxCacheByType max number of storable object fore each type * @return bool|CommonObject */ -function getObjectFromCache($objetClassName, $objectId, $objectRef = false, $maxCacheByType = 10) +function fetchObjectFromCache($objetClassName, $objectId, $objectRef = false, $maxCacheByType = 10) { global $db,$globalCacheForGetObjectFromCache; From 50d77b826df858266346b7e7fef8c99665d43d0d Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Mon, 8 Aug 2022 10:23:49 +0200 Subject: [PATCH 09/28] Use already existing function --- htdocs/core/lib/functions.lib.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 522b9c03f85c5..5fd55a41cd220 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10858,20 +10858,21 @@ function fetchObjectByElement($element_id, $element_type, $element_ref = '', $us * @param int $objectId object Id * @param string $objectRef object ref * @param int $maxCacheByType max number of storable object fore each type - * @return bool|CommonObject + * @return int|object object || 0 || -1 if error */ function fetchObjectFromCache($objetClassName, $objectId, $objectRef = false, $maxCacheByType = 10) { global $db,$globalCacheForGetObjectFromCache; if (!class_exists($objetClassName)) { - return false; + return -1; } if (empty($globalCacheForGetObjectFromCache[$objetClassName][$objectId])) { $object = new $objetClassName($db); - if ($object->fetch($objectId, $objectRef) <= 0) { - return false; + $res = $object->fetch($objectId, $objectRef); + if ($res <= 0) { + return $res; } if (is_array($globalCacheForGetObjectFromCache[$objetClassName]) && count($globalCacheForGetObjectFromCache[$objetClassName]) >= $maxCacheByType) { From 20c9c64d7f1ba71557099963db08a39e10a00ff0 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Mon, 8 Aug 2022 10:48:14 +0200 Subject: [PATCH 10/28] Use already existing function --- htdocs/core/lib/functions.lib.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 5fd55a41cd220..843212e002ebc 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10837,13 +10837,15 @@ function fetchObjectByElement($element_id, $element_type, $element_ref = '', $us if ($useCache) { $objecttmp = fetchObjectFromCache($element_prop['classname'], $element_id, $element_ref, $maxCacheByType); + if (is_object($objecttmp)) { + return $objecttmp; + } } else { $objecttmp = new $element_prop['classname']($db); $ret = $objecttmp->fetch($element_id, $element_ref); - } - - if ($ret >= 0) { - return $objecttmp; + if ($ret >= 0) { + return $objecttmp; + } } } return 0; From 74fb2c006288689ed6ebf29ad52ae90917dd3a75 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Mon, 8 Aug 2022 11:03:10 +0200 Subject: [PATCH 11/28] Add llx element type table --- .../install/mysql/tables/llx_element_type.sql | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 htdocs/install/mysql/tables/llx_element_type.sql diff --git a/htdocs/install/mysql/tables/llx_element_type.sql b/htdocs/install/mysql/tables/llx_element_type.sql new file mode 100644 index 0000000000000..e79875fd16a2f --- /dev/null +++ b/htdocs/install/mysql/tables/llx_element_type.sql @@ -0,0 +1,33 @@ +-- ============================================================================ +-- Copyright (C) 2008-2011 Laurent Destailleur +-- Copyright (C) 2011 Regis Houssin +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- ============================================================================ +-- Table used for relations between elements of different types: +-- invoice-propal, propal-order, etc... +-- ============================================================================ + +create table llx_element_type +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + fk_element integer NOT NULL, + element_type varchar(64) NOT NULL, + element varchar(32) NOT NULL, + module_name varchar(31) NOT NULL, + class_path text NOT NULL, + class_file varchar(128) NOT NULL, +) ENGINE=innodb; + From ba335942682bb51b286608b3be0ac6403c580672 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Tue, 9 Aug 2022 10:12:39 +0200 Subject: [PATCH 12/28] Update htdocs/install/mysql/tables/llx_element_type.sql Co-authored-by: Florian Mortgat <50440633+atm-florianm@users.noreply.github.com> --- htdocs/install/mysql/tables/llx_element_type.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/mysql/tables/llx_element_type.sql b/htdocs/install/mysql/tables/llx_element_type.sql index e79875fd16a2f..9fe86e5d23c24 100644 --- a/htdocs/install/mysql/tables/llx_element_type.sql +++ b/htdocs/install/mysql/tables/llx_element_type.sql @@ -27,7 +27,7 @@ create table llx_element_type element_type varchar(64) NOT NULL, element varchar(32) NOT NULL, module_name varchar(31) NOT NULL, - class_path text NOT NULL, + class_dir text NOT NULL, class_file varchar(128) NOT NULL, ) ENGINE=innodb; From 96a2dc7ea3ce4ebe22726edc1d0c5296a3758e2e Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Mon, 15 Aug 2022 18:08:46 +0200 Subject: [PATCH 13/28] Update htdocs/install/mysql/migration/16.0.0-17.0.0.sql --- htdocs/install/mysql/migration/16.0.0-17.0.0.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql index 2149aa44ce3b3..7623ed08525d1 100644 --- a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql +++ b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql @@ -79,4 +79,4 @@ ALTER TABLE llx_ticket ADD email_date datetime after email_msgid; INSERT INTO llx_const (name, entity, value, type, visible) VALUES ('MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT', 1, 1000, 'int', 0); ALTER TABLE llx_element_element CHANGE sourcetype sourcetype VARCHAR(64) NOT NULL; -ALTER TABLE llx_element_element CHANGE targettype targettype VARCHAR(64) NOT NULL; +ALTER TABLE llx_element_element MODIFY COLUMN targettype VARCHAR(64) NOT NULL; From 75aa755707c1395e078c9484fc24c44201d75082 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Mon, 15 Aug 2022 18:08:53 +0200 Subject: [PATCH 14/28] Update htdocs/install/mysql/migration/16.0.0-17.0.0.sql --- htdocs/install/mysql/migration/16.0.0-17.0.0.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql index 7623ed08525d1..108b9a4283b0c 100644 --- a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql +++ b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql @@ -78,5 +78,5 @@ ALTER TABLE llx_ticket ADD email_date datetime after email_msgid; INSERT INTO llx_const (name, entity, value, type, visible) VALUES ('MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT', 1, 1000, 'int', 0); -ALTER TABLE llx_element_element CHANGE sourcetype sourcetype VARCHAR(64) NOT NULL; +ALTER TABLE llx_element_element MODIFY COLUMN sourcetype VARCHAR(64) NOT NULL; ALTER TABLE llx_element_element MODIFY COLUMN targettype VARCHAR(64) NOT NULL; From 80a30ff173e710a4847bc9593783b8cb547618fc Mon Sep 17 00:00:00 2001 From: ATM john Date: Thu, 1 Sep 2022 10:24:48 +0200 Subject: [PATCH 15/28] Add class element properties --- htdocs/core/class/elementproperties.class.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 htdocs/core/class/elementproperties.class.php diff --git a/htdocs/core/class/elementproperties.class.php b/htdocs/core/class/elementproperties.class.php new file mode 100644 index 0000000000000..7a25d08d410ed --- /dev/null +++ b/htdocs/core/class/elementproperties.class.php @@ -0,0 +1,35 @@ + Date: Thu, 1 Sep 2022 15:26:22 +0200 Subject: [PATCH 16/28] Class element properties --- htdocs/core/class/elementproperties.class.php | 291 +++++++++++++++++- htdocs/core/lib/functions.lib.php | 17 +- .../tables/llx_element_properties.key.sql | 22 ++ ...nt_type.sql => llx_element_properties.sql} | 20 +- 4 files changed, 336 insertions(+), 14 deletions(-) create mode 100644 htdocs/install/mysql/tables/llx_element_properties.key.sql rename htdocs/install/mysql/tables/{llx_element_type.sql => llx_element_properties.sql} (69%) diff --git a/htdocs/core/class/elementproperties.class.php b/htdocs/core/class/elementproperties.class.php index 7a25d08d410ed..0aae0b334b6f9 100644 --- a/htdocs/core/class/elementproperties.class.php +++ b/htdocs/core/class/elementproperties.class.php @@ -3,6 +3,7 @@ /** * class to manage element properties + * this class cannot extend common object */ class ElementProperties { @@ -18,7 +19,7 @@ class ElementProperties public $id; /** - * @var string Error string + * @var string Error string containing last error * @see $errors */ public $error; @@ -31,5 +32,291 @@ class ElementProperties /** * @var string Name of table without prefix where object is stored */ - public $table_element = 'element_type'; + public $table_element = 'element_properties'; + + + /** + * @var string default usage is a concat like $this->element.'_'.$this->>module_name but old modules or external modules could have old bad practices + */ + public $element_type; + + /** + * @var string ID to identify targeted managed object in common object + */ + public $element; + + + /** + * @var string the module name in lowercase + */ + public $module_name; + + /** + * @var string the location of the class without the file name and trailing slash (/). + * Will be used for dol_include_once. + * Ex: compta/facture/class + */ + public $class_dir = null; + + /** + * @var string the class filename + */ + public $class_file; + + /** + * @var string the class name + */ + public $class_name; + + /** + * @var int creation date + */ + public $datec; + + /** + * @var int creation date + */ + public $tms; + + /** + * class constructor + * @param DoliDB $db the doliDb instance + */ + public function __construct($db) + { + $this->db = $db; + } + + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $element_type element_type + * @param string $moreWhere More SQL filters (' AND ...') + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id = null, $element_type = null, $moreWhere = '') + { + $sql = /** @lang MySQL */ "SELECT rowid, element_type, element, module_name, class_dir, class_file,class_name, datec, tms"; + $sql .= " FROM ".$this->db->prefix().$this->table_element.' as t'; + + if (!empty($id)) { + $sql .= ' WHERE t.rowid = '.((int) $id); + } elseif (!empty($element_type)) { + $sql .= " WHERE t.element_type = '".$this->db->escape($element_type)."'"; + } elseif (!empty($moreWhere)) { + $sql .= ' WHERE 1 = 1'; + } else { + $this->setError('Missing fetching parameters'); + return -1; + } + + if ($moreWhere) { + $sql .= $moreWhere; + } + + $obj = $this->db->getRow($sql); + if ($obj === false) { + $this->setError('SQL query error'); + return -1; + } elseif ($obj) { + $this->id = $obj->rowid; + $this->element_type = $obj->element_type; + $this->element = $obj->element; + $this->module_name = $obj->module_name; + $this->class_dir = $obj->class_dir; + $this->class_file = $obj->class_file; + $this->class_name = $obj->class_name; + $this->datec = $this->db->jdate($obj->datec); + $this->tms = $this->db->jdate($obj->tms); + + return 1; + } + + // no results + return 0; + } + + /** + * Load object in memory from the database + * + * @param string $element element + * @param string $module_name module name + * @param string $moreWhere More SQL filters (' AND ...') + * @return ElementProperties[]|int <0 if KO, array of ElementProperties on success + */ + public function fetchAll($element = null, $module_name = null, $moreWhere = '') + { + + $elementsProperties = array(); + + $sql = /** @lang MySQL */ "SELECT rowid"; + $sql .= " FROM ".$this->db->prefix().$this->table_element.' as t'; + $sql .= ' WHERE 1 = 1'; + + if (!empty($id)) { + $sql .= " AND t.element = '".$this->db->escape($element)."'"; + } elseif (!empty($element_type)) { + $sql .= " AND t.module_name = '".$this->db->escape($module_name)."'"; + } + + $sql .= $moreWhere; + $objs = $this->db->getRows($sql); + if ($objs === false) { + $this->setError('SQL query error'); + return -1; + } elseif (!empty($objs)) { + foreach ($objs as $obj) { + $elementProperties = new self($this->db); + if ($elementProperties->fetch($obj->rowid) > 0) { + $elementsProperties[$obj->rowid] = $elementProperties; + } else { + $elementProperties->setError($elementProperties->error); + return -1; + } + } + } + + return $elementsProperties; + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function create(User $user, $notrigger = false) + { + global $conf, $langs; + dol_syslog(get_class($this)."::create", LOG_DEBUG); + + $error = 0; + + if (empty($this->tms)) { + $this->tms = dol_now(); + } + + if (empty($this->datec)) { + $this->datec = dol_now(); + } + + + $sql = /** @lang MySQL */ 'INSERT INTO '.$this->db->prefix().$this->table_element; + $sql .= "("; + $sql .= " rowid, element_type, element, module_name, class_dir, class_file, class_name, datec, tms "; + $sql .= ") VALUES ("; + $sql .= " NULL ,"; + $sql .= "'".$this->db->escape($this->element_type)."',"; + $sql .= "'".$this->db->escape($this->element)."',"; + $sql .= "'".$this->db->escape($this->module_name)."',"; + $sql .= "'".$this->db->escape($this->class_dir)."',"; + $sql .= "'".$this->db->escape($this->class_file)."',"; + $sql .= "'".$this->db->escape($this->class_name)."',"; + $sql .= "'".$this->db->idate($this->datec)."',"; + $sql .= "'".$this->db->idate($this->tms)."'"; + $sql .= ")"; + $sql .= ' WHERE rowid='.((int) $this->id); + + $this->db->begin(); + + if (!$error) { + $res = $this->db->query($sql); + if (!$res) { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } + + // Triggers + if (!$error && !$notrigger) { + // Call triggers + $result = $this->call_trigger(strtoupper(get_class($this)).'_CREATE', $user); + if ($result < 0) { + $error++; + } //Do also here what you must do to rollback action if trigger fail + // End call triggers + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return $this->id; + } + } + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + global $conf, $langs; + dol_syslog(get_class($this)."::update", LOG_DEBUG); + + $error = 0; + + $this->tms = dol_now(); + + $sql = /** @lang MySQL */ 'UPDATE '.$this->db->prefix().$this->table_element; + $sql .= ' SET '; + $sql .= " element_type = '".$this->db->escape($this->element_type)."' ,"; + $sql .= " element = '".$this->db->escape($this->element)."' ,"; + $sql .= " module_name = '".$this->db->escape($this->module_name)."' ,"; + $sql .= " class_dir = '".$this->db->escape($this->class_dir)."' ,"; + $sql .= " class_file = '".$this->db->escape($this->class_file)."' ,"; + $sql .= " class_name = '".$this->db->escape($this->class_name)."' ,"; + $sql .= " datec = '".$this->db->idate($this->datec)."' ,"; + $sql .= " tms = '".$this->db->idate($this->tms)."'"; + $sql .= ' WHERE rowid='.((int) $this->id); + + $this->db->begin(); + + if (!$error) { + $res = $this->db->query($sql); + if (!$res) { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } + + // Triggers + if (!$error && !$notrigger) { + // Call triggers + $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $user); + if ($result < 0) { + $error++; + } //Do also here what you must do to rollback action if trigger fail + // End call triggers + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return $this->id; + } + } + + /** + * set error for this object + * @param $msg error message + * @return void + */ + protected function setError($msg) + { + if (!empty($msg)) { + $this->error = $msg; + $this->errors[] = $msg; + } + } } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 3ec5cb54af274..39cf900b8d823 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10711,6 +10711,7 @@ function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $u */ function getElementProperties($element_type) { + global $db; $regs = array(); $classfile = $classname = $classpath = ''; @@ -10832,8 +10833,20 @@ function getElementProperties($element_type) 'classname' => $classname ); - // TODO : Add hook here but need to add cache for results if there is a hook (hook could add performance loss) - // OR **store special elements in database in table like element_type and fetch it Once** + + + if (!class_exists('ElementProperties')) { require_once DOL_DOCUMENT_ROOT . '/core/class/elementproperties.class.php'; } + $elementProperties = new ElementProperties($db); + if ($elementProperties->fetch(null, $element_type)>0) { + $element_properties = array( + 'module' => $elementProperties->module_name, + 'classpath' => $elementProperties->class_dir, + 'element' => $elementProperties->element, + 'subelement' => $elementProperties->class_name, + 'classfile' => $elementProperties->class_file, + 'classname' => $elementProperties->class_name + ); + } return $element_properties; diff --git a/htdocs/install/mysql/tables/llx_element_properties.key.sql b/htdocs/install/mysql/tables/llx_element_properties.key.sql new file mode 100644 index 0000000000000..f7f8ab298f285 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_element_properties.key.sql @@ -0,0 +1,22 @@ +-- ============================================================================ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- ============================================================================ +-- Table used for relations between elements of different types: +-- invoice-propal, propal-order, etc... +-- ============================================================================ + +ALTER TABLE llx_element_properties ADD UNIQUE INDEX element_type (element_type); +ALTER TABLE llx_element_properties ADD INDEX element_module (element, module_name); diff --git a/htdocs/install/mysql/tables/llx_element_type.sql b/htdocs/install/mysql/tables/llx_element_properties.sql similarity index 69% rename from htdocs/install/mysql/tables/llx_element_type.sql rename to htdocs/install/mysql/tables/llx_element_properties.sql index 9fe86e5d23c24..ac8180e79ffcb 100644 --- a/htdocs/install/mysql/tables/llx_element_type.sql +++ b/htdocs/install/mysql/tables/llx_element_properties.sql @@ -1,6 +1,4 @@ -- ============================================================================ --- Copyright (C) 2008-2011 Laurent Destailleur --- Copyright (C) 2011 Regis Houssin -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by @@ -20,14 +18,16 @@ -- invoice-propal, propal-order, etc... -- ============================================================================ -create table llx_element_type +create table llx_element_properties ( - rowid integer AUTO_INCREMENT PRIMARY KEY, - fk_element integer NOT NULL, - element_type varchar(64) NOT NULL, - element varchar(32) NOT NULL, - module_name varchar(31) NOT NULL, - class_dir text NOT NULL, - class_file varchar(128) NOT NULL, + rowid integer AUTO_INCREMENT PRIMARY KEY, + element_type varchar(64) NOT NULL, + element varchar(32) NOT NULL, + module_name varchar(31) NOT NULL, + class_dir text NOT NULL, + class_file varchar(128) NOT NULL, + class_name varchar(128) NOT NULL, + datec datetime, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=innodb; From a09eb7ca935508c1a68b6e4f0e93452776526f4e Mon Sep 17 00:00:00 2001 From: ATM john Date: Thu, 1 Sep 2022 15:39:11 +0200 Subject: [PATCH 17/28] Add mysql migrattion crete table for element properties --- htdocs/install/mysql/migration/16.0.0-17.0.0.sql | 14 ++++++++++++++ .../mysql/tables/llx_element_properties.sql | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql index dc912cef8a07e..c4015bd97d924 100644 --- a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql +++ b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql @@ -117,6 +117,20 @@ ALTER TABLE llx_cronjob ADD COLUMN pid integer; ALTER TABLE llx_element_element CHANGE sourcetype sourcetype VARCHAR(64) NOT NULL; ALTER TABLE llx_element_element CHANGE targettype targettype VARCHAR(64) NOT NULL; +CREATE TABLE llx_element_properties +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + element_type varchar(64) NOT NULL, + element varchar(32) NOT NULL, + module_name varchar(31) NOT NULL, + class_dir text NOT NULL, + class_file varchar(128) NOT NULL, + class_name varchar(128) NOT NULL, + datec datetime, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=innodb; + + INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('BE-VICTORYDAY', 0, 2, '', 0, 5, 8, 1); INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('BE-NATIONALDAY', 0, 2, '', 0, 7, 21, 1); INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('BE-ASSOMPTION', 0, 2, '', 0, 8, 15, 1); diff --git a/htdocs/install/mysql/tables/llx_element_properties.sql b/htdocs/install/mysql/tables/llx_element_properties.sql index ac8180e79ffcb..87ea195e162fc 100644 --- a/htdocs/install/mysql/tables/llx_element_properties.sql +++ b/htdocs/install/mysql/tables/llx_element_properties.sql @@ -18,7 +18,7 @@ -- invoice-propal, propal-order, etc... -- ============================================================================ -create table llx_element_properties +CREATE TABLE llx_element_properties ( rowid integer AUTO_INCREMENT PRIMARY KEY, element_type varchar(64) NOT NULL, From 840173cf37fd1c3d1d21962d887cfc8e376a8911 Mon Sep 17 00:00:00 2001 From: ATM john Date: Thu, 1 Sep 2022 15:48:48 +0200 Subject: [PATCH 18/28] Change sql file comment --- htdocs/install/mysql/tables/llx_element_properties.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/install/mysql/tables/llx_element_properties.sql b/htdocs/install/mysql/tables/llx_element_properties.sql index 87ea195e162fc..3aee94de1725a 100644 --- a/htdocs/install/mysql/tables/llx_element_properties.sql +++ b/htdocs/install/mysql/tables/llx_element_properties.sql @@ -14,8 +14,7 @@ -- along with this program. If not, see . -- -- ============================================================================ --- Table used for relations between elements of different types: --- invoice-propal, propal-order, etc... +-- Table used for describe an object properties who extends CommonObject -- ============================================================================ CREATE TABLE llx_element_properties From dc029cb2c0a5d6764a4a4079dbc7246b5703a7fb Mon Sep 17 00:00:00 2001 From: ATM john Date: Thu, 1 Sep 2022 15:53:01 +0200 Subject: [PATCH 19/28] fix fetch all --- htdocs/core/class/elementproperties.class.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/elementproperties.class.php b/htdocs/core/class/elementproperties.class.php index 0aae0b334b6f9..2991461734f0c 100644 --- a/htdocs/core/class/elementproperties.class.php +++ b/htdocs/core/class/elementproperties.class.php @@ -155,9 +155,11 @@ public function fetchAll($element = null, $module_name = null, $moreWhere = '') $sql .= " FROM ".$this->db->prefix().$this->table_element.' as t'; $sql .= ' WHERE 1 = 1'; - if (!empty($id)) { + if (!empty($element)) { $sql .= " AND t.element = '".$this->db->escape($element)."'"; - } elseif (!empty($element_type)) { + } + + if (!empty($module_name)) { $sql .= " AND t.module_name = '".$this->db->escape($module_name)."'"; } From 0fd5be8ba0724de22d71ff93fe209fc177d19787 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Thu, 1 Sep 2022 15:55:34 +0200 Subject: [PATCH 20/28] Update htdocs/core/class/commonobject.class.php Co-authored-by: Florian Mortgat <50440633+atm-florianm@users.noreply.github.com> --- htdocs/core/class/commonobject.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index f15ccb4161473..53b9bb9f57015 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3888,8 +3888,8 @@ public function add_object_linked($origin = null, $origin_id = null, $f_user = n */ public function getElementType() { - // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. - // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. + // Elements of the core modules having a `$module` property but for which we may not not want to prefix the element name with the module name for finding the linked object in llx_element_element. + // It's because existing llx_element_element entries inserted prior to this modification (version <=14.2) may already use the element name alone in fk_source or fk_target (without the module name prefix). $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization', 'asset'); // Add module part to target type if object has $module property and isn't in core modules. return ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; From 5ec8e96be8e4e21de3b0a5258c071abdfdd734da Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Thu, 1 Sep 2022 16:00:19 +0200 Subject: [PATCH 21/28] Update htdocs/core/class/elementproperties.class.php Co-authored-by: Florian Mortgat <50440633+atm-florianm@users.noreply.github.com> --- htdocs/core/class/elementproperties.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/elementproperties.class.php b/htdocs/core/class/elementproperties.class.php index 2991461734f0c..44dfcddf827f2 100644 --- a/htdocs/core/class/elementproperties.class.php +++ b/htdocs/core/class/elementproperties.class.php @@ -89,7 +89,8 @@ public function __construct($db) /** - * Load object in memory from the database + * Load object in memory from the database using either the ID, element type or a custom filter + * (parameters are mutually exclusive) * * @param int $id Id object * @param string $element_type element_type From ced8cf54eb52786102c3da42f3d352da1d9a0e13 Mon Sep 17 00:00:00 2001 From: ATM john Date: Thu, 1 Sep 2022 16:06:05 +0200 Subject: [PATCH 22/28] Fix sql create --- htdocs/core/class/elementproperties.class.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/elementproperties.class.php b/htdocs/core/class/elementproperties.class.php index 2991461734f0c..1aca25daea786 100644 --- a/htdocs/core/class/elementproperties.class.php +++ b/htdocs/core/class/elementproperties.class.php @@ -220,7 +220,6 @@ public function create(User $user, $notrigger = false) $sql .= "'".$this->db->idate($this->datec)."',"; $sql .= "'".$this->db->idate($this->tms)."'"; $sql .= ")"; - $sql .= ' WHERE rowid='.((int) $this->id); $this->db->begin(); @@ -230,6 +229,10 @@ public function create(User $user, $notrigger = false) $error++; $this->errors[] = $this->db->lasterror(); } + + if (!$error) { + $this->id = $this->db->last_insert_id($this->db->prefix().$this->table_element); + } } // Triggers From aa787d2791d251c28b9a495d7a81e4843cd0b00c Mon Sep 17 00:00:00 2001 From: ATM john Date: Thu, 1 Sep 2022 16:54:58 +0200 Subject: [PATCH 23/28] Free memory --- htdocs/core/db/DoliDB.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index c262cd94b9473..804d042164dc6 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -358,6 +358,7 @@ public function getRow($sql) if ($res) { $obj = $this->fetch_object($res); if ($obj) { + $this->free($res); return $obj; } else { return 0; From 36ac81768c859fb04c12f10550b3cd1c77f0bba9 Mon Sep 17 00:00:00 2001 From: ATM john Date: Thu, 1 Sep 2022 17:03:09 +0200 Subject: [PATCH 24/28] Add todo Comment --- htdocs/core/lib/functions.lib.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 39cf900b8d823..808ead8b4a91a 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10838,6 +10838,8 @@ function getElementProperties($element_type) if (!class_exists('ElementProperties')) { require_once DOL_DOCUMENT_ROOT . '/core/class/elementproperties.class.php'; } $elementProperties = new ElementProperties($db); if ($elementProperties->fetch(null, $element_type)>0) { + // TODO : manage cache or fetch all once in main instead of always fetch ? + $element_properties = array( 'module' => $elementProperties->module_name, 'classpath' => $elementProperties->class_dir, From 5472b32e1b270a6e3b55d6afdebfe52e58f23261 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Mon, 12 Sep 2022 15:20:23 +0200 Subject: [PATCH 25/28] update sql --- htdocs/install/mysql/migration/16.0.0-17.0.0.sql | 5 +++-- htdocs/install/mysql/tables/llx_c_type_contact.sql | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql index c4015bd97d924..8f085e5f0e53b 100644 --- a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql +++ b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql @@ -114,8 +114,9 @@ ALTER TABLE llx_ticket ADD email_date datetime after email_msgid; ALTER TABLE llx_cronjob ADD COLUMN pid integer; -ALTER TABLE llx_element_element CHANGE sourcetype sourcetype VARCHAR(64) NOT NULL; -ALTER TABLE llx_element_element CHANGE targettype targettype VARCHAR(64) NOT NULL; +ALTER TABLE llx_element_element MODIFY COLUMN sourcetype VARCHAR(64) NOT NULL; +ALTER TABLE llx_element_element MODIFY COLUMN targettype VARCHAR(64) NOT NULL; +ALTER TABLE llx_c_type_contact MODIFY COLUMN element VARCHAR(64) NOT NULL; CREATE TABLE llx_element_properties ( diff --git a/htdocs/install/mysql/tables/llx_c_type_contact.sql b/htdocs/install/mysql/tables/llx_c_type_contact.sql index e2275e71e5fd2..65ddb592ce0fc 100644 --- a/htdocs/install/mysql/tables/llx_c_type_contact.sql +++ b/htdocs/install/mysql/tables/llx_c_type_contact.sql @@ -30,7 +30,7 @@ create table llx_c_type_contact ( rowid integer AUTO_INCREMENT PRIMARY KEY, - element varchar(30) NOT NULL, + element varchar(64) NOT NULL, source varchar(8) DEFAULT 'external' NOT NULL, code varchar(32) NOT NULL, libelle varchar(128) NOT NULL, From e5b8e9042ab7604209ce3d08abf33cd98aa6b67e Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Mon, 24 Oct 2022 17:40:08 +0200 Subject: [PATCH 26/28] Remove element properties class and replace by hook --- htdocs/core/class/elementproperties.class.php | 328 ------------------ htdocs/core/lib/functions.lib.php | 38 +- .../install/mysql/migration/16.0.0-17.0.0.sql | 13 - .../tables/llx_element_properties.key.sql | 22 -- .../mysql/tables/llx_element_properties.sql | 32 -- 5 files changed, 25 insertions(+), 408 deletions(-) delete mode 100644 htdocs/core/class/elementproperties.class.php delete mode 100644 htdocs/install/mysql/tables/llx_element_properties.key.sql delete mode 100644 htdocs/install/mysql/tables/llx_element_properties.sql diff --git a/htdocs/core/class/elementproperties.class.php b/htdocs/core/class/elementproperties.class.php deleted file mode 100644 index b40e63f90ddcd..0000000000000 --- a/htdocs/core/class/elementproperties.class.php +++ /dev/null @@ -1,328 +0,0 @@ -element.'_'.$this->>module_name but old modules or external modules could have old bad practices - */ - public $element_type; - - /** - * @var string ID to identify targeted managed object in common object - */ - public $element; - - - /** - * @var string the module name in lowercase - */ - public $module_name; - - /** - * @var string the location of the class without the file name and trailing slash (/). - * Will be used for dol_include_once. - * Ex: compta/facture/class - */ - public $class_dir = null; - - /** - * @var string the class filename - */ - public $class_file; - - /** - * @var string the class name - */ - public $class_name; - - /** - * @var int creation date - */ - public $datec; - - /** - * @var int creation date - */ - public $tms; - - /** - * class constructor - * @param DoliDB $db the doliDb instance - */ - public function __construct($db) - { - $this->db = $db; - } - - - /** - * Load object in memory from the database using either the ID, element type or a custom filter - * (parameters are mutually exclusive) - * - * @param int $id Id object - * @param string $element_type element_type - * @param string $moreWhere More SQL filters (' AND ...') - * @return int <0 if KO, 0 if not found, >0 if OK - */ - public function fetch($id = null, $element_type = null, $moreWhere = '') - { - $sql = /** @lang MySQL */ "SELECT rowid, element_type, element, module_name, class_dir, class_file,class_name, datec, tms"; - $sql .= " FROM ".$this->db->prefix().$this->table_element.' as t'; - - if (!empty($id)) { - $sql .= ' WHERE t.rowid = '.((int) $id); - } elseif (!empty($element_type)) { - $sql .= " WHERE t.element_type = '".$this->db->escape($element_type)."'"; - } elseif (!empty($moreWhere)) { - $sql .= ' WHERE 1 = 1'; - } else { - $this->setError('Missing fetching parameters'); - return -1; - } - - if ($moreWhere) { - $sql .= $moreWhere; - } - - $obj = $this->db->getRow($sql); - if ($obj === false) { - $this->setError('SQL query error'); - return -1; - } elseif ($obj) { - $this->id = $obj->rowid; - $this->element_type = $obj->element_type; - $this->element = $obj->element; - $this->module_name = $obj->module_name; - $this->class_dir = $obj->class_dir; - $this->class_file = $obj->class_file; - $this->class_name = $obj->class_name; - $this->datec = $this->db->jdate($obj->datec); - $this->tms = $this->db->jdate($obj->tms); - - return 1; - } - - // no results - return 0; - } - - /** - * Load object in memory from the database - * - * @param string $element element - * @param string $module_name module name - * @param string $moreWhere More SQL filters (' AND ...') - * @return ElementProperties[]|int <0 if KO, array of ElementProperties on success - */ - public function fetchAll($element = null, $module_name = null, $moreWhere = '') - { - - $elementsProperties = array(); - - $sql = /** @lang MySQL */ "SELECT rowid"; - $sql .= " FROM ".$this->db->prefix().$this->table_element.' as t'; - $sql .= ' WHERE 1 = 1'; - - if (!empty($element)) { - $sql .= " AND t.element = '".$this->db->escape($element)."'"; - } - - if (!empty($module_name)) { - $sql .= " AND t.module_name = '".$this->db->escape($module_name)."'"; - } - - $sql .= $moreWhere; - $objs = $this->db->getRows($sql); - if ($objs === false) { - $this->setError('SQL query error'); - return -1; - } elseif (!empty($objs)) { - foreach ($objs as $obj) { - $elementProperties = new self($this->db); - if ($elementProperties->fetch($obj->rowid) > 0) { - $elementsProperties[$obj->rowid] = $elementProperties; - } else { - $elementProperties->setError($elementProperties->error); - return -1; - } - } - } - - return $elementsProperties; - } - - /** - * Update object into database - * - * @param User $user User that modifies - * @param bool $notrigger false=launch triggers after, true=disable triggers - * @return int <0 if KO, >0 if OK - */ - public function create(User $user, $notrigger = false) - { - global $conf, $langs; - dol_syslog(get_class($this)."::create", LOG_DEBUG); - - $error = 0; - - if (empty($this->tms)) { - $this->tms = dol_now(); - } - - if (empty($this->datec)) { - $this->datec = dol_now(); - } - - - $sql = /** @lang MySQL */ 'INSERT INTO '.$this->db->prefix().$this->table_element; - $sql .= "("; - $sql .= " rowid, element_type, element, module_name, class_dir, class_file, class_name, datec, tms "; - $sql .= ") VALUES ("; - $sql .= " NULL ,"; - $sql .= "'".$this->db->escape($this->element_type)."',"; - $sql .= "'".$this->db->escape($this->element)."',"; - $sql .= "'".$this->db->escape($this->module_name)."',"; - $sql .= "'".$this->db->escape($this->class_dir)."',"; - $sql .= "'".$this->db->escape($this->class_file)."',"; - $sql .= "'".$this->db->escape($this->class_name)."',"; - $sql .= "'".$this->db->idate($this->datec)."',"; - $sql .= "'".$this->db->idate($this->tms)."'"; - $sql .= ")"; - - $this->db->begin(); - - if (!$error) { - $res = $this->db->query($sql); - if (!$res) { - $error++; - $this->errors[] = $this->db->lasterror(); - } - - if (!$error) { - $this->id = $this->db->last_insert_id($this->db->prefix().$this->table_element); - } - } - - // Triggers - if (!$error && !$notrigger) { - // Call triggers - $result = $this->call_trigger(strtoupper(get_class($this)).'_CREATE', $user); - if ($result < 0) { - $error++; - } //Do also here what you must do to rollback action if trigger fail - // End call triggers - } - - // Commit or rollback - if ($error) { - $this->db->rollback(); - return -1; - } else { - $this->db->commit(); - return $this->id; - } - } - /** - * Update object into database - * - * @param User $user User that modifies - * @param bool $notrigger false=launch triggers after, true=disable triggers - * @return int <0 if KO, >0 if OK - */ - public function update(User $user, $notrigger = false) - { - global $conf, $langs; - dol_syslog(get_class($this)."::update", LOG_DEBUG); - - $error = 0; - - $this->tms = dol_now(); - - $sql = /** @lang MySQL */ 'UPDATE '.$this->db->prefix().$this->table_element; - $sql .= ' SET '; - $sql .= " element_type = '".$this->db->escape($this->element_type)."' ,"; - $sql .= " element = '".$this->db->escape($this->element)."' ,"; - $sql .= " module_name = '".$this->db->escape($this->module_name)."' ,"; - $sql .= " class_dir = '".$this->db->escape($this->class_dir)."' ,"; - $sql .= " class_file = '".$this->db->escape($this->class_file)."' ,"; - $sql .= " class_name = '".$this->db->escape($this->class_name)."' ,"; - $sql .= " datec = '".$this->db->idate($this->datec)."' ,"; - $sql .= " tms = '".$this->db->idate($this->tms)."'"; - $sql .= ' WHERE rowid='.((int) $this->id); - - $this->db->begin(); - - if (!$error) { - $res = $this->db->query($sql); - if (!$res) { - $error++; - $this->errors[] = $this->db->lasterror(); - } - } - - // Triggers - if (!$error && !$notrigger) { - // Call triggers - $result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $user); - if ($result < 0) { - $error++; - } //Do also here what you must do to rollback action if trigger fail - // End call triggers - } - - // Commit or rollback - if ($error) { - $this->db->rollback(); - return -1; - } else { - $this->db->commit(); - return $this->id; - } - } - - /** - * set error for this object - * @param $msg error message - * @return void - */ - protected function setError($msg) - { - if (!empty($msg)) { - $this->error = $msg; - $this->errors[] = $msg; - } - } -} diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 808ead8b4a91a..7610308b773a5 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10834,22 +10834,34 @@ function getElementProperties($element_type) ); + // Add pdfgeneration hook + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + $hookmanager->initHooks(array('elementproperties')); - if (!class_exists('ElementProperties')) { require_once DOL_DOCUMENT_ROOT . '/core/class/elementproperties.class.php'; } - $elementProperties = new ElementProperties($db); - if ($elementProperties->fetch(null, $element_type)>0) { - // TODO : manage cache or fetch all once in main instead of always fetch ? - - $element_properties = array( - 'module' => $elementProperties->module_name, - 'classpath' => $elementProperties->class_dir, - 'element' => $elementProperties->element, - 'subelement' => $elementProperties->class_name, - 'classfile' => $elementProperties->class_file, - 'classname' => $elementProperties->class_name - ); + + // Hook params + $parameters = array( + 'element_type' => $element_type, + 'element_properties' => $element_properties + ); + + $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters); + + if ($reshook) { + $element_properties = $hookmanager->resArray; + } else { + foreach ($hookmanager->resArray as $k => $desc) { + $element_properties[$k] = $desc; + } } + // context of elementproperties doesn't need to exist out of this function so delete it to avoid elementproperties is equal to all + if (($key = array_search($this->contextarray, 'elementproperties')) !== false) { + unset($this->contextarray[$key]); + } return $element_properties; } diff --git a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql index 8f085e5f0e53b..f8322648156be 100644 --- a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql +++ b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql @@ -118,19 +118,6 @@ ALTER TABLE llx_element_element MODIFY COLUMN sourcetype VARCHAR(64) NOT NULL; ALTER TABLE llx_element_element MODIFY COLUMN targettype VARCHAR(64) NOT NULL; ALTER TABLE llx_c_type_contact MODIFY COLUMN element VARCHAR(64) NOT NULL; -CREATE TABLE llx_element_properties -( - rowid integer AUTO_INCREMENT PRIMARY KEY, - element_type varchar(64) NOT NULL, - element varchar(32) NOT NULL, - module_name varchar(31) NOT NULL, - class_dir text NOT NULL, - class_file varchar(128) NOT NULL, - class_name varchar(128) NOT NULL, - datec datetime, - tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -) ENGINE=innodb; - INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('BE-VICTORYDAY', 0, 2, '', 0, 5, 8, 1); INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('BE-NATIONALDAY', 0, 2, '', 0, 7, 21, 1); diff --git a/htdocs/install/mysql/tables/llx_element_properties.key.sql b/htdocs/install/mysql/tables/llx_element_properties.key.sql deleted file mode 100644 index f7f8ab298f285..0000000000000 --- a/htdocs/install/mysql/tables/llx_element_properties.key.sql +++ /dev/null @@ -1,22 +0,0 @@ --- ============================================================================ --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License --- along with this program. If not, see . --- --- ============================================================================ --- Table used for relations between elements of different types: --- invoice-propal, propal-order, etc... --- ============================================================================ - -ALTER TABLE llx_element_properties ADD UNIQUE INDEX element_type (element_type); -ALTER TABLE llx_element_properties ADD INDEX element_module (element, module_name); diff --git a/htdocs/install/mysql/tables/llx_element_properties.sql b/htdocs/install/mysql/tables/llx_element_properties.sql deleted file mode 100644 index 3aee94de1725a..0000000000000 --- a/htdocs/install/mysql/tables/llx_element_properties.sql +++ /dev/null @@ -1,32 +0,0 @@ --- ============================================================================ --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License --- along with this program. If not, see . --- --- ============================================================================ --- Table used for describe an object properties who extends CommonObject --- ============================================================================ - -CREATE TABLE llx_element_properties -( - rowid integer AUTO_INCREMENT PRIMARY KEY, - element_type varchar(64) NOT NULL, - element varchar(32) NOT NULL, - module_name varchar(31) NOT NULL, - class_dir text NOT NULL, - class_file varchar(128) NOT NULL, - class_name varchar(128) NOT NULL, - datec datetime, - tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -) ENGINE=innodb; - From a9786cdeb54fdfb2b5fd5e00f09e056d671d8cc1 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Wed, 26 Oct 2022 09:18:01 +0200 Subject: [PATCH 27/28] Fix hook --- htdocs/core/lib/functions.lib.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 95170c3dbc372..6d9246af47423 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10866,7 +10866,7 @@ function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $u */ function getElementProperties($element_type) { - global $db; + global $db, $hookmanager; $regs = array(); $classfile = $classname = $classpath = ''; @@ -10989,10 +10989,10 @@ function getElementProperties($element_type) ); - // Add pdfgeneration hook + // Add hook if (!is_object($hookmanager)) { include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; - $hookmanager = new HookManager($this->db); + $hookmanager = new HookManager($db); } $hookmanager->initHooks(array('elementproperties')); @@ -11014,8 +11014,8 @@ function getElementProperties($element_type) } // context of elementproperties doesn't need to exist out of this function so delete it to avoid elementproperties is equal to all - if (($key = array_search($this->contextarray, 'elementproperties')) !== false) { - unset($this->contextarray[$key]); + if (($key = array_search('elementproperties', $hookmanager->contextarray)) !== false) { + unset($hookmanager->contextarray[$key]); } return $element_properties; From 7f46bc21465cf4958328540aa28037b9e3296ee9 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Wed, 19 Jul 2023 16:35:14 +0200 Subject: [PATCH 28/28] Update htdocs/core/lib/functions.lib.php --- htdocs/core/lib/functions.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 6d9246af47423..2591a0263ec52 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -11003,7 +11003,7 @@ function getElementProperties($element_type) 'element_properties' => $element_properties ); - $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters); + $reshook = $hookmanager->executeHooks('getElementProperties', $parameters); if ($reshook) { $element_properties = $hookmanager->resArray;