From 46d5e873b3c7f55708a23ceee0e7ddd2994d22cc Mon Sep 17 00:00:00 2001 From: hipot Date: Fri, 9 Aug 2024 18:10:47 +0300 Subject: [PATCH] Now IblockAbstractLayer has numeric property ID in phpDocs. introduced a new method in EventHelper.php for setting property values efficiently. Added `secondsToTimeString` and `timeToIso8601Duration` functions in DateTimeUtils.php for better time conversion (it's need to rewrite, todos) Add methods to clean unused basket properties on events Integrated two event handlers in `handlers_add.php` to trigger the cleanup of unused basket properties upon adding an item to the basket and upon saving an order. Also, implemented the `deleteUnUsedBasketProps` method in `Sale.php` to execute the actual deletion in the database. --- lib/classes/Hipot/BitrixUtils/Sale.php | 25 +++++++ .../GenerateSxem/IblockGenerateSxem.php | 8 +-- lib/classes/Hipot/Utils/EventHelper.php | 30 ++++++++ .../Hipot/Utils/Helper/DateTimeUtils.php | 71 +++++++++++++++++++ lib/handlers_add.php | 21 ++++++ 5 files changed, 151 insertions(+), 4 deletions(-) diff --git a/lib/classes/Hipot/BitrixUtils/Sale.php b/lib/classes/Hipot/BitrixUtils/Sale.php index e888a0f..92c5f39 100644 --- a/lib/classes/Hipot/BitrixUtils/Sale.php +++ b/lib/classes/Hipot/BitrixUtils/Sale.php @@ -241,4 +241,29 @@ public static function orderHasPayedInHistory(int $orderId): bool } return false; } + + /** + * Deletes unused basket properties from the database (event handler) + * + * @param bool|int $basketId The ID of the basket to delete unused properties from. Optional, defaults to false. + * + * @return void + */ + public static function deleteUnUsedBasketProps($basketId = false): void + { + global $DB; + + $nps = []; + foreach (\App::NEED_BASKET_PROPERTY as $np) { + $nps[] = "\"" . $np . "\""; + } + + /** @noinspection SqlNoDataSourceInspection */ + /** @noinspection SqlResolve */ + $sqlDelUnusedProps = + 'delete from b_sale_basket_props where ' . + //'delete from b_sale_basket_props WHERE BASKET_ID = ' . (int)$ID . ' AND ' . + 'CODE NOT IN ('.implode(', ',$nps).')'; + $DB->Query($sqlDelUnusedProps); + } } \ No newline at end of file diff --git a/lib/classes/Hipot/IbAbstractLayer/GenerateSxem/IblockGenerateSxem.php b/lib/classes/Hipot/IbAbstractLayer/GenerateSxem/IblockGenerateSxem.php index 5278344..faf8cb3 100644 --- a/lib/classes/Hipot/IbAbstractLayer/GenerateSxem/IblockGenerateSxem.php +++ b/lib/classes/Hipot/IbAbstractLayer/GenerateSxem/IblockGenerateSxem.php @@ -117,7 +117,7 @@ class __IblockElementItem_#ABSTRACT_LAYER_SAULT#_#IBLOCK_CODE#_#IBLOCK_ID# exten */ private string $oneRowPropertytemplate = ' /** - * #PROPERTY_TITLE# + * #PROPERTY_TITLE# (ID: #PROPERTY_ID#) * @var #PROPERTY_TYPE# */ public $#PROPERTY_CODE#; @@ -133,7 +133,7 @@ class __IblockElementItem_#ABSTRACT_LAYER_SAULT#_#IBLOCK_CODE#_#IBLOCK_ID# exten */ private string $multipleRowPropertyTemplate = ' /** - * #PROPERTY_TITLE# + * #PROPERTY_TITLE# (ID: #PROPERTY_ID#) * @var array[#PROPERTY_TYPE#] * @var #PROPERTY_TYPE#[] */ @@ -557,8 +557,8 @@ public function generate(): bool $temp = ($prop['MULTIPLE'] != 'Y') ? $this->oneRowPropertytemplate : $this->multipleRowPropertyTemplate; $outPropsIter .= str_replace( - ['#PROPERTY_TITLE#', '#PROPERTY_CODE#', '#PROPERTY_TYPE#'], - [$prop['NAME'], $prop['CODE'], $propType], + ['#PROPERTY_TITLE#', '#PROPERTY_CODE#', '#PROPERTY_ID#', '#PROPERTY_TYPE#'], + [$prop['NAME'], $prop['CODE'], $prop['ID'], $propType], $temp ); } diff --git a/lib/classes/Hipot/Utils/EventHelper.php b/lib/classes/Hipot/Utils/EventHelper.php index 02b2bed..424d0c7 100644 --- a/lib/classes/Hipot/Utils/EventHelper.php +++ b/lib/classes/Hipot/Utils/EventHelper.php @@ -28,4 +28,34 @@ public static function getIblockEventPropValue($propIdx) } return false; } + + /** + * Удобно использовать в событиях инфоблока для задания значений без сдвига массива + * $arFields['PROPERTY_VALUES'][107][ ??? - 1259|0|n0 ]['VALUE'] = $newValue; + *
+	 * setIblockEventPropValue($arFields['PROPERTY_VALUES'][107], 'test')
+	 * 
+ * + * @param array $propIdx The array index containing the property. + * @param mixed $newValue The new value to set. + * + * @return void + */ + public static function setIblockEventPropValue(&$propIdx, $newValue): void + { + if (is_array($propIdx)) { + $k = array_keys($propIdx); + if (isset($propIdx[ $k[0] ]['VALUE'])) { + $propIdx[ $k[0] ]['VALUE'] = $newValue; + } else { + $propIdx[ $k[0] ] = $newValue; + } + } else { + $propIdx = [ + 'n0' => [ + 'VALUE' => $newValue, + ] + ]; + } + } } \ No newline at end of file diff --git a/lib/classes/Hipot/Utils/Helper/DateTimeUtils.php b/lib/classes/Hipot/Utils/Helper/DateTimeUtils.php index fbb3c11..ac74aef 100644 --- a/lib/classes/Hipot/Utils/Helper/DateTimeUtils.php +++ b/lib/classes/Hipot/Utils/Helper/DateTimeUtils.php @@ -6,6 +6,8 @@ */ namespace Hipot\Utils\Helper; +use Hipot\Utils\UUtils; + trait DateTimeUtils { /** @@ -48,4 +50,73 @@ public static function timestampToSeason(\DateTimeInterface $dateTime): string } return 'Fall'; } + + /** + * Утилитарная функция для красивого вывода периода (в секундах) в дни, часы, минуты и секунды + * + * @param integer $duration Длительность периода в секундах + * @return string + */ + public static function secondsToTimeString($duration): string + { + $timeStrings = array(); + + $converted = [ + 'days' => floor($duration / (3600 * 24)), + 'hours' => floor($duration / 3600), + 'minutes' => floor(($duration / 60) % 60), + 'seconds' => ($duration % 60) + ]; + + if ($converted['days'] > 0) { + $timeStrings[] = $converted['days'] . ' ' . UUtils::Suffix($converted['days'], 'день|дня|дней'); + } + + if ($converted['hours'] > 0) { + $timeStrings[] = $converted['hours'] . ' ' . UUtils::Suffix($converted['hours'], 'час|часа|часов'); + } + if ($converted['minutes'] > 0) { + $timeStrings[] = $converted['minutes'] . ' мин.'; + } + if ($converted['seconds'] > 0) { + $timeStrings[] = $converted['seconds'] . ' сек.'; + } + + if(!empty($timeStrings)) { + return implode(' ', $timeStrings); + } + + return ' 0 секунд'; + } + + /** + * @param int $time seconds + * @return string + * @see https://en.wikipedia.org/wiki/ISO_8601#Durations + */ + public static function timeToIso8601Duration(int $time): string + { + $units = [ + "Y" => 365*24*3600, + "D" => 24*3600, + "H" => 3600, + "M" => 60, + "S" => 1, + ]; + $str = "P"; + $istime = false; + foreach ($units as $unitName => &$unit) { + $quot = (int)($time / $unit); + $time -= $quot * $unit; + $unit = $quot; + if ($unit > 0) { + if (!$istime && in_array($unitName, ["H", "M", "S"])) { // There may be a better way to do this + $str .= "T"; + $istime = true; + } + $str .= $unit . $unitName; + } + } + return $str; + } } \ No newline at end of file diff --git a/lib/handlers_add.php b/lib/handlers_add.php index eb7b93a..5c7a0d9 100644 --- a/lib/handlers_add.php +++ b/lib/handlers_add.php @@ -9,6 +9,7 @@ use Bitrix\Main\Loader; use Bitrix\Main\EventManager; +use Bitrix\Main\Event; use Bitrix\Main\Application; use Bitrix\Main\Web\HttpClient; use Bitrix\Main\Composite\Page as CompositePage; @@ -217,3 +218,23 @@ static function (&$this_al) { $eventManager->addEventHandler('', 'CustomSettingsOnAfterAdd', [HiBlockApps::class, 'clearCustomSettingsCacheHandler']); $eventManager->addEventHandler('', 'CustomSettingsOnAfterDelete', [HiBlockApps::class, 'clearCustomSettingsCacheHandler']); +// region очистка из корзины ненужных свойств (при добавлении товара из админки) +$eventManager->addEventHandler("sale", "OnBasketAdd", static function ($ID, $arFields) { + Hipot\BitrixUtils\Sale::deleteUnUsedBasketProps($ID); +}); +$eventManager->addEventHandler( + 'sale', + 'OnSaleOrderSaved', + static function (Event $event) { + /** @var \Bitrix\Sale\Order $order */ + $order = $event->getParameter("ENTITY"); + + if (isset($GLOBALS['deletedOrderUnusedProps_' . $order->getId()])) { + return; + } + + Hipot\BitrixUtils\Sale::deleteUnUsedBasketProps(); + $GLOBALS['deletedOrderUnusedProps_' . $order->getId()] = true; + } +); +// endregion \ No newline at end of file