• Модуль: disk
  • Путь к файлу: ~/bitrix/modules/disk/lib/bitrix24disk/legacy/newdiskstorage.php
  • Класс: BitrixDiskBitrix24DiskLegacyNewDiskStorage
  • Вызов: NewDiskStorage::snapshotFromLink
private function snapshotFromLink(TreeNode $link, FixedArray $items, PageState $pageState, $internalVersion, $pageSize = self::SNAPSHOT_PAGE_SIZE)
{
	$hasNextPage = false;
	$nextCursor = $nextId = null;
	$expectedFirstId = empty($dataByStep['lid'])? null : $dataByStep['lid'];
	$securityContext = $this->storage->getSecurityContext($this->userId);

	$query = new InternalsEntityQuery(ObjectTable::getEntity());
	$query
		->setSelect(['ID'])
		->addFilter('PATH_CHILD.PARENT_ID', $link->realObjectId)
		->addFilter('DELETED_TYPE', ObjectTable::DELETED_TYPE_NONE)
		->addFilter('=RIGHTS_CHECK', true)
		->registerRuntimeField(
			'RIGHTS_CHECK',
			new ExpressionField(
				'RIGHTS_CHECK',
				'CASE WHEN ' . $securityContext->getSqlExpressionForList('%1$s', '%2$s') . ' THEN 1 ELSE 0 END',
				array('ID', 'CREATED_BY')
			)
		)
		->addOrder('SYNC_UPDATE_TIME')
		->addOrder('ID')
//			->addOrder('PATH_CHILD.OBJECT_ID')
		->setLimit($pageSize + 1)
	;

	$cursor = $pageState->getCursor();
	if (
		!$cursor &&
		$internalVersion > 0 &&
		$this->compareVersion(
			$this->convertToExternalVersion($link->createDate->getTimestamp()),
			$this->convertToExternalVersion($internalVersion)
		) < 0
	)
	{
		$cursor = $internalVersion;
	}

	if($cursor > 0)
	{
		$query->addFilter('>=SYNC_UPDATE_TIME', DateTime::createFromTimestamp($cursor));
	}

	$offset = $pageState->getOffset();
	if ($cursor && $offset)
	{
		//we want to skip values which were on previous page.
		$query->setOffset($offset);
	}

	$objectIds = [];
	foreach ($query->exec() as $item)
	{
		$objectIds[] = $item['ID'];
		if ($expectedFirstId !== null && $item['ID'] != $expectedFirstId)
		{
			throw new UnexpectedNextIdException("{$expectedFirstId} vs {$item['ID']}");
		}
	}

	$fetchedItems = [];
	if ($objectIds)
	{
		$query = new InternalsEntityQuery(ObjectTable::getEntity());
		$query
			->setSelect($this->getSelectableColumnsForObject())
			->addFilter('@ID', $objectIds)
			->addOrder('SYNC_UPDATE_TIME')
			->addOrder('ID')
			->setLimit($pageSize + 1)
		;
		if ($this->isEnabledObjectLock)
		{
			$query->addSelect('LOCK.*', self::LOCK_PREFIX_IN_SELECT);
		}

		$fetchedItems = $query->exec()->fetchAll();
	}

	$count = 0;
	foreach($fetchedItems as $item)
	{
		if($count === 0)
		{
			if($expectedFirstId !== null && $item['ID'] != $expectedFirstId)
			{
				throw new UnexpectedNextIdException("{$expectedFirstId} vs {$item['ID']}");
			}

			$this->loadTree();
			$this->loadSharedData();
		}

		$count++;
		if($count > $pageSize)
		{
			$nextCursor = $item['SYNC_UPDATE_TIME']->getTimestamp();
			$nextId = $item['ID'];
			$hasNextPage = true;

			break;
		}

		$formattedItem = $this->formatObjectRowToResponse($item);
		if(
			!$formattedItem ||
			$formattedItem['path'] === '/' ||
			//this is root of symlink. We don't have to show it. We show only symlink.
			($link->realObjectId == $item['ID'] && $link->realObjectId == $item['REAL_OBJECT_ID'])
		)
		{
			$items->push(array(
				'version' => (string)$this->generateTimestamp($item['SYNC_UPDATE_TIME']->getTimestamp()),
			));
			//but we can have null on the page in snapshots. It's necessary for correct page navigation.
			continue;
		}

		$items->push($formattedItem);
	}

	$pageState->reset();
	if($hasNextPage)
	{
		$toSkipOnNextStep = 0;
		if($cursor == $nextCursor)
		{
			$toSkipOnNextStep += $offset;
		}

		$toSkipOnNextStep += $this->countIdsWithSameSyncDate($items, $this->convertToExternalVersion($nextCursor));
		if($toSkipOnNextStep)
		{
			$pageState->setOffset($toSkipOnNextStep);
		}

		$pageState
			->setStep($pageState::STEP_SYMLINKS)
			->setNextId($link->id)
			->setCursor($nextCursor)
			->setDataByStep(array(
				'lid' => $nextId
			))
		;
	}
}