• Модуль: calendar
  • Путь к файлу: ~/bitrix/modules/calendar/classes/general/calendar_event.php
  • Класс: CCalendarEvent
  • Вызов: CCalendarEvent::Edit
static function Edit($params = [])
{
	global $DB, $CACHE_MANAGER;
	$entryFields = $params['arFields'] ?? [];
	$arAffectedSections = [];
	$entryChanges = [];
	$sendInvitations = ($params['sendInvitations'] ?? null) !== false;
	$sendEditNotification = ($params['sendEditNotification'] ?? null) !== false;
	$checkLocationOccupancy = ($params['checkLocationOccupancy'] ?? null) === true;
	$checkLocationOccupancyFields = $params['checkLocationOccupancyFields'] ?? null;
	$result = false;

	// Get current user id
	$userId = (isset($params['userId']) && (int)$params['userId'] > 0)
		? (int)$params['userId']
		: CCalendar::GetCurUserId();

	if (!$userId && isset($entryFields['CREATED_BY']))
	{
		$userId = (int)$entryFields['CREATED_BY'];
	}

	$isNewEvent = !isset($entryFields['ID']) || !$entryFields['ID'];
	$entryFields['TIMESTAMP_X'] = CCalendar::Date(time(), true, false);

	// Current event
	$currentEvent = [];
	if (!empty($entryFields['IS_MEETING']) && !isset($entryFields['ATTENDEES']) && isset($entryFields['ATTENDEES_CODES']))
	{
		$entryFields['ATTENDEES'] = CCalendar::getDestinationUsers($entryFields['ATTENDEES_CODES']);
	}

	if (!$isNewEvent)
	{
		$currentEvent = $params['currentEvent'] ?? self::GetById($entryFields['ID'], $params['checkPermission'] ?? true);

		if (!isset($entryFields['LOCATION']) || !is_array($entryFields['LOCATION']))
		{
			$entryFields['LOCATION'] = [
				'NEW' => $entryFields['LOCATION'] ?? null
			];
		}

		if (
			isset($entryFields['MEETING'])
			&& is_array($entryFields['MEETING'])
			&& is_array($currentEvent['MEETING'])
                && !isset($entryFields['MEETING']['CHAT_ID'])
                && isset($currentEvent['MEETING']['CHAT_ID'])
		)
		{
			$entryFields['MEETING']['CHAT_ID'] = $currentEvent['MEETING']['CHAT_ID'];
		}

		if (empty($entryFields['LOCATION']['OLD']))
		{
			$entryFields['LOCATION']['OLD'] = $currentEvent['LOCATION'] ?? null;
		}

		if (
			!empty($currentEvent['IS_MEETING']) && !isset($entryFields['ATTENDEES'])
			&& $currentEvent['PARENT_ID'] === $currentEvent['ID']
			&& !empty($entryFields['IS_MEETING'])
		)
		{
			$entryFields['ATTENDEES'] = [];
			$attendees = self::GetAttendees($currentEvent['PARENT_ID']);
			if (!empty($attendees[$currentEvent['PARENT_ID']]))
			{
				$attendeesCount = count($attendees[$currentEvent['PARENT_ID']]);
				for ($i = 0; $i < $attendeesCount; $i++)
				{
					$entryFields['ATTENDEES'][] = $attendees[$currentEvent['PARENT_ID']][$i]['USER_ID'];
				}
			}
		}

		if (!empty($currentEvent['PARENT_ID']))
		{
			$entryFields['PARENT_ID'] = (int)$currentEvent['PARENT_ID'];
		}
	}

	if (self::CheckFields($entryFields, $currentEvent, $userId))
	{
		$attendees = (isset($entryFields['ATTENDEES']) && is_array($entryFields['ATTENDEES']))
                ? $entryFields['ATTENDEES']
                : [];
		if (
                ($entryFields['CAL_TYPE'] ?? null) !== RoomsManager::TYPE
			&& (empty($entryFields['PARENT_ID']) || $entryFields['PARENT_ID'] === $entryFields['ID'])
		)
		{
			$fromTs = $entryFields['DATE_FROM_TS_UTC'] ?? null;
			$toTs = $entryFields['DATE_TO_TS_UTC'] ?? null;
			if (($entryFields['DT_SKIP_TIME'] ?? null) !== "Y")
			{
				$fromTs += (int)date('Z', $fromTs);
				$toTs += (int)date('Z', $toTs);
			}

			$entryFields['LOCATION'] = self::checkLocationField($entryFields['LOCATION'] ?? null, $isNewEvent);

			if ($checkLocationOccupancy)
			{
				$fieldsToCheckOccupancy = $entryFields;
				if (!empty($params['checkLocationOccupancyFields']))
				{
					$fieldsToCheckOccupancy = $params['checkLocationOccupancyFields'];
					$fieldsToCheckOccupancy['LOCATION'] = [
						'NEW' => $checkLocationOccupancyFields['LOCATION'] ?? ''
					];
					self::CheckFields($fieldsToCheckOccupancy, $currentEvent, $userId);
				}
				$occupancyCheckResult = (new RoomsOccupancyChecker())->check($fieldsToCheckOccupancy);
				if (!$occupancyCheckResult->isSuccess())
				{
					$disturbingEventsFormatted = $occupancyCheckResult->getData()['disturbingEventsFormatted'];
					if ($occupancyCheckResult->getData()['isDisturbingEventsAmountOverShowLimit'])
					{
						$message = Loc::getMessage(
							'EC_LOCATION_REPEAT_BUSY_TOO_MANY',
							['#DATES#' => $disturbingEventsFormatted]
						);
					}
					else
					{
						$message = Loc::getMessage(
							'EC_LOCATION_REPEAT_BUSY',
							['#DATES#' => $disturbingEventsFormatted]
						);
					}
					throw new RoomsOccupancyCheckerException($message);
				}
			}

			$entryFields['LOCATION'] = BitrixCalendarRoomsUtil::setLocation(
				$entryFields['LOCATION']['OLD'],
				$entryFields['LOCATION']['NEW'],
				[
					// UTC timestamp + date('Z', $timestamp) /*offset of the server*/
					'dateFrom' => CCalendar::Date($fromTs, $entryFields['DT_SKIP_TIME'] !== "Y"),
					'dateTo' => CCalendar::Date($toTs, $entryFields['DT_SKIP_TIME'] !== "Y"),
					'parentParams' => $params,
					'name' => $entryFields['NAME'],
					'persons' => count($attendees),
					'attendees' => $attendees,
					'bRecreateReserveMeetings' => ($entryFields['LOCATION']['RE_RESERVE'] ?? null) !== 'N',
					'checkPermission' => $params['checkPermission'] ?? null,
				]
			);
		}
		else
		{
			$entryFields['LOCATION'] = self::checkLocationField($entryFields['LOCATION'], $isNewEvent);
			$entryFields['LOCATION'] = $entryFields['LOCATION']['NEW'];
		}

		// Section
		if (isset($entryFields['SECTION_ID']))
		{
			$sectionId = (int)$entryFields['SECTION_ID'];
		}
		else
		{
			$sectionId = !empty($entryFields['SECTIONS'][0])
                    ? (int)$entryFields['SECTIONS'][0]
				: false;
		}

		if (!$sectionId)
		{
			// It's new event we have to find section where to put it automatically
			if ($isNewEvent)
			{
				if (
					!empty($entryFields['IS_MEETING'])
					&& !empty($entryFields['PARENT_ID'])
					&& ($entryFields['CAL_TYPE'] ?? null) === 'user'
				)
				{
					$sectionId = CCalendar::GetMeetingSection($entryFields['OWNER_ID'] ?? null);
				}
				else
				{
					$sectionId = CCalendarSect::GetLastUsedSection(
                            $entryFields['CAL_TYPE'] ?? null,
                            $entryFields['OWNER_ID'] ?? null,
                            $userId);
				}

				if ($sectionId)
				{
					$res = CCalendarSect::GetList([
						'arFilter' => [
							'CAL_TYPE' => $entryFields['CAL_TYPE'] ?? null,
							'OWNER_ID' => $entryFields['OWNER_ID'] ?? null,
							'ID'=> $sectionId
						]
					]);

					if (empty($res[0]))
					{
						$sectionId = false;
					}
				}
				else
				{
					$sectionId = false;
				}

				if (empty($sectionId))
				{
					$sectRes = CCalendarSect::GetSectionForOwner($entryFields['CAL_TYPE'], $entryFields['OWNER_ID'], true);
					$sectionId = $sectRes['sectionId'];
				}
			}
			else
			{
				$sectionId = $currentEvent['SECTION_ID'] ?? $currentEvent['SECT_ID'];
			}
		}
		$entryFields['SECTION_ID'] = $sectionId;
		$arAffectedSections[] = $sectionId;

		$section = CCalendarSect::GetList(['arFilter' => ['ID' => $sectionId],
			'checkPermissions' => false,
			'getPermissions' => false
		])[0] ?? null;

		// Here we take type and owner parameters from section data
		if ($section)
		{
			$entryFields['CAL_TYPE'] = $section['CAL_TYPE'];
			$entryFields['OWNER_ID'] = $section['OWNER_ID'] ?? '';
		}

		if (($entryFields['CAL_TYPE'] ?? null) === 'user')
		{
			$CACHE_MANAGER->ClearByTag('calendar_user_'.$entryFields['OWNER_ID']);
		}

		if ($isNewEvent)
		{
			if (!isset($entryFields['CREATED_BY']))
			{
				$entryFields['CREATED_BY'] = (
                        !empty($entryFields['IS_MEETING'])
					&& ($entryFields['CAL_TYPE'] ?? null) === 'user'
					&& !empty($entryFields['OWNER_ID'])
                    ) ? $entryFields['OWNER_ID'] : $userId;
			}

			if (!isset($entryFields['DATE_CREATE']))
			{
				$entryFields['DATE_CREATE'] = $entryFields['TIMESTAMP_X'];
			}
		}
		else
		{
			$arAffectedSections[] = $currentEvent['SECTION_ID'] ?? $currentEvent['SECT_ID'];
		}

		if (
			!isset($entryFields['IS_MEETING'])
			&& isset($entryFields['ATTENDEES'])
			&& is_array($entryFields['ATTENDEES'])
			&& empty($entryFields['ATTENDEES'])
		)
		{
			$entryFields['IS_MEETING'] = false;
		}
		if (!empty($entryFields['IS_MEETING']) && !$isNewEvent)
		{
			$entryChanges = self::CheckEntryChanges($entryFields, $currentEvent);
		}

		$attendeesCodes = $entryFields['ATTENDEES_CODES'] ?? null;
		if (is_array($attendeesCodes))
		{
			$entryFields['ATTENDEES_CODES'] = implode(',', $attendeesCodes);
		}

		if (
                !isset($entryFields['MEETING_STATUS'])
			&& !empty($entryFields['MEETING_HOST'])
                && (int)$entryFields['MEETING_HOST'] === (int)($entryFields['CREATED_BY'] ?? null)
		)
		{
			$entryFields['MEETING_STATUS'] = 'H';
		}
		else if (!isset($entryFields['MEETING_STATUS']) && !$currentEvent)
		{
			$entryFields['MEETING_STATUS'] = 'Y';
		}

		if (isset($entryFields['MEETING']) && is_array($entryFields['MEETING']))
		{
			$entryFields['~MEETING'] = $entryFields['MEETING'];
			$entryFields['MEETING']['REINVITE'] = false;
			$meetingHostSettings = UserSettings::get($entryFields['MEETING_HOST'] ?? null);
			$entryFields['MEETING']['MAIL_FROM'] = $meetingHostSettings['sendFromEmail'] ?? null;
			$entryFields['MEETING'] = serialize($entryFields['MEETING']);
		}

		if (isset($entryFields['RELATIONS']) && is_array($entryFields['RELATIONS']))
		{
			$entryFields['~RELATIONS'] = $entryFields['RELATIONS'];
			$entryFields['RELATIONS'] = serialize($entryFields['RELATIONS']);
		}

		if (
			isset($entryFields['REMIND'])
			&& (
				$isNewEvent
				|| !$entryFields['IS_MEETING']
				|| (int)$entryFields['CREATED_BY'] === $userId
				|| ($params['updateReminders'] ?? null) === true
			)
		)
		{
			$reminderList = CCalendarReminder::prepareReminder($entryFields['REMIND']);
		}
		elseif (!empty($currentEvent['REMIND']))
		{
			$reminderList = CCalendarReminder::prepareReminder($currentEvent['REMIND']);
		}
		else
		{
			$reminderList = [];
		}
		$entryFields['REMIND'] = serialize($reminderList);

		if (
			isset($entryFields['SYNC_STATUS'])
			&& !in_array($entryFields['SYNC_STATUS'],BitrixCalendarSyncGoogleDictionary::SYNC_STATUS, true)
		)
		{
			$entryFields['SYNC_STATUS'] = null;
		}

		if (isset($entryFields['EXDATE']) && is_array($entryFields['EXDATE']))
		{
			$entryFields['EXDATE'] = implode(';', $entryFields['EXDATE']);
		}
		$entryFields['EXDATE'] = !empty($entryFields['EXDATE'])
			? self::convertExDatesToInternalFormat($entryFields['EXDATE'])
			: ''
		;

		$entryFields['RRULE'] = self::convertRuleUntilToInternalFormat($entryFields['RRULE'] ?? null);

		$AllFields = self::GetFields();
		$dbFields = [];

		foreach($entryFields as $field => $val)
		{
			if (
				isset($AllFields[$field])
				&& $field !== "ID"
				&& is_scalar($val)
			)
			{
				$dbFields[$field] = $val;
			}
		}

		if (!empty($dbFields['NAME']))
		{
			$dbFields['NAME'] = Emoji::encode($dbFields['NAME']);
		}
		if (!empty($dbFields['DESCRIPTION']))
		{
			$dbFields['DESCRIPTION'] = Emoji::encode($dbFields['DESCRIPTION']);
		}
		if (!empty($dbFields['LOCATION']))
		{
			$dbFields['LOCATION'] = Emoji::encode($dbFields['LOCATION']);
		}

		CTimeZone::Disable();

		if ($isNewEvent) // Add
		{
			$eventId = $DB->Add("b_calendar_event", $dbFields, ['DESCRIPTION', 'MEETING', 'EXDATE']);
		}
		else // Update
		{
			$eventId = $entryFields['ID'];
			$strUpdate = $DB->PrepareUpdate("b_calendar_event", $dbFields);
			$strSql =
				"UPDATE b_calendar_event SET ".
					$strUpdate.
					" WHERE ID=". (int)$eventId;

			$DB->QueryBind($strSql, array(
				'DESCRIPTION' => Emoji::encode($entryFields['DESCRIPTION'] ?? ''),
				'MEETING' => $entryFields['MEETING'] ?? null,
				'EXDATE' => $entryFields['EXDATE'] ?? null
			));
		}

		CTimeZone::Enable();

		if (
			$userId
			&& $params
			&& ($params['overSaving'] ?? null) !== true
			&& BitrixCalendarSyncUtilRequestLogger::isEnabled()
		)
		{
			$loggerParams = $params;
			$loggerParams['arFields'] = $entryFields;
			$loggerParams['loggerUuid'] = $eventId;

			(new BitrixCalendarSyncUtilRequestLogger($userId, 'portal_edit'))->write($loggerParams);
		}

		if ($isNewEvent && !isset($dbFields['DAV_XML_ID']))
		{
			$strSql =
				"UPDATE b_calendar_event SET ".
					$DB->PrepareUpdate("b_calendar_event", ['DAV_XML_ID' => (int)$eventId]).
					" WHERE ID = ". (int)$eventId;
			$DB->Query($strSql, false, "File: ".__FILE__."
Line: ".__LINE__); } // Deprecated. Now connection saved in the table if ( !Util::isSectionStructureConverted() && ($isNewEvent || $sectionId !== $currentEvent['SECTION_ID'])) { self::ConnectEventToSection($eventId, $sectionId); } if (!empty($arAffectedSections)) { CCalendarSect::UpdateModificationLabel($arAffectedSections); } if ( !empty($entryFields['IS_MEETING']) || (!$isNewEvent && !empty($currentEvent['IS_MEETING'])) ) { if (empty($entryFields['PARENT_ID'])) { $DB->Query("UPDATE b_calendar_event SET ".$DB->PrepareUpdate("b_calendar_event", array("PARENT_ID" => $eventId))." WHERE ID=". (int)$eventId, false, "FILE: ".__FILE__."
LINE: ".__LINE__); } $mailEvent = ICalUtil::isMailUser($entryFields['MEETING_HOST'] ?? null); if ((empty($entryFields['PARENT_ID']) || $entryFields['PARENT_ID'] === $eventId) && !$mailEvent) { self::CreateChildEvents($eventId, $entryFields, $params, $entryChanges); } if ((empty($entryFields['PARENT_ID']) || $entryFields['PARENT_ID'] === $eventId) && !empty($entryFields['RECURRENCE_ID'])) { self::UpdateParentEventExDate($entryFields['RECURRENCE_ID'], $entryFields['ORIGINAL_DATE_FROM'], $entryFields['ATTENDEES']); } if (empty($entryFields['PARENT_ID'])) { $entryFields['PARENT_ID'] = (int)$eventId; } } else if (($isNewEvent && empty($entryFields['PARENT_ID'])) || (!$isNewEvent && empty($currentEvent['PARENT_ID']))) { $DB->Query("UPDATE b_calendar_event SET ".$DB->PrepareUpdate("b_calendar_event", array("PARENT_ID" => $eventId))." WHERE ID=".intval($eventId), false, "FILE: ".__FILE__."
LINE: ".__LINE__); if (empty($entryFields['PARENT_ID'])) { $entryFields['PARENT_ID'] = (int)$eventId; } } // Update reminders for event CCalendarReminder::updateReminders([ 'id' => $eventId, 'reminders' => $reminderList, 'arFields' => $entryFields, 'userId' => $userId, 'path' => $params['path'] ?? null ]); // Update search index self::updateSearchIndex($eventId, ['userId' => $userId]); $nowUtc = time() - date('Z'); // Send invitations and notifications if ( !empty($entryFields['IS_MEETING']) && ($params['overSaving'] ?? null) !== true ) { $fromTo = self::GetEventFromToForUser($entryFields, $entryFields['OWNER_ID'] ?? null); // If it's event in the past we're skipping notifications. // The past is the past... if (isset($entryFields['DATE_TO_TS_UTC']) && $entryFields['DATE_TO_TS_UTC'] > $nowUtc) { if ( $sendEditNotification && (int)($entryFields['PARENT_ID'] ?? null) !== (int)$eventId && !empty($entryChanges) && ( ($entryFields['MEETING_STATUS'] ?? null) === 'Y' || ($entryFields['MEETING_STATUS'] ?? null) === 'H' ) ) { // third problematic place if ( (!empty($entryFields['MEETING_HOST']) && (int)$entryFields['MEETING_HOST'] === (int)$userId) || self::checkAttendeeBelongsToEvent($entryFields['PARENT_ID'] ?? null, $userId) ) { $CACHE_MANAGER->ClearByTag('calendar_user_'.$entryFields['OWNER_ID']); CCalendarNotify::Send([ 'mode' => 'change_notify', 'name' => $entryFields['NAME'] ?? null, "from" => $fromTo['DATE_FROM'] ?? null, "to" => $fromTo['DATE_TO'] ?? null, "location" => CCalendar::GetTextLocation($entryFields["LOCATION"] ?? null), "guestId" => $entryFields['OWNER_ID'] ?? null, "eventId" => $entryFields['PARENT_ID'] ?? null, "userId" => $userId, "fields" => $entryFields, "isSharing" => ($entryFields['EVENT_TYPE'] ?? null) === Dictionary::EVENT_TYPE['shared'], "entryChanges" => $entryChanges ]); } } elseif ( (int)($entryFields['PARENT_ID'] ?? null) !== $eventId && ($entryFields['MEETING_STATUS'] ?? null) === 'Q' && $sendInvitations ) { $CACHE_MANAGER->ClearByTag('calendar_user_'.$entryFields['OWNER_ID'] ?? ''); CCalendarNotify::Send(array( "mode" => 'invite', "name" => $entryFields['NAME'] ?? null, "from" => $fromTo['DATE_FROM'] ?? null, "to" => $fromTo['DATE_TO'] ?? null, "location" => CCalendar::GetTextLocation($entryFields["LOCATION"] ?? null), "guestId" => $entryFields['OWNER_ID'] ?? null, "eventId" => $entryFields['PARENT_ID'] ?? null, "userId" => $userId, "isSharing" => ($entryFields['EVENT_TYPE'] ?? null) === Dictionary::EVENT_TYPE['shared'], "fields" => $entryFields )); } } } if ( !empty($entryFields['IS_MEETING']) && !empty($entryFields['ATTENDEES_CODES']) && (int)($entryFields['PARENT_ID'] ?? null) === (int)$eventId && ($params['overSaving'] ?? null) !== true && isset($entryFields['DATE_TO_TS_UTC']) && $entryFields['DATE_TO_TS_UTC'] > $nowUtc ) { CCalendarLiveFeed::OnEditCalendarEventEntry([ 'eventId' => $eventId, 'arFields' => $entryFields, 'attendeesCodes' => $attendeesCodes ]); } CCalendar::ClearCache('event_list'); $result = $eventId; if (!empty($entryFields['LOCATION'])) { RoomsManager::setEventIdForLocation($eventId); } if ($isNewEvent) { foreach(EventManager::getInstance()->findEventHandlers("calendar", "OnAfterCalendarEntryAdd") as $event) { ExecuteModuleEventEx( $event, [ $eventId, $entryFields, [] ] ); } if (($entryFields['PARENT_ID'] ?? null) === $eventId && $entryFields['CAL_TYPE'] !== 'location') { Bitrix24Manager::increaseEventsAmount(); } } else { foreach(EventManager::getInstance()->findEventHandlers("calendar", "OnAfterCalendarEntryUpdate") as $event) { ExecuteModuleEventEx( $event, [ $eventId, $entryFields, $currentEvent['ATTENDEE_LIST'] ?? null ] ); } } $pullUserId = (isset($entryFields['CREATED_BY']) && (int)($entryFields['CREATED_BY'] ?? null) > 0) ? (int)$entryFields['CREATED_BY'] : $userId; if ( $pullUserId > 0 && ($params['overSaving'] ?? null) !== true ) { $entryFields = self::calculateUserOffset($pullUserId, $entryFields); Util::addPullEvent( 'edit_event', $pullUserId, [ 'fields' => $entryFields, 'newEvent' => $isNewEvent, 'requestUid' => $params['requestUid'] ?? null ] ); } } return $result; }