From ab4f224a00685e90e2c7022c32bd6a6299d563be Mon Sep 17 00:00:00 2001 From: Molkobain Date: Wed, 6 Mar 2024 16:26:13 +0100 Subject: [PATCH 1/6] =?UTF-8?q?N=C2=B07315=20-=20Fix=20regression=20from?= =?UTF-8?q?=20previous=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sources/Application/WebPage/WebPage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/Application/WebPage/WebPage.php b/sources/Application/WebPage/WebPage.php index b0c576f47..61f8572d8 100644 --- a/sources/Application/WebPage/WebPage.php +++ b/sources/Application/WebPage/WebPage.php @@ -624,7 +624,7 @@ class WebPage implements Page break; case static::ENUM_RESOURCE_TYPE_CSS: - $this->a_linked_stylesheets[$sFileAbsURI] = $sFileAbsURI; + $this->a_linked_stylesheets[$sFileAbsURI] = ['link' => $sFileAbsURI, 'condition' => '']; break; } } From 17bab06ff5eacf97e2ffaaf2e744ee336ed3f79c Mon Sep 17 00:00:00 2001 From: Molkobain Date: Wed, 6 Mar 2024 18:40:47 +0100 Subject: [PATCH 2/6] =?UTF-8?q?N=C2=B07157=20-=20Migrate=20enum=20values?= =?UTF-8?q?=20from=20strings=20to=20PHP=20Enum?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/trigger.class.inc.php | 2 +- lib/composer/autoload_classmap.php | 1 + lib/composer/autoload_static.php | 1 + .../NotificationsCenterController.php | 15 ++++++++------- sources/Core/Trigger/Enum/SubscriptionPolicy.php | 16 ++++++++++++++++ .../Notification/NotificationsService.php | 3 ++- 6 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 sources/Core/Trigger/Enum/SubscriptionPolicy.php diff --git a/core/trigger.class.inc.php b/core/trigger.class.inc.php index 24a8ecb85..701333917 100644 --- a/core/trigger.class.inc.php +++ b/core/trigger.class.inc.php @@ -53,7 +53,7 @@ abstract class Trigger extends cmdbAbstractObject MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12))); // "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); - MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum('allow_no_channel,force_at_least_one_channel,force_all_channels'), "sql" => "subscription_policy", "default_value" => 'allow_no_channel', "is_null_allowed" => false, "depends_on" => array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(implode(",", Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases())), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel, "is_null_allowed" => false, "depends_on" => array()))); // Display lists MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index b7dc1b2dc..75334c1ce 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -417,6 +417,7 @@ return array( 'Combodo\\iTop\\Core\\Kpi\\KpiLogData' => $baseDir . '/sources/Core/Kpi/KpiLogData.php', 'Combodo\\iTop\\Core\\MetaModel\\FriendlyNameType' => $baseDir . '/sources/Core/MetaModel/FriendlyNameType.php', 'Combodo\\iTop\\Core\\MetaModel\\HierarchicalKey' => $baseDir . '/sources/Core/MetaModel/HierarchicalKey.php', + 'Combodo\\iTop\\Core\\Trigger\\Enum\\SubscriptionPolicy' => $baseDir . '/sources/Core/Trigger/Enum/SubscriptionPolicy.php', 'Combodo\\iTop\\DesignDocument' => $baseDir . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\DesignElement' => $baseDir . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\Form\\Field\\AbstractSimpleField' => $baseDir . '/sources/Form/Field/AbstractSimpleField.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index 5006a1900..6c8d92a98 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -792,6 +792,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Combodo\\iTop\\Core\\Kpi\\KpiLogData' => __DIR__ . '/../..' . '/sources/Core/Kpi/KpiLogData.php', 'Combodo\\iTop\\Core\\MetaModel\\FriendlyNameType' => __DIR__ . '/../..' . '/sources/Core/MetaModel/FriendlyNameType.php', 'Combodo\\iTop\\Core\\MetaModel\\HierarchicalKey' => __DIR__ . '/../..' . '/sources/Core/MetaModel/HierarchicalKey.php', + 'Combodo\\iTop\\Core\\Trigger\\Enum\\SubscriptionPolicy' => __DIR__ . '/../..' . '/sources/Core/Trigger/Enum/SubscriptionPolicy.php', 'Combodo\\iTop\\DesignDocument' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\DesignElement' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\Form\\Field\\AbstractSimpleField' => __DIR__ . '/../..' . '/sources/Form/Field/AbstractSimpleField.php', diff --git a/sources/Controller/Notifications/NotificationsCenterController.php b/sources/Controller/Notifications/NotificationsCenterController.php index d121af6bf..8520879dc 100644 --- a/sources/Controller/Notifications/NotificationsCenterController.php +++ b/sources/Controller/Notifications/NotificationsCenterController.php @@ -11,6 +11,7 @@ use Combodo\iTop\Application\UI\Base\Component\Input\Set\SetUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Panel\Panel; use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock; use Combodo\iTop\Application\WebPage\iTopWebPage; +use Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy; use Combodo\iTop\Renderer\BlockRenderer; use Combodo\iTop\Service\Notification\NotificationsRepository; use Combodo\iTop\Service\Router\Router; @@ -82,7 +83,7 @@ class NotificationsCenterController extends Controller // Add the action notification to the list of actions notifications for the trigger $oActionsNotificationsByTrigger[$iTriggerId][] = $oSubscribedActionNotification; // Add the subscribed status to the list of subscribed actions notifications for the trigger - $aSubscribedActionsNotificationsByTrigger[$iTriggerId][$oSubscribedActionNotification->GetKey()] = $oLnkActionsNotifications->Get('subscribed') || $oTrigger->Get('subscription_policy') === 'force_all_channels'; + $aSubscribedActionsNotificationsByTrigger[$iTriggerId][$oSubscribedActionNotification->GetKey()] = $oLnkActionsNotifications->Get('subscribed') || $oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels; } // Build table rows @@ -155,7 +156,7 @@ class NotificationsCenterController extends Controller $oChannelSet->SetOptionsTemplate('application/object/set/option_renderer.html.twig'); $oChannelSet->SetItemsTemplate('application/preferences/notification-center/item_renderer.html.twig'); // Disable the input set if the subscription policy is 'force_all_channels' - if($sTriggerSubscriptionPolicy === 'force_all_channels'){ + if ($sTriggerSubscriptionPolicy === SubscriptionPolicy::ForceAllChannels) { $oChannelSet->SetIsDisabled(true); } // Add a CSRF Token @@ -190,8 +191,8 @@ $.ajax({ }); JS ); - // Set the minimum number of channels to 1 if the subscription policy is 'force_at_least_one_channel' - if($sTriggerSubscriptionPolicy === 'force_at_least_one_channel') + // Set the minimum number of channels to 1 if the subscription policy is {@see SubscriptionPolicy::ForceAtLeastOneChannel} + if($sTriggerSubscriptionPolicy === SubscriptionPolicy::ForceAtLeastOneChannel) { $oChannelSet->SetMinItems(1); } @@ -289,7 +290,7 @@ JS // Add the action notification to the list of actions notifications for the trigger $oActionsNotificationsByTrigger[$iTriggerId][] = $oSubscribedActionNotification; // Add the subscribed status to the list of subscribed actions notifications for the trigger - $aSubscribedActionsNotificationsByTrigger[$iTriggerId][$oSubscribedActionNotification->GetKey()] = $oLnkActionsNotifications->Get('subscribed') || $oTrigger->Get('subscription_policy') === 'force_all_channels'; + $aSubscribedActionsNotificationsByTrigger[$iTriggerId][$oSubscribedActionNotification->GetKey()] = $oLnkActionsNotifications->Get('subscribed') || $oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels; } $oPage->AddTabContainer('NotificationsCenter', '', $oNotificationsPanel); @@ -491,7 +492,7 @@ JS throw new \Exception('Invalid trigger'); } // Check the trigger subscription policy - if($oTrigger->Get('subscription_policy') === 'force_all_channels'){ + if ($oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels) { throw new \Exception('You are not allowed to unsubscribe from this channel'); } @@ -501,7 +502,7 @@ JS throw new \Exception('You are not subscribed to any channel'); } // Check the trigger subscription policy and if we are subscribed to at least 1 channel if necessary - if($oTrigger->Get('subscription_policy') === 'force_at_least_one_channel') { + if($oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAtLeastOneChannel) { $oTotalSubscribedActionsNotificationsSet = NotificationsRepository::GetInstance()->SearchSubscriptionByTriggerContactAndSubscription($iTriggerId, \UserRights::GetContactId(), '1'); if (($oTotalSubscribedActionsNotificationsSet->Count() - $oSubscribedActionsNotificationsSet->Count()) === 0) { throw new \Exception('You can\'t unsubscribe from this channel, you must be subscribed to at least one channel'); diff --git a/sources/Core/Trigger/Enum/SubscriptionPolicy.php b/sources/Core/Trigger/Enum/SubscriptionPolicy.php new file mode 100644 index 000000000..67e46879b --- /dev/null +++ b/sources/Core/Trigger/Enum/SubscriptionPolicy.php @@ -0,0 +1,16 @@ + + * @package Combodo\iTop\Core\Trigger\Enum + * @since 3.2.0 + */ +enum SubscriptionPolicy: string { + case AllowNoChannel = "allow_no_channel"; + case ForceAtLeastOneChannel = "force_at_least_one_channel"; + case ForceAllChannels = "force_all_channels"; +} diff --git a/sources/Service/Notification/NotificationsService.php b/sources/Service/Notification/NotificationsService.php index 810e27b1c..8412a2dc6 100644 --- a/sources/Service/Notification/NotificationsService.php +++ b/sources/Service/Notification/NotificationsService.php @@ -3,6 +3,7 @@ namespace Combodo\iTop\Service\Notification; use ActionNotification; +use Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy; use Contact; use lnkActionNotificationToContact; use Trigger; @@ -99,7 +100,7 @@ class NotificationsService { public function IsSubscribed(Trigger $oTrigger, ActionNotification $oActionNotification, Contact $oRecipient): bool { // Check if the trigger subscription policy is 'force_all_channels' - if ($oTrigger->Get('subscription_policy') === 'force_all_channels') { + if ($oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels) { return true; } // Check if the user is already subscribed to the action notification From 02efea4e55ad820ebe5e0e954d7e670b9a4c9c1b Mon Sep 17 00:00:00 2001 From: Molkobain Date: Wed, 6 Mar 2024 19:31:17 +0100 Subject: [PATCH 3/6] =?UTF-8?q?N=C2=B07157=20-=20Migrate=20enum=20values?= =?UTF-8?q?=20from=20strings=20to=20PHP=20Enum?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/trigger.class.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/trigger.class.inc.php b/core/trigger.class.inc.php index 701333917..273b09794 100644 --- a/core/trigger.class.inc.php +++ b/core/trigger.class.inc.php @@ -53,7 +53,7 @@ abstract class Trigger extends cmdbAbstractObject MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12))); // "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); - MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(implode(",", Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases())), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel, "is_null_allowed" => false, "depends_on" => array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(implode(",", array_map(fn($case) => $case->value, Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases()))), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel, "is_null_allowed" => false, "depends_on" => array()))); // Display lists MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details From e05b4e772c3025fe0fd018d32fa45c2b57053940 Mon Sep 17 00:00:00 2001 From: Molkobain Date: Wed, 6 Mar 2024 23:05:16 +0100 Subject: [PATCH 4/6] =?UTF-8?q?N=C2=B07157=20-=20Fix=20usage=20of=20Enum?= =?UTF-8?q?=20case=20value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/trigger.class.inc.php | 2 +- core/valuesetdef.class.inc.php | 23 +++++++++++++++++++ .../NotificationsCenterController.php | 12 +++++----- .../Notification/NotificationsService.php | 2 +- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/core/trigger.class.inc.php b/core/trigger.class.inc.php index 273b09794..01242bc2e 100644 --- a/core/trigger.class.inc.php +++ b/core/trigger.class.inc.php @@ -53,7 +53,7 @@ abstract class Trigger extends cmdbAbstractObject MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12))); // "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); - MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(implode(",", array_map(fn($case) => $case->value, Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases()))), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel, "is_null_allowed" => false, "depends_on" => array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(implode(",", array_map(fn($case) => $case->value, Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases()))), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel->value, "is_null_allowed" => false, "depends_on" => array()))); // Display lists MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details diff --git a/core/valuesetdef.class.inc.php b/core/valuesetdef.class.inc.php index c32766b0f..21a7fb654 100644 --- a/core/valuesetdef.class.inc.php +++ b/core/valuesetdef.class.inc.php @@ -471,6 +471,29 @@ class ValueSetEnum extends ValueSetDefinition */ protected bool $bSortByValues; + /** + * @param string $sBackedEnumFQCN FQCN of the backed enum to use + * @param bool $bSortValues {@see static::$bSortValues} + * + * @return \ValueSetEnum ValueSetEnum based on the values of the $sBackedEnumFQCN backed enum + * @throws \CoreException + * @since 3.2.0 + */ + public static function FromBackedEnum(string $sBackedEnumFQCN, bool $bSortValues = false): ValueSetEnum + { + // First, check that we pass an enum as there is no generic type hint for that yet + if (false === enum_exists($sBackedEnumFQCN)) { + throw new CoreException("Can't instantiate " . __CLASS__ . "::" . __METHOD__ . " from a non-enum argument", [ + "argument" => $sBackedEnumFQCN + ]); + } + + // Implode cases + $sJoinedValues = implode(",", array_map(fn($case) => $case->value, $sBackedEnumFQCN::cases())); + + return new ValueSetEnum($sJoinedValues, $bSortValues); + } + /** * @param array|string $Values * @param bool $bLocalizedSort diff --git a/sources/Controller/Notifications/NotificationsCenterController.php b/sources/Controller/Notifications/NotificationsCenterController.php index 8520879dc..325715ffd 100644 --- a/sources/Controller/Notifications/NotificationsCenterController.php +++ b/sources/Controller/Notifications/NotificationsCenterController.php @@ -83,7 +83,7 @@ class NotificationsCenterController extends Controller // Add the action notification to the list of actions notifications for the trigger $oActionsNotificationsByTrigger[$iTriggerId][] = $oSubscribedActionNotification; // Add the subscribed status to the list of subscribed actions notifications for the trigger - $aSubscribedActionsNotificationsByTrigger[$iTriggerId][$oSubscribedActionNotification->GetKey()] = $oLnkActionsNotifications->Get('subscribed') || $oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels; + $aSubscribedActionsNotificationsByTrigger[$iTriggerId][$oSubscribedActionNotification->GetKey()] = $oLnkActionsNotifications->Get('subscribed') || $oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels->value; } // Build table rows @@ -156,7 +156,7 @@ class NotificationsCenterController extends Controller $oChannelSet->SetOptionsTemplate('application/object/set/option_renderer.html.twig'); $oChannelSet->SetItemsTemplate('application/preferences/notification-center/item_renderer.html.twig'); // Disable the input set if the subscription policy is 'force_all_channels' - if ($sTriggerSubscriptionPolicy === SubscriptionPolicy::ForceAllChannels) { + if ($sTriggerSubscriptionPolicy === SubscriptionPolicy::ForceAllChannels->value) { $oChannelSet->SetIsDisabled(true); } // Add a CSRF Token @@ -192,7 +192,7 @@ $.ajax({ JS ); // Set the minimum number of channels to 1 if the subscription policy is {@see SubscriptionPolicy::ForceAtLeastOneChannel} - if($sTriggerSubscriptionPolicy === SubscriptionPolicy::ForceAtLeastOneChannel) + if($sTriggerSubscriptionPolicy === SubscriptionPolicy::ForceAtLeastOneChannel->value) { $oChannelSet->SetMinItems(1); } @@ -290,7 +290,7 @@ JS // Add the action notification to the list of actions notifications for the trigger $oActionsNotificationsByTrigger[$iTriggerId][] = $oSubscribedActionNotification; // Add the subscribed status to the list of subscribed actions notifications for the trigger - $aSubscribedActionsNotificationsByTrigger[$iTriggerId][$oSubscribedActionNotification->GetKey()] = $oLnkActionsNotifications->Get('subscribed') || $oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels; + $aSubscribedActionsNotificationsByTrigger[$iTriggerId][$oSubscribedActionNotification->GetKey()] = $oLnkActionsNotifications->Get('subscribed') || $oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels->value; } $oPage->AddTabContainer('NotificationsCenter', '', $oNotificationsPanel); @@ -492,7 +492,7 @@ JS throw new \Exception('Invalid trigger'); } // Check the trigger subscription policy - if ($oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels) { + if ($oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels->value) { throw new \Exception('You are not allowed to unsubscribe from this channel'); } @@ -502,7 +502,7 @@ JS throw new \Exception('You are not subscribed to any channel'); } // Check the trigger subscription policy and if we are subscribed to at least 1 channel if necessary - if($oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAtLeastOneChannel) { + if($oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAtLeastOneChannel->value) { $oTotalSubscribedActionsNotificationsSet = NotificationsRepository::GetInstance()->SearchSubscriptionByTriggerContactAndSubscription($iTriggerId, \UserRights::GetContactId(), '1'); if (($oTotalSubscribedActionsNotificationsSet->Count() - $oSubscribedActionsNotificationsSet->Count()) === 0) { throw new \Exception('You can\'t unsubscribe from this channel, you must be subscribed to at least one channel'); diff --git a/sources/Service/Notification/NotificationsService.php b/sources/Service/Notification/NotificationsService.php index 8412a2dc6..4beecfc13 100644 --- a/sources/Service/Notification/NotificationsService.php +++ b/sources/Service/Notification/NotificationsService.php @@ -100,7 +100,7 @@ class NotificationsService { public function IsSubscribed(Trigger $oTrigger, ActionNotification $oActionNotification, Contact $oRecipient): bool { // Check if the trigger subscription policy is 'force_all_channels' - if ($oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels) { + if ($oTrigger->Get('subscription_policy') === SubscriptionPolicy::ForceAllChannels->value) { return true; } // Check if the user is already subscribed to the action notification From 8e8d586dcc0b34ebd1a64cd182e82af9b442218d Mon Sep 17 00:00:00 2001 From: Molkobain Date: Thu, 7 Mar 2024 11:02:23 +0100 Subject: [PATCH 5/6] =?UTF-8?q?N=C2=B07157=20-=20Add=20support=20for=20bac?= =?UTF-8?q?ked-enum=20in=20\ValueSetEnum=20constructor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/trigger.class.inc.php | 2 +- core/valuesetdef.class.inc.php | 38 +++----- .../core/ValueSetEnum/ABCEnum.php | 13 +++ .../unitary-tests/core/ValueSetEnumTest.php | 90 +++++++++++++++++++ 4 files changed, 116 insertions(+), 27 deletions(-) create mode 100644 tests/php-unit-tests/unitary-tests/core/ValueSetEnum/ABCEnum.php create mode 100644 tests/php-unit-tests/unitary-tests/core/ValueSetEnumTest.php diff --git a/core/trigger.class.inc.php b/core/trigger.class.inc.php index 01242bc2e..ba193b773 100644 --- a/core/trigger.class.inc.php +++ b/core/trigger.class.inc.php @@ -53,7 +53,7 @@ abstract class Trigger extends cmdbAbstractObject MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12))); // "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); - MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(implode(",", array_map(fn($case) => $case->value, Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases()))), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel->value, "is_null_allowed" => false, "depends_on" => array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases()), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel->value, "is_null_allowed" => false, "depends_on" => array()))); // Display lists MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details diff --git a/core/valuesetdef.class.inc.php b/core/valuesetdef.class.inc.php index 21a7fb654..44733976d 100644 --- a/core/valuesetdef.class.inc.php +++ b/core/valuesetdef.class.inc.php @@ -471,34 +471,12 @@ class ValueSetEnum extends ValueSetDefinition */ protected bool $bSortByValues; - /** - * @param string $sBackedEnumFQCN FQCN of the backed enum to use - * @param bool $bSortValues {@see static::$bSortValues} - * - * @return \ValueSetEnum ValueSetEnum based on the values of the $sBackedEnumFQCN backed enum - * @throws \CoreException - * @since 3.2.0 - */ - public static function FromBackedEnum(string $sBackedEnumFQCN, bool $bSortValues = false): ValueSetEnum - { - // First, check that we pass an enum as there is no generic type hint for that yet - if (false === enum_exists($sBackedEnumFQCN)) { - throw new CoreException("Can't instantiate " . __CLASS__ . "::" . __METHOD__ . " from a non-enum argument", [ - "argument" => $sBackedEnumFQCN - ]); - } - - // Implode cases - $sJoinedValues = implode(",", array_map(fn($case) => $case->value, $sBackedEnumFQCN::cases())); - - return new ValueSetEnum($sJoinedValues, $bSortValues); - } - /** * @param array|string $Values * @param bool $bLocalizedSort * * @since 3.1.0 N°1646 Add $bLocalizedSort parameter + * @since 3.2.0 N°7157 $Values can be an array of backed-enum cases */ public function __construct($Values, bool $bSortByValues = false) { @@ -546,13 +524,21 @@ class ValueSetEnum extends ValueSetDefinition */ protected function LoadValues($aArgs) { + $aValues = []; if (is_array($this->m_values)) { - $aValues = $this->m_values; + foreach ($this->m_values as $value) { + // Handle backed-enum case + if (is_object($value) && enum_exists(get_class($value))) { + $aValues[] = $value->value; + continue; + } + + $aValues[] = $value; + } } elseif (is_string($this->m_values) && strlen($this->m_values) > 0) { - $aValues = array(); foreach (explode(",", $this->m_values) as $sVal) { $sVal = trim($sVal); @@ -562,7 +548,7 @@ class ValueSetEnum extends ValueSetDefinition } else { - $aValues = array(); + $aValues = []; } $this->m_aValues = $aValues; return true; diff --git a/tests/php-unit-tests/unitary-tests/core/ValueSetEnum/ABCEnum.php b/tests/php-unit-tests/unitary-tests/core/ValueSetEnum/ABCEnum.php new file mode 100644 index 000000000..4e8be881b --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/core/ValueSetEnum/ABCEnum.php @@ -0,0 +1,13 @@ + + * @package Combodo\iTop\Test\UnitTest\Core + * @coves \ValueSetEnum + */ +class ValueSetEnumTest extends ItopTestCase +{ + public static function setupBeforeClass(): void + { + require_once __DIR__ . "/ValueSetEnum/ABCEnum.php"; + } + + /** + * @dataProvider LoadValuesProvider + * + * @param mixed $input + * @param array $aExpectedValues + * @param bool $bIsInputBackedEnum + * + * @return void + */ + public function testLoadValues(mixed $input, array $aExpectedValues, bool $bIsInputBackedEnum = false): void + { + if ($bIsInputBackedEnum) { + $input = $input::cases(); + } + $oValueSetEnum = new ValueSetEnum($input); + $aTestedValues = $oValueSetEnum->GetValues([]); + + $this->assertEquals($aExpectedValues, $aTestedValues, "Values should be the same and ordered the same way"); + } + + public function LoadValuesProvider(): array + { + return [ + "CSV list, trimmed values, already ordered" => [ + "a,b,c", + [ + "a" => "a", + "b" => "b", + "c" => "c", + ], + ], + "CSV list, values to trim, already ordered" => [ + "a, b ,c ", + [ + "a" => "a", + "b" => "b", + "c" => "c", + ], + ], + "Array, already ordered" => [ + ["a", "b", "c"], + [ + 0 => "a", + 1 => "b", + 2 => "c", + ], + ], + "Backed-Enum" => [ + ABCEnum::class, + [ + 0 => "a", + 1 => "b", + 2 => "c", + ], + true, // Is the input value a backed enum? + ], + "Invalid int value" => [ + 123, + [], + ] + ]; + } +} \ No newline at end of file From da490739be2b8eb957aea2fa8ade3bf16fecc13b Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 7 Mar 2024 11:10:53 +0100 Subject: [PATCH 6/6] :bulb: Fix \CMDBSource::Query phpdoc block --- core/cmdbsource.class.inc.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/cmdbsource.class.inc.php b/core/cmdbsource.class.inc.php index 07a1767d7..e65496cd0 100644 --- a/core/cmdbsource.class.inc.php +++ b/core/cmdbsource.class.inc.php @@ -674,10 +674,9 @@ class CMDBSource /** * @param string $sSQLQuery * - * @return \mysqli_result|null - * @throws \MySQLException - * @throws \MySQLHasGoneAwayException - * @throws \CoreException + * @return mysqli_result|null + * @throws MySQLException + * @throws MySQLHasGoneAwayException * * @since 2.7.0 N°679 handles nested transactions */