1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
C:/bitrix/modules/learning/classes/general/clearnlesson.php

Lists immediate parents.

Аргументы
integerid of lesson
Возвращает
array of immediate parents (empty array if there is no parents)

<?php $arParents = ThisClass::ListImmediateNeighbours (1); var _dump ($arParents); ?>

output: array(2) { [0]=> array(4) { ["PARENT_LESSON"]=> int(1) ["CHILD_LESSON"]=> int(2) ["SORT"]=> int(500) } [1]=> array(4) { ["PARENT_LESSON"]=> int(4) ["CHILD_LESSON"]=> int(1) ["SORT"]=> int(500) } }

<?php
interface ILearnLesson
{
public static function Add ($arFields, $isCourse = false,
$parentLessonId = true, $arProperties = array('SORT' => 500));
public static function Update ($id, $arFields);
public static function Delete ($id);
public static function DeleteRecursiveLikeHardlinks ($id);
public static function GetByIDAsArr($id);
public static function GetByID($id);
public static function GetList($arOrder = array(), $arFilter = array());
public static function GetListOfImmediateParents($lessonId, $arOrder = array(), $arFilter = array(), $arSelectFields = array());
public static function GetListOfImmediateChilds($lessonId, $arOrder = array(), $arFilter = array(), $arSelectFields = array());
public static function ListImmediateParents($lessonId);
public static function ListImmediateChilds($lessonId);
public static function ListImmediateNeighbours($lessonId);
public static function GetLinkedCourse ($lessonId);
public static function GetTree (
$lessonId,
$arOrder = array ('EDGE_SORT' => 'asc'),
$publishProhibitionMode = true
);
public static function RelationAdd ($parentLessonId, $childLessonId, $arProperties);
public static function RelationUpdate ($parentLessonId, $childLessonId, $arProperties);
public static function RelationGet ($parentLessonId, $childLessonId);
public static function RelationRemove ($parentLessonId, $childLessonId);
public static function CountImmediateChilds ($lessonId);
public static function GetListOfParentPathes ($lessonId, $breakOnLessonId = false,
$breakBeforeLessonId = false, $arIgnoreEdges = array());
public static function IsPublishProhibited ($lessonId, $contextCourseLessonId);
public static function PublishProhibitionSetTo ($lessonId, $contextCourseLessonId, $isProhibited);
}
class CLearnLesson implements ILearnLesson
{
const GET_LIST_ALL = 0x0; // List any lessons
const GET_LIST_IMMEDIATE_CHILDS_OF = 0x1; // List only immediate childs of requested parent_lesson_id
const GET_LIST_IMMEDIATE_PARENTS_OF = 0x2; // List only immediate parents of requested parent_lesson_id
// PUBLISH_PROHIBITION_PURGE_* constants can be ORed
// Purge all prohibitions where given lessonId is contextCourse
// Purge all prohibitions for lessonId in all contextCourses
// Purge all prohibitions for given lessonId (as course, and as prohibited lesson)
final public static function Add ($arFields,
$isCourse = false,
$parentLessonId = true,
$arProperties = array('SORT' => 500),
$isCheckPermissions = true,
$checkPermissionsForUserId = -1 // -1 means - for current logged user
)
{
$isAccessGranted = false;
if ($isCheckPermissions)
{
array('user_id' => $checkPermissionsForUserId)
)
)
{
if ($parentLessonId === true)
{
// we don't need to link lesson to parent,
// so permissions check is complete
$isAccessGranted = true;
}
else
{
// We must check, is user have access to link lesson to some parent
'parent_lesson_id' => $parentLessonId,
'user_id' => $checkPermissionsForUserId
)
)
)
{
$isAccessGranted = true;
}
}
}
}
else
$isAccessGranted = true; // don't check permissions
if ( ! $isAccessGranted )
{
throw new LearnException(
'EA_ACCESS_DENIED',
}
// If lesson is course, there is can be additional params, which must be extracted
if ($isCourse)
{
// Additional fields will be removed from $arFields by this method
}
if ( ! $USER_FIELD_MANAGER->CheckFields('LEARNING_LESSONS', 0, $arFields) )
return (false);
foreach(GetModuleEvents('learning', 'OnBeforeLessonAdd', true) as $arEvent)
if (
( ! isset($arFields['NAME']) )
|| ($arFields['NAME'] == '')
)
{
$lessonId = false;
$arMsg = array(array("id"=>"NAME", "text"=> GetMessage("LEARNING_BAD_NAME")));
$e = new CAdminException($arMsg);
$GLOBALS["APPLICATION"]->ThrowException($e);
}
else
if ($lessonId)
{
$USER_FIELD_MANAGER->Update('LEARNING_LESSONS', $lessonId, $arFields);
if ($isCourse)
{
// Convert lesson to course
self::BecomeCourse ($lessonId, $arCourseFields);
}
else
{
// Link to parent lesson, if need
if ($parentLessonId !== true)
self::RelationAdd ($parentLessonId, $lessonId, $arProperties);
}
}
$arFields['LESSON_ID'] = $lessonId;
foreach(GetModuleEvents('learning', 'OnAfterLessonAdd', true) as $arEvent)
if (!$isCourse)
{
\Bitrix\Learning\Integration\Search::indexLesson($lessonId);
}
return ($lessonId);
}
protected static function _ExtractAdditionalCourseFields (&$arFields)
{
$arCourseFields = array();
if (array_key_exists('SORT', $arFields)
&& ( ! array_key_exists('COURSE_SORT', $arFields))
)
{
// If SORT given, but COURSE_SORT not given => COURSE_SORT = SORT
$arFields['COURSE_SORT'] = $arFields['SORT'];
// So, if both SORT and COURSE_SORT are exists => SORT ignored.
}
// We must unset course-related fields
if (array_key_exists('SORT', $arFields))
unset ($arFields['SORT']);
$additionalParams = array ('COURSE_SORT', 'ACTIVE_FROM',
'ACTIVE_TO', 'RATING', 'RATING_TYPE', 'SCORM');
foreach ($additionalParams as $paramName)
{
if (array_key_exists($paramName, $arFields))
{
$arCourseFields[$paramName] = $arFields[$paramName];
unset ($arFields[$paramName]); // We must unset course-related fields
}
}
return ($arCourseFields);
}
protected static function _CanonizeAndCheckAdditionalParamsForAddCourse ($arFields, $forUpdate = false)
{
if ( ! is_array($arFields) )
throw new LearnException ('EA_PARAMS', LearnException::EXC_ERR_ALL_PARAMS);
$arAllowedFields = array ('COURSE_SORT', 'ACTIVE_FROM', 'ACTIVE_TO', 'RATING', 'RATING_TYPE', 'SCORM');
if ( ! $forUpdate )
{
$defaultsValues = array (
'COURSE_SORT' => 500,
'ACTIVE_FROM' => NULL,
'ACTIVE_TO' => NULL,
'RATING' => 'N',
'RATING_TYPE' => NULL,
'SCORM' => 'N'
);
// set defaults values, if need
foreach ($defaultsValues as $fieldName => $defaultValue)
{
if ( ! array_key_exists($fieldName, $arFields) )
$arFields[$fieldName] = $defaultValue;
}
}
// check for admitted regions (do all checks only if not forUpdate mode OR in forUpdate mode and field given):
// COURSE_SORT
if ( ( ! $forUpdate) || array_key_exists('COURSE_SORT', $arFields) )
// ACTIVE_FROM
if ( ( ! $forUpdate) || isset($arFields['ACTIVE_FROM']) )
{
if ( ($arFields['ACTIVE_FROM'] !== NULL)
&& ( ! is_string($arFields['ACTIVE_FROM']) )
)
{
throw new LearnException ('EA_PARAMS', LearnException::EXC_ERR_ALL_PARAMS);
}
}
// ACTIVE_TO
if ( ( ! $forUpdate) || isset($arFields['ACTIVE_TO']) )
{
if ( ($arFields['ACTIVE_TO'] !== NULL)
&& ( ! is_string($arFields['ACTIVE_TO']) )
)
{
throw new LearnException ('EA_PARAMS', LearnException::EXC_ERR_ALL_PARAMS);
}
}
// RATING
if ( ( ! $forUpdate) || array_key_exists('RATING', $arFields) )
{
if ($arFields['RATING'] === '')
$arFields['RATING'] = NULL;
if ( ! in_array ($arFields['RATING'], array ('Y', 'N', NULL), true) )
throw new LearnException ('EA_PARAMS: RATING is ' . $arFields['RATING'], LearnException::EXC_ERR_ALL_PARAMS);
}
// RATING_TYPE
if ( ( ! $forUpdate) || array_key_exists('RATING_TYPE', $arFields) )
{
if ( ($arFields['RATING_TYPE'] !== NULL)
&&
( ! in_array (
$arFields['RATING_TYPE'],
array ('like', 'standart_text', 'like_graphic', 'standart'),
true)
)
)
{
throw new LearnException ('EA_PARAMS', LearnException::EXC_ERR_ALL_PARAMS);
}
}
// SCORM
if ( ( ! $forUpdate) || array_key_exists('SCORM', $arFields) )
{
if ( ! in_array ($arFields['SCORM'], array ('Y', 'N'), true) )
throw new LearnException ('EA_PARAMS', LearnException::EXC_ERR_ALL_PARAMS);
}
// Return only exists fields (some fields may be omitted in case $forUpdate = true)
$rc = array();
foreach ($arAllowedFields as $fieldName)
{
if (array_key_exists($fieldName, $arFields))
$rc[$fieldName] = $arFields[$fieldName];
}
return ($rc);
}
final public static function Update ($id, $arFields)
{
if ( isset($arFields['ACTIVE'])
&& ( ! is_bool($arFields['ACTIVE']) )
)
{
if ($arFields['ACTIVE'] === 'Y')
$arFields['ACTIVE'] = true;
else
$arFields['ACTIVE'] = false;
}
if ( ! $USER_FIELD_MANAGER->CheckFields('LEARNING_LESSONS', $id, $arFields) )
return (false);
$courseId = self::GetLinkedCourse ($id);
// if lesson is course, extract additional fields of course
if ($courseId !== false)
{
// Additional fields will be removed from $arFields by this method
}
foreach(GetModuleEvents('learning', 'OnBeforeLessonUpdate', true) as $arEvent)
if (
array_key_exists('NAME', $arFields)
&& ($arFields['NAME'] == '')
)
{
$lessonId = false;
$arMsg = array(array("id"=>"NAME", "text"=> GetMessage("LEARNING_BAD_NAME")));
$e = new CAdminException($arMsg);
$GLOBALS["APPLICATION"]->ThrowException($e);
return(false);
}
$USER_FIELD_MANAGER->Update('LEARNING_LESSONS', $id, $arFields);
// Update main lesson data
// If lesson is course, update course-specific data
if ($courseId !== false)
{
// LearnException will be throwed on invalid params
$arCourseFields = self::_CanonizeAndCheckAdditionalParamsForAddCourse ($arCourseFields, true); // forUpdate = true
$arFieldsToDb = array();
if (array_key_exists('COURSE_SORT', $arCourseFields))
$arFieldsToDb['SORT'] = "'" . (int) ($arCourseFields['COURSE_SORT'] + 0) . "'";
if (array_key_exists('ACTIVE_FROM', $arCourseFields))
{
if (($arCourseFields['ACTIVE_FROM'] === NULL) || ($arCourseFields['ACTIVE_FROM'] === ''))
$arFieldsToDb['ACTIVE_FROM'] = 'NULL';
else
$arFieldsToDb['ACTIVE_FROM'] = $DB->CharToDateFunction($arCourseFields['ACTIVE_FROM']);
}
if (array_key_exists('ACTIVE_TO', $arCourseFields))
{
if (($arCourseFields['ACTIVE_TO'] === NULL) || ($arCourseFields['ACTIVE_TO'] === ''))
$arFieldsToDb['ACTIVE_TO'] = 'NULL';
else
$arFieldsToDb['ACTIVE_TO'] = $DB->CharToDateFunction($arCourseFields['ACTIVE_TO']);
}
if (array_key_exists('RATING', $arCourseFields))
$arFieldsToDb['RATING'] = "'" . $DB->ForSql($arCourseFields['RATING']) . "'";
if (array_key_exists('RATING_TYPE', $arCourseFields))
{
if ($arCourseFields['RATING_TYPE'] === NULL)
$arFieldsToDb['RATING_TYPE'] = 'NULL';
else
$arFieldsToDb['RATING_TYPE'] = "'" . $DB->ForSql($arCourseFields['RATING_TYPE']) . "'";
}
if (array_key_exists('SCORM', $arCourseFields))
$arFieldsToDb['SCORM'] = "'" . $DB->ForSql($arCourseFields['SCORM']) . "'";
// Does need update for some fields?
if (count($arFieldsToDb) > 0)
{
$rc = $DB->Update ('b_learn_course', $arFieldsToDb,
"WHERE ID='" . (int) ($courseId + 0) . "'", __LINE__, false,
false); // we must halt on errors due to bug in CDatabase::Update();
// reload cache of LINKED_LESSON_ID -> COURSE_ID
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
}
}
foreach(GetModuleEvents('learning', 'OnAfterLessonUpdate', true) as $arEvent)
\Bitrix\Learning\Integration\Search::indexLesson($id);
return true;
}
protected static function _funcDelete_ParseOptions($lesson_id)
{
$simulate = false; // don't simulate by default
$check_permissions = true; // check rights by default
$user_id = -1; // -1 means 'current logged user'
if (is_array($lesson_id))
{
// Parse options
$lesson_id,
'lesson_id' => array(
'type' => 'strictly_castable_to_integer',
'mandatory' => true
),
'simulate' => array(
'type' => 'boolean',
'mandatory' => false,
'default_value' => $simulate
),
'check_permissions' => array(
'type' => 'boolean',
'mandatory' => false,
'default_value' => $check_permissions
),
'user_id' => array(
'type' => 'strictly_castable_to_integer',
'mandatory' => false,
'default_value' => $user_id
)
)
);
$lesson_id = $options['lesson_id'];
$simulate = $options['simulate'];
$check_permissions = $options['check_permissions'];
$user_id = $options['user_id'];
}
else
$lesson_id = (int) $lesson_id;
if ($check_permissions)
{
if ($user_id === -1)
{
global $USER;
if ( ! (is_object($USER) && method_exists($USER, 'GetID')) )
{
throw new LearnException(
'EA_OTHER: $USER isn\'t available.',
}
$user_id = (int) $USER->GetID();
}
}
return (array($lesson_id, $simulate, $check_permissions, $user_id));
}
final public static function DeleteRecursiveLikeHardlinks ($in_data)
{
list ($root_lesson_id, $simulate, $check_permissions, $user_id) =
// list of lessons, which are candidates to be removed
$arCandidatesToRemove = array();
// Build list of all descendants (excluded duplicated)
$oTree = self::GetTree($root_lesson_id);
$arDescendantsList = $oTree->GetLessonsIdListInTree();
// Transform list: add list of immediate parents to every candidate
foreach ($arDescendantsList as $lesson_id)
{
$arParents = array();
$arEdges = self::ListImmediateParents($lesson_id);
foreach ($arEdges as $arEdgeData)
$arParents[] = (int) $arEdgeData['PARENT_LESSON'];
$arCandidatesToRemove[(int) $lesson_id] = $arParents;
}
// Now, move out parents of root lesson, because they mustn't be checked below.
$arCandidatesToRemove[$root_lesson_id] = array();
// Withdraw lessons, which has ancestors not among candidates to be removed
do
{
$lessonsWithdrawn = 0; // count of withdrawn lessons
foreach ($arCandidatesToRemove as $lesson_id => $arParents)
{
// Check that all parents are from candidates to be removed;
// otherwise $lesson_id must be withdrew from candidates
foreach ($arParents as $parent_lesson_id)
{
if ( ! array_key_exists((int) $parent_lesson_id, $arCandidatesToRemove) )
{
unset($arCandidatesToRemove[(int) $lesson_id]);
$lessonsWithdrawn++;
break; // we don't need to check other parents for this lesson anymore
}
}
}
}
while ($lessonsWithdrawn > 0);
// Now, broke edges and remove lessons.
// Broke edges to lessons in $arCandidatesToRemove list only.
foreach ($arCandidatesToRemove as $lesson_id => $arParents)
{
try
{
'lesson_id' => $lesson_id,
'simulate' => $simulate,
'check_permissions' => $check_permissions,
'user_id' => $user_id
)
);
}
catch (LearnException $e)
{
; // course cannot be removed - ignore this error
{
// if lesson not exists - ignore error (lesson to be deleted is already removed)
$rsLesson = self::GetListUni(
array(),
array('LESSON_ID' => $lesson_id, 'CHECK_PERMISSIONS' => 'N'),
array('LESSON_ID'),
self::GET_LIST_ALL
);
if ( ! $rsLesson->fetch() )
{
; // ignore this situation, it's OK
}
else
{
// bubble exception
throw new LearnException ($e->GetMessage(), $e->GetCode());
}
}
else
{
// bubble exception
throw new LearnException ($e->GetMessage(), $e->GetCode());
}
}
}
}
final public static function Delete ($lesson_id)
{
list ($lesson_id, $simulate, $check_permissions, $user_id) =
if ($check_permissions)
{
if ( ! $oAccess->IsLessonAccessible($lesson_id, CLearnAccess::OP_LESSON_REMOVE) )
{
throw new LearnException(
'EA_ACCESS_DENIED',
}
}
// Parents and childs of the lesson
$arNeighboursEdges = self::ListImmediateNeighbours ($lesson_id);
// precache rights for lesson
if ($check_permissions)
{
$IsLessonAccessibleFor_OP_LESSON_UNLINK_DESCENDANTS =
$oAccess->IsLessonAccessible($lesson_id, CLearnAccess::OP_LESSON_UNLINK_DESCENDANTS);
$IsLessonAccessibleFor_OP_LESSON_UNLINK_FROM_PARENTS =
$oAccess->IsLessonAccessible($lesson_id, CLearnAccess::OP_LESSON_UNLINK_FROM_PARENTS);
}
foreach(GetModuleEvents('learning', 'OnBeforeLessonDelete', true) as $arEvent)
ExecuteModuleEventEx($arEvent, array($lesson_id));
foreach ($arNeighboursEdges as $arEdge)
{
$child_lesson_id = (int) $arEdge['CHILD_LESSON'];
$parent_lesson_id = (int) $arEdge['PARENT_LESSON'];
if ($check_permissions)
{
$IsLessonAccessible = false;
if ($child_lesson_id === $lesson_id)
{
// if we will be remove edge to parent - use precached rights for OP_LESSON_UNLINK_FROM_PARENTS
$IsLessonAccessible = $IsLessonAccessibleFor_OP_LESSON_UNLINK_FROM_PARENTS
&& $oAccess->IsLessonAccessible($parent_lesson_id, CLearnAccess::OP_LESSON_UNLINK_DESCENDANTS);
}
elseif ($parent_lesson_id === $lesson_id)
{
// if we will be remove edge to child - use precached rights for OP_LESSON_UNLINK_DESCENDANTS
$IsLessonAccessible = $IsLessonAccessibleFor_OP_LESSON_UNLINK_DESCENDANTS
&& $oAccess->IsLessonAccessible($child_lesson_id, CLearnAccess::OP_LESSON_UNLINK_FROM_PARENTS);
}
else
{
throw new LearnException(
'EA_FATAL: $lesson_id (' . $lesson_id
. ') not equal to one of: $child_lesson_id ('
. $child_lesson_id . '), $parent_lesson_id ('
. $parent_lesson_id . ')',
}
if ( ! $IsLessonAccessible )
{
throw new LearnException(
'EA_ACCESS_DENIED',
}
if ($simulate === false)
self::RelationRemove ($parent_lesson_id, $child_lesson_id);
}
}
$linkedCourseId = self::GetLinkedCourse ($lesson_id);
// If lesson is course, remove course
if ($linkedCourseId !== false)
{
global $DB;
if ($simulate === false)
{
if ( ! $DB->Query("DELETE FROM b_learn_course_site WHERE COURSE_ID = " . (int) $linkedCourseId, true) )
throw new LearnException ( 'EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
$rc = self::CourseBecomeLesson ($linkedCourseId);
// if course cannot be converted to lesson - don't remove lesson
if ($rc === false)
{
throw new LearnException (
'EA_OTHER: lesson is unremovable because linked course is in use.',
}
// reload cache of LINKED_LESSON_ID -> COURSE_ID
}
}
// And remove lesson
if ($simulate === false)
{
global $DB;
$r = $DB->Query(
"SELECT PREVIEW_PICTURE, DETAIL_PICTURE
FROM b_learn_lesson
WHERE ID = " . (int) $lesson_id,
true);
if ($r === false)
{
throw new LearnException(
'EA_SQLERROR',
}
$arRes = $r->Fetch();
if ( ! $arRes )
{
throw new LearnException(
'EA_SQLERROR',
}
CFile::Delete($arRes['PREVIEW_PICTURE']);
CFile::Delete($arRes['DETAIL_PICTURE']);
// Remove questions
array(),
array('LESSON_ID' => $lesson_id)
);
while($arQ = $q->Fetch())
{
if ( ! CLQuestion::Delete($arQ['ID']) )
{
throw new LearnException(
'EA_QUESTION_NOT_REMOVED',
}
}
$USER_FIELD_MANAGER->delete('LEARNING_LESSONS', $lesson_id);
CEventLog::add(array(
'AUDIT_TYPE_ID' => 'LEARNING_REMOVE_ITEM',
'MODULE_ID' => 'learning',
'ITEM_ID' => 'L #' . $lesson_id,
'DESCRIPTION' => 'lesson removed'
));
if (CModule::IncludeModule('search'))
{
CSearch::deleteIndex("learning", "U\\_%", "L".$lesson_id, null);
}
}
if ($simulate === false)
{
foreach(GetModuleEvents('learning', 'OnAfterLessonDelete', true) as $arEvent)
ExecuteModuleEventEx($arEvent, array($lesson_id));
}
}
final public static function GetByID($id)
{
return (self::GetList(array(), array('LESSON_ID' => $id)));
}
final public static function GetByIDAsArr($id)
{
global $DB;
$arData = CLearnGraphNode::GetByID($id);
// If lesson is course - get additional data
$courseId = self::GetLinkedCourse ($id);
if ($courseId !== false)
{
$rc = $DB->Query (
"SELECT SORT, ACTIVE_FROM, ACTIVE_TO, RATING, RATING_TYPE, SCORM
FROM b_learn_course
WHERE ID = '" . (int) ($courseId + 0) . "'",
true // ignore errors
);
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
$arCourseData = $rc->Fetch();
if ( ($arCourseData === false) || ( ! isset($arCourseData['SORT']) ) )
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
$arData = array_merge($arData, $arCourseData);
}
// convert return data to expected form
if ( isset($arData['ACTIVE'])
&& is_bool($arData['ACTIVE'])
)
{
if ($arData['ACTIVE'])
$arData['ACTIVE'] = 'Y';
else
$arData['ACTIVE'] = 'N';
}
$arData['LESSON_ID'] = $arData['ID'];
return ($arData);
}
final public static function GetLinkedCourse ($lessonId)
{
if ( ! isset($arMap['L' . $lessonId]) )
return (false); // no corresponded course
// return id of corresponded course
return ($arMap['L' . $lessonId]);
}
final public static function GetCourseToLessonMap($bRefreshCache = false)
{
static $arMap = array();
$bCacheHit = false;
static $ttl = 1800; // seconds
static $cacheId = 'fixed_cache_id';
static $cachePath = '/learning/coursetolessonmap/';
$oCache = new CPHPCache();
// Try to load from cache only if cache isn't dirty
if ( ! $bRefreshCache )
{
if ($oCache->InitCache($ttl, $cacheId, $cachePath))
{
$arCached = $oCache->GetVars();
if (isset($arCached['arMap']) && is_array($arCached['arMap']))
{
$arMap = $arCached['arMap'];
$bCacheHit = true;
}
}
}
// Reload map from DB on cache miss or when cache is dirty
if (( ! $bCacheHit ) || $bRefreshCache)
{
$oCache->CleanDir($cachePath);
$oCache->InitCache($ttl, $cacheId, $cachePath);
$oCache->StartDataCache($ttl, $cacheId, $cachePath);
$oCache->EndDataCache(array('arMap' => $arMap));
}
return ($arMap);
}
protected static function GetCourseToLessonMap_ReloadCache()
{
$bRefreshCache = true;
self::GetCourseToLessonMap($bRefreshCache);
}
protected static function GetCourseToLessonMap_LoadFromDB()
{
global $DB;
$arMap = array();
$rc = $DB->Query (
"SELECT ID, LINKED_LESSON_ID
FROM b_learn_course
WHERE 1 = 1",
true // ignore errors
);
if ($rc === false)
{
throw new LearnException (
'EA_SQLERROR',
}
while ($arData = $rc->Fetch())
{
// skip invalid elements
if ( ($arData['ID'] <= 0) || ($arData['LINKED_LESSON_ID'] <= 0) )
continue;
$arMap['C' . $arData['ID']] = (int) $arData['LINKED_LESSON_ID'];
$arMap['L' . $arData['LINKED_LESSON_ID']] = (int) $arData['ID'];
}
return ($arMap);
}
protected static function BecomeCourse ($lessonId, $arFields)
{
global $DB;
// LearnException will be throwed on invalid params
$ACTIVE_FROM = $ACTIVE_TO = 'NULL';
if (($arCourseFields['ACTIVE_FROM'] !== NULL) && ($arCourseFields['ACTIVE_FROM'] !== ''))
$ACTIVE_FROM = $DB->CharToDateFunction($arCourseFields['ACTIVE_FROM']);
if (($arCourseFields['ACTIVE_TO'] !== NULL) && ($arCourseFields['ACTIVE_TO'] !== ''))
$ACTIVE_TO = $DB->CharToDateFunction($arCourseFields['ACTIVE_TO']);
$arFieldsToDb = array(
'LINKED_LESSON_ID' => "'" . (int) ($lessonId + 0) . "'",
'SORT' => "'" . (int) ($arCourseFields['COURSE_SORT'] + 0) . "'",
'ACTIVE_FROM' => $ACTIVE_FROM,
'ACTIVE_TO' => $ACTIVE_TO,
'RATING' => "'" . $DB->ForSql($arCourseFields['RATING']) . "'",
'RATING_TYPE' => ( ($arCourseFields['RATING_TYPE'] === NULL) ? 'NULL' : ("'" . $DB->ForSql($arCourseFields['RATING_TYPE']) . "'") ),
'SCORM' => "'" . $DB->ForSql($arCourseFields['SCORM']) . "'"
);
$rc = $DB->Insert ('b_learn_course',
$arFieldsToDb,
__LINE__, // $error_position
false, // $debug
"", // $exist_id
false // $ignore_errors, we must halt on errors due to bug in CDatabase::Insert();
);
// reload cache of LINKED_LESSON_ID -> COURSE_ID
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
return ( (int) $rc); // returns course_id
}
protected static function CourseBecomeLesson ($courseId)
{
global $DB;
$linkedLessonId = CCourse::CourseGetLinkedLesson ($courseId);
if ($linkedLessonId === false)
{
return false;
}
// Check certificates (if exists => forbid removing course)
$certificate = CCertification::GetList(Array(), Array("COURSE_ID" => $courseId, 'CHECK_PERMISSIONS' => 'N'));
if ( ($certificate === false) || ($certificate->GetNext()) )
return false;
// Remove tests
$tests = CTest::GetList(Array(), Array("COURSE_ID" => $courseId));
if ($tests === false)
return (false);
while ($arTest = $tests->Fetch())
{
if ( ! CTest::Delete($arTest["ID"]) )
return false;
}
// Remove all prohibitions for lessons in context of course to be removed
// and remove prohibitions for course to be removed in context of all other courses
$linkedLessonId,
self::PUBLISH_PROHIBITION_PURGE_ALL_LESSONS_IN_COURSE_CONTEXT
| self::PUBLISH_PROHIBITION_PURGE_LESSON_IN_ALL_COURSE_CONTEXT
);
$rc = $DB->Query (
"DELETE FROM b_learn_course
WHERE ID=" . (string) ((int) $courseId),
true // $ignore_errors
);
// reload cache of LINKED_LESSON_ID -> COURSE_ID
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
// If data not updated
if ($rc === 0)
throw new LearnException ('EA_OTHER: data not updated', LearnException::EXC_ERR_ALL_GIVEUP);
}
protected static function _EnsureArgsStrictlyCastableToIntegers ()
{
$args = func_get_args();
foreach ($args as $arg)
{
if (
( ! is_numeric($arg) )
|| ( ! is_int($arg + 0) )
)
{
throw new LearnException ('EA_PARAMS',
}
}
return (true);
}
final public static function RelationAdd ($parentLessonId, $childLessonId, $arProperties)
{
CLearnGraphRelation::Link ($parentLessonId, $childLessonId, $arProperties);
Bitrix\Learning\Integration\Search::indexLesson($parentLessonId);
Bitrix\Learning\Integration\Search::indexLesson($childLessonId);
}
final public static function RelationUpdate ($parentLessonId, $childLessonId, $arProperties)
{
foreach ($arProperties as $propertyName => $value)
CLearnGraphRelation::SetProperty ($parentLessonId, $childLessonId, $propertyName, $value);
}
final public static function RelationGet ($parentLessonId, $childLessonId)
{
$rc = array();
$rc['SORT'] = CLearnGraphRelation::GetProperty ($parentLessonId, $childLessonId, 'SORT');
return ($rc);
}
final public static function RelationRemove ($parentLessonId, $childLessonId)
{
self::PublishProhibitionPurge_OnBeforeRelationRemove ($parentLessonId, $parentLessonId);
CLearnGraphRelation::Unlink ($parentLessonId, $childLessonId);
Bitrix\Learning\Integration\Search::indexLesson($parentLessonId);
Bitrix\Learning\Integration\Search::indexLesson($childLessonId);
}
final public static function ListImmediateParents($lessonId)
{
}
final public static function ListImmediateChilds($lessonId)
{
}
final public static function ListImmediateNeighbours($lessonId)
{
}
protected static function GetListUni ($arOrder = array(), $arFilter = array(), $arSelectFields = array(), $mode = self::GET_LIST_ALL, $lessonId = -1, $arNavParams = array())
{
$obUserFieldsSql = new CUserTypeSQL();
$obUserFieldsSql->SetEntity('LEARNING_LESSONS', 'TL.ID');
$obUserFieldsSql->SetSelect($arSelectFields);
$obUserFieldsSql->SetFilter($arFilter);
$obUserFieldsSql->SetOrder($arOrder);
$bReplaceCourseId = false;
if (isset($arFilter['#REPLACE_COURSE_ID_TO_ID']))
{
$bReplaceCourseId = true;
unset($arFilter['#REPLACE_COURSE_ID_TO_ID']);
}
$oPermParser = new CLearnParsePermissionsFromFilter ($arFilter);
// For ordering
$arMap = array(
'lesson_id' => 'TL.ID',
'site_id' => 'TL.ID', // hack for compatibility with courses in shared lists
'name' => 'TL.NAME',
'code' => 'TL.CODE',
'active' => 'TL.ACTIVE',
'created' => 'TL.DATE_CREATE', // 'created' was in previous code, perhaps for back compatibility
'date_create' => 'TL.DATE_CREATE',
'created_by' => 'TL.CREATED_BY',
'timestamp_x' => 'TL.TIMESTAMP_X',
'course_id' => 'TC.ID',
'course_sort' => 'TC.SORT',
'active_from' => 'TC.ACTIVE_FROM',
// ! This will be overrided below to TLE.SORT in case of self::GET_LIST_IMMEDIATE_CHILDS_OF
'sort' => 'TC.SORT',
'linked_lesson_id' => 'TC.LINKED_LESSON_ID'
// This element is dynamically added below for case of self::GET_LIST_IMMEDIATE_CHILDS_OF
// 'edge_sort' => 'TLE.SORT'
);
$allowedModes = array(
self::GET_LIST_ALL,
self::GET_LIST_IMMEDIATE_CHILDS_OF,
self::GET_LIST_IMMEDIATE_PARENTS_OF,
self::GET_LIST_IMMEDIATE_CHILDS_OF | self::GET_LIST_IMMEDIATE_PARENTS_OF
);
$argsCheck = is_array($arOrder)
&& is_array($arSelectFields)
&& in_array($mode, $allowedModes, true)
if ( ! $argsCheck )
throw new LearnException('EA_PARAMS', LearnException::EXC_ERR_ALL_PARAMS);
$arFieldsMap = array(
'LESSON_ID' => 'TL.ID',
'SITE_ID' => 'CASE WHEN (1 > 0) THEN \'no site\' ELSE \'0\' END', // hack for compatibility with courses in shared lists
'WAS_CHAPTER_ID' => 'TL.WAS_CHAPTER_ID',
'KEYWORDS' => 'TL.KEYWORDS',
'CHILDS_CNT' => '(SELECT COUNT(*) FROM b_learn_lesson_edges TLES WHERE TLES.SOURCE_NODE = TL.ID)',
'IS_CHILDS' => 'CASE WHEN (SELECT COUNT(*) FROM b_learn_lesson_edges TLES WHERE TLES.SOURCE_NODE = TL.ID) > 0 THEN \'1\' ELSE \'0\' END',
'SORT' => 'TC.SORT',
'TIMESTAMP_X' => $DB->DateToCharFunction('TL.TIMESTAMP_X'),
'DATE_CREATE' => $DB->DateToCharFunction('TL.DATE_CREATE'),
'CREATED_USER_NAME' => $DB->Concat("'('", 'TU.LOGIN', "') '", 'TU.NAME', "' '", 'TU.LAST_NAME'),
'CREATED_BY' => 'TL.CREATED_BY',
'ACTIVE' => 'TL.ACTIVE',
'NAME' => 'TL.NAME',
'PREVIEW_PICTURE' => 'TL.PREVIEW_PICTURE',
'PREVIEW_TEXT' => 'TL.PREVIEW_TEXT',
'PREVIEW_TEXT_TYPE' => 'TL.PREVIEW_TEXT_TYPE',
'DETAIL_TEXT' => 'TL.DETAIL_TEXT',
'DETAIL_PICTURE' => 'TL.DETAIL_PICTURE',
'DETAIL_TEXT_TYPE' => 'TL.DETAIL_TEXT_TYPE',
'LAUNCH' => 'TL.LAUNCH',
'CODE' => 'TL.CODE',
'ACTIVE_FROM' => $DB->DateToCharFunction('TC.ACTIVE_FROM'),
'ACTIVE_TO' => $DB->DateToCharFunction('TC.ACTIVE_TO'),
'RATING' => 'TC.RATING',
'RATING_TYPE' => 'TC.RATING_TYPE',
'SCORM' => 'TC.SCORM',
'LINKED_LESSON_ID' => 'TC.LINKED_LESSON_ID',
'COURSE_ID' => 'TC.ID',
'COURSE_SORT' => 'TC.SORT'
);
// filter by TIMESTAMP_X by default
if (count($arOrder) == 0)
$arOrder['TIMESTAMP_X'] = 'DESC';
$arSqlSearch = self::GetFilter($arFilter, $mode);
$SqlSearchLang = '';
if (isset($arFilter['SITE_ID']))
{
$arLID = array();
if (is_array($arFilter['SITE_ID']))
$arLID = $arFilter['SITE_ID'];
else
{
if ($arFilter['SITE_ID'] <> '')
$arLID[] = $arFilter['SITE_ID'];
}
$SqlSearchLang = "''";
foreach ($arLID as $v)
$SqlSearchLang .= ", '" . $DB->ForSql($v) . "'";
}
$r = $obUserFieldsSql->GetFilter();
if ($r <> '')
$arSqlSearch[] = "(".$r.")";
$sqlSearch = '';
foreach ($arSqlSearch as $value)
{
if ($value <> '')
$sqlSearch .= ' AND ' . $value;
}
$modeSQL_join = $modeSQL_where = '';
$modeSQL_defaultSortField = "TC.SORT"; // as SORT
// Prepare SQL's joins, if $mode need it
if ($mode & self::GET_LIST_IMMEDIATE_PARENTS_OF)
{
$modeSQL_join .=
"\nINNER JOIN b_learn_lesson_edges TLE
ON TLE.SOURCE_NODE = TL.ID\n";
$modeSQL_where .= "\nAND TLE.TARGET_NODE = " . ($lessonId + 0) . "\n";
$arFieldsMap['EDGE_SORT'] = 'TLE.SORT';
$arFieldsMap['SORT'] = 'TLE.SORT';
}
if ($mode & self::GET_LIST_IMMEDIATE_CHILDS_OF)
{
$modeSQL_join .=
"\nINNER JOIN b_learn_lesson_edges TLE
ON TLE.TARGET_NODE = TL.ID\n";
$modeSQL_where .= "\nAND TLE.SOURCE_NODE = " . ($lessonId + 0) . "\n";
$arMap['childs_cnt'] = 'CHILDS_CNT';
$arMap['is_childs'] = 'IS_CHILDS';
$arMap['edge_sort'] = 'TLE.SORT';
// Override default sort
$arMap['sort'] = $arMap['edge_sort'];
$modeSQL_defaultSortField = "TLE.SORT"; // as SORT
$arFieldsMap['EDGE_SORT'] = 'TLE.SORT';
$arFieldsMap['SORT'] = 'TLE.SORT';
}
if ($bReplaceCourseId)
$arFieldsMap['ID'] = $arFieldsMap['COURSE_ID'];
// Select all fields by default
if (count($arSelectFields) == 0)
$arSelectFields = array_keys($arFieldsMap);
// Ensure that all order fields will be selected
foreach ($arOrder as $by => $order)
{
$fieldName = mb_strtoupper($by);
if ( ! in_array($fieldName, $arSelectFields) )
$arSelectFields[] = $fieldName;
}
// Build list of fields to be selected
$strSqlSelect = '';
$bFirstPass = true;
$bDefaultSortFieldSelected = false;
foreach ($arSelectFields as $selectFieldName)
{
if (mb_substr($selectFieldName, 0, 3) === 'UF_')
continue;
if (!$bFirstPass)
$strSqlSelect .= ', ';
else
$bFirstPass = false;
if (!isset($arFieldsMap[$selectFieldName]))
{
throw new LearnException(
'EA_OTHER: UNKNOWN FIELD: ' . $selectFieldName,
}
$strSqlSelect .= $arFieldsMap[$selectFieldName] . ' AS ' . $selectFieldName;
if (
($selectFieldName === 'SORT')
&& ($arFieldsMap[$selectFieldName] === $modeSQL_defaultSortField)
)
{
$bDefaultSortFieldSelected = true;
}
}
if ( ! $bDefaultSortFieldSelected )
{
if ($strSqlSelect !== '')
$strSqlSelect .= ', ';
$strSqlSelect .= $modeSQL_defaultSortField . ' AS SORT';
}
$strSqlSelect .= $obUserFieldsSql->GetSelect();
$sqlLangConstraint = '';
if (mb_strlen($SqlSearchLang) > 2)
{
$sqlLangConstraint = "
AND
EXISTS
(
SELECT 'x' FROM b_learn_course_site TCS
WHERE TC.ID = TCS.COURSE_ID AND TCS.SITE_ID IN (" . $SqlSearchLang . ")
)
";
}
$strSqlFrom = "FROM b_learn_lesson TL
LEFT JOIN b_learn_course TC
ON TC.LINKED_LESSON_ID = TL.ID
LEFT JOIN b_user TU
ON TU.ID = TL.CREATED_BY "
. $modeSQL_join // for getting only parents/childs, if need
. $obUserFieldsSql->GetJoin("TL.ID")
. " WHERE 1 = 1 "
. $sqlLangConstraint // filter by site IDs
. $modeSQL_where; // for getting only parents/childs, if need
if ($oPermParser->IsNeedCheckPerm())
$strSqlFrom .= " AND TL.ID IN (" . $oPermParser->SQLForAccessibleLessons() . ") ";
$strSqlFrom .= $sqlSearch;
$sql = "SELECT " . $strSqlSelect . " " . $strSqlFrom;
$arSqlOrder = array();
foreach($arOrder as $by => $order)
{
$by = mb_strtolower($by);
$order = mb_strtolower($order);
if ($order !== 'asc')
$order = 'desc';
if ($s = $obUserFieldsSql->getOrder(mb_strtolower($by)))
$arSqlOrder[] = ' ' . $s . ' ' . $order . ' ';
if (mb_substr($by, 0, 3) !== 'uf_')
{
if ( ! isset($arMap[$by]) )
{
throw new LearnException(
'EA_PARAMS: unknown order by field: "' . $by . '"',
);
}
}
$arSqlOrder[] = ' ' . $arMap[$by] . ' ' . $order . ' ';
}
// on duplicate first occured FIELD will be used according to function description
DelDuplicateSort($arSqlOrder);
$sql .= ' ORDER BY ' . implode(', ', $arSqlOrder);
if (is_array($arNavParams) && ( ! empty($arNavParams) ) )
{
if (isset($arNavParams['nTopCount']) && ((int) $arNavParams['nTopCount'] > 0))
{
$sql = $DB->TopSql($sql, (int) $arNavParams['nTopCount']);
$res = $DB->Query($sql, true);
}
else
{
$res_cnt = $DB->Query("SELECT COUNT(TL.ID) as C " . $strSqlFrom);
$res_cnt = $res_cnt->fetch();
$res = new CDBResult();
$rc = $res->NavQuery($sql, $res_cnt['C'], $arNavParams, true);
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
}
}
else
$res = $DB->Query($sql, true);
if ($res === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
$res->SetUserFields($USER_FIELD_MANAGER->GetUserFields('LEARNING_LESSONS'));
return ($res);
}
final public static function GetList ($arOrder = array(), $arFilter = array(), $arSelectFields = array(), $arNavParams = array())
{
return (self::GetListUni($arOrder, $arFilter, $arSelectFields, self::GET_LIST_ALL, -1, $arNavParams));
}
final public static function GetListOfImmediateChilds ($lessonId, $arOrder = array(), $arFilter = array(), $arSelectFields = array(), $arNavParams = array())
{
return (self::GetListUni($arOrder, $arFilter, $arSelectFields, self::GET_LIST_IMMEDIATE_CHILDS_OF, $lessonId, $arNavParams));
}
final public static function GetListOfImmediateParents ($lessonId, $arOrder = array(), $arFilter = array(), $arSelectFields = array(), $arNavParams = array())
{
return (self::GetListUni($arOrder, $arFilter, $arSelectFields, self::GET_LIST_IMMEDIATE_PARENTS_OF, $lessonId, $arNavParams));
}
final public static function GetTree (
$lessonId,
$arOrder = array ('EDGE_SORT' => 'asc'),
$publishProhibitionMode = true,
$arSelectFields = array()
)
{
return (new CLearnLessonTree ($lessonId, $arOrder, $arFilter, $publishProhibitionMode, $arSelectFields));
}
protected static function GetFilter($arFilter = array(), $mode)
{
global $DB;
if ( ! is_array($arFilter) )
throw new LearnException ('EA_PARAMS', LearnException::EXC_ERR_ALL_PARAMS);
$arSqlSearch = array();
foreach ($arFilter as $key => $val)
{
$key = $res["FIELD"];
$cOperationType = $res["OPERATION"];
$key = mb_strtoupper($key);
switch ($key)
{
// for courses only
case 'COURSE_ID':
$arSqlSearch[] = CLearnHelper::FilterCreate('TC.ID', $val, 'number', $bFullJoin, $cOperationType);
break;
case 'COURSE_SORT':
$arSqlSearch[] = CLearnHelper::FilterCreate('TC.SORT', $val, 'number', $bFullJoin, $cOperationType);
break;
case 'EDGE_SORT':
// edges table (TLE) available only if requested immediate childs of some parent lesson
if ($mode & self::GET_LIST_IMMEDIATE_CHILDS_OF)
$arSqlSearch[] = CLearnHelper::FilterCreate('TLE.SORT', $val, 'number', $bFullJoin, $cOperationType);
else
throw new LearnException ('EA_PARAMS: unknown field ' . $key, LearnException::EXC_ERR_ALL_PARAMS);
break;
case 'SORT':
if ($mode & self::GET_LIST_IMMEDIATE_CHILDS_OF)
{
// edges table (TLE) available only if requested immediate childs of some parent lesson
$arSqlSearch[] = CLearnHelper::FilterCreate('TLE.SORT', $val, 'number', $bFullJoin, $cOperationType);
}
else
{
// so, by default sort by b_learn_course.SORT (for partially backward compatibility)
$arSqlSearch[] = CLearnHelper::FilterCreate('TC.SORT', $val, 'number', $bFullJoin, $cOperationType);
}
break;
case 'LINKED_LESSON_ID':
$arSqlSearch[] = CLearnHelper::FilterCreate('TC.' . $key, $val, 'number', $bFullJoin, $cOperationType, false);
break;
case 'CHILDS_CNT':
$arSqlSearch[] = CLearnHelper::FilterCreate('(SELECT COUNT(*) FROM b_learn_lesson_edges TLES WHERE TLES.SOURCE_NODE = TL.ID)', $val, 'number', $bFullJoin, $cOperationType);
break;
case 'ACTIVE_FROM':
case 'ACTIVE_TO':
if ($val <> '')
{
$arSqlSearch[] = "(TC." . $key . " " . ($cOperationType == "N" ? "<" : ">=")
. $DB->CharToDateFunction($DB->ForSql($val), "FULL")
. ($cOperationType == "N" ? "" : " OR TC.ACTIVE_FROM IS NULL")
. ")";
}
break;
case "ACTIVE_DATE":
if($val <> '')
{
$arSqlSearch[] = ($cOperationType == "N" ? " NOT" : "")
. "((TC.ACTIVE_TO >= " . $DB->GetNowFunction()
." OR TC.ACTIVE_TO IS NULL) AND (TC.ACTIVE_FROM <= " . $DB->GetNowFunction()
. " OR TC.ACTIVE_FROM IS NULL))";
}
break;
case "DATE_ACTIVE_TO":
case "DATE_ACTIVE_FROM":
$arSqlSearch[] = CLearnHelper::FilterCreate("TC." . $key, $val, 'date', $bFullJoin, $cOperationType);
break;
case 'RATING_TYPE':
$arSqlSearch[] = CLearnHelper::FilterCreate('TC.' . $key, $val, 'string', $bFullJoin, $cOperationType);
break;
case 'RATING':
case 'SCORM':
$arSqlSearch[] = CLearnHelper::FilterCreate('TC.' . $key, $val, 'string_equal', $bFullJoin, $cOperationType);
break;
// for all lessons
case 'WAS_CHAPTER_ID':
$arSqlSearch[] = CLearnHelper::FilterCreate('TL.WAS_CHAPTER_ID', $val, 'number', $bFullJoin, $cOperationType);
break;
case 'LESSON_ID':
$arSqlSearch[] = CLearnHelper::FilterCreate('TL.ID', $val, 'number', $bFullJoin, $cOperationType);
break;
case 'CREATED_BY':
$arSqlSearch[] = CLearnHelper::FilterCreate('TL.' . $key, $val, 'number', $bFullJoin, $cOperationType);
break;
case 'NAME':
case 'CODE':
case 'LAUNCH':
case 'DETAIL_TEXT':
case 'DETAIL_TEXT_TYPE':
case 'PREVIEW_TEXT':
case 'PREVIEW_TEXT_TYPE':
$arSqlSearch[] = CLearnHelper::FilterCreate('TL.' . $key, $val, 'string', $bFullJoin, $cOperationType);
break;
case 'CREATED_USER_NAME':
$arSqlSearch[] = CLearnHelper::FilterCreate($DB->Concat("'('", 'TU.LOGIN', "') '", 'TU.NAME', "' '", 'TU.LAST_NAME'),
$val, 'string', $bFullJoin, $cOperationType);
break;
case 'KEYWORDS':
$arSqlSearch[] = CLearnHelper::FilterCreate('TL.' . $key, $val, 'string', $bFullJoin, $cOperationType);
break;
case 'ACTIVE':
$arSqlSearch[] = CLearnHelper::FilterCreate('TL.' . $key, $val, 'string_equal', $bFullJoin, $cOperationType);
break;
case 'TIMESTAMP_X':
case 'DATE_CREATE':
$arSqlSearch[] = CLearnHelper::FilterCreate('TL.' . $key, $val, 'date', $bFullJoin, $cOperationType);
break;
case 'SITE_ID':
break;
case 'CHECK_PERMISSIONS':
case 'CHECK_PERMISSIONS_FOR_USER_ID':
case 'ACCESS_OPERATIONS':
// this is meta-fields, nothing to do with them here
break;
default:
if (mb_substr($key, 0, 3) !== 'UF_')
throw new LearnException ('EA_PARAMS: unknown field ' . $key, LearnException::EXC_ERR_ALL_PARAMS);
break;
}
}
return $arSqlSearch;
}
final public static function CountImmediateChilds ($lessonId)
{
if ( ! self::_EnsureArgsStrictlyCastableToIntegers ($lessonId) )
throw new LearnException('EA_PARAMS', LearnException::EXC_ERR_ALL_PARAMS);
global $DB;
$rc = $DB->Query (
"SELECT COUNT(TARGET_NODE) AS CHILDS_COUNT
FROM b_learn_lesson_edges
WHERE SOURCE_NODE = '" . (int) ($lessonId + 0) . "'",
true // ignore errors
);
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
$arData = $rc->Fetch();
if ( ($arData === false) || ( ! isset($arData['CHILDS_COUNT']) ) )
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
return ( (int) ($arData['CHILDS_COUNT'] + 0) );
}
final public static function LessonIdByChapterId ($chapterId)
{
array(),
'WAS_CHAPTER_ID' => $chapterId,
'CHECK_PERMISSIONS' => 'N'
),
array('LESSON_ID'),
self::GET_LIST_ALL
);
if ($rc === false)
throw new LearnException ('EA_UNKNOWN_ERROR', LearnException::EXC_ERR_ALL_GIVEUP);
$row = $rc->Fetch();
if ( ! isset($row['LESSON_ID']) )
return (false);
else
return ( (int) $row['LESSON_ID'] );
}
final public static function GetListOfAncestors ($lessonId, $stopAtLessonId = false, $stopBeforeLessonId = false, $arIgnoreEdges = array())
{
$arAncestors = array();
$arOPathes = self::GetListOfParentPathes ($lessonId, $stopAtLessonId, $stopBeforeLessonId, $arIgnoreEdges);
foreach ($arOPathes as $oPath)
$arAncestors = array_merge($arAncestors, array_map('intval', $oPath->GetPathAsArray()));
array_unique($arAncestors);
return ($arAncestors);
}
final public static function GetListOfParentPathes ($lessonId, $breakOnLessonId = false, $breakBeforeLesson = false, $arIgnoreEdges = array())
{
array($lessonId)
);
$arAlreadyProcessedLessons = array($lessonId);
if ($breakOnLessonId !== false)
{
// This lesson must be interpreted as parentless.
// This behaviour can be emulated by adding to
// $arAlreadyProcessedLessons all immediate parents
// of this lesson.
$arEdges = self::ListImmediateParents($breakOnLessonId);
foreach ($arEdges as $arEdge)
$arAlreadyProcessedLessons[] = (int) $arEdge['PARENT_LESSON'];
}
if ($breakBeforeLesson !== false)
$arAlreadyProcessedLessons[] = (int) $breakBeforeLesson;
$arAllPathes = self::GetListOfParentPathesRecursive ($arPathes, $arAlreadyProcessedLessons, $arIgnoreEdges);
$arObjPathes = array();
foreach ($arAllPathes as $arPathBackward)
{
$arPath = array_reverse($arPathBackward);
$o = new CLearnPath ($arPath);
$o->PopBottom(); // remove $lessonId
// skip empty pathes
if ($o->Count() > 0)
$arObjPathes[] = $o;
}
return ($arObjPathes);
}
protected static function GetListOfParentPathesRecursive ($arPathes, &$arAlreadyProcessedLessons, $arIgnoreEdges = array())
{
$arPathesNew = $arPathes;
$must_be_stopped = 0x1; // stop if no more parents available or finally cycled
foreach ($arPathes as $key => $arPath)
{
$lessonId = $arPath[count($arPath) - 1];
$arEdges = self::ListImmediateParents($lessonId);
$arParents = array();
foreach ($arEdges as $arEdge)
{
$parentLessonId = (int) $arEdge['PARENT_LESSON'];
if ( ! in_array($parentLessonId, $arAlreadyProcessedLessons, true) )
{
$isEdgeIgnored = false;
foreach ($arIgnoreEdges as $arIgnoreEdge)
{
if (
($arIgnoreEdge['PARENT_LESSON'] == $arEdge['PARENT_LESSON'])
&& ($arIgnoreEdge['CHILD_LESSON'] == $arEdge['CHILD_LESSON'])
)
{
$isEdgeIgnored = true;
break;
}
}
if ( ! $isEdgeIgnored )
{
$arParents[] = $parentLessonId;
// Precache already processed lesson (for prevent cycling)
$arAlreadyProcessedLessons[] = $parentLessonId;
}
}
}
$must_be_stopped &= (int) (count($arParents) === 0); // true evaluted to 1
$i = 0;
foreach ($arParents as $parentLessonId)
{
$parentLessonId = (int) $parentLessonId;
if ( $i || $i++ ) // executed only for all except first lesson in $arParents
{
$arPathTmp = $arPath;
$arPathTmp[] = $parentLessonId;
$arPathesNew[] = $arPathTmp;
}
else
{
$arPathesNew[$key][] = $parentLessonId;
}
}
}
if ($must_be_stopped)
return ($arPathesNew);
return (self::GetListOfParentPathesRecursive($arPathesNew, $arAlreadyProcessedLessons, $arIgnoreEdges));
}
final public static function IsPublishProhibited ($in_lessonId, $in_contextCourseLessonId)
{
global $DB;
self::_EnsureArgsStrictlyCastableToIntegers ($in_lessonId, $in_contextCourseLessonId);
$lessonId = (int) $in_lessonId;
$contextCourseLessonId = (int) $in_contextCourseLessonId;
$rc = $DB->Query (
"SELECT COURSE_LESSON_ID
FROM b_learn_publish_prohibition
WHERE COURSE_LESSON_ID = $contextCourseLessonId
AND PROHIBITED_LESSON_ID = $lessonId
",
true // ignore errors
);
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
$arData = $rc->Fetch();
if ($arData === false)
return (false); // lesson isn't prohibited for publish under given course
return (true); // lesson is prohibited for publish
}
final public static function PublishProhibitionSetTo ($in_lessonId, $in_contextCourseLessonId, $in_isProhibited)
{
global $DB;
self::_EnsureArgsStrictlyCastableToIntegers ($in_lessonId, $in_contextCourseLessonId);
if ( ! is_bool($in_isProhibited) )
{
throw new LearnException ('EA_PARAMS: isProhibited',
}
$lessonId = (int) $in_lessonId;
$contextCourseLessonId = (int) $in_contextCourseLessonId;
$isProhibitedNow = self::IsPublishProhibited ($lessonId, $contextCourseLessonId);
// Update status only if it was changed
if ($isProhibitedNow !== $in_isProhibited)
{
if ($in_isProhibited)
{
$sql = "INSERT INTO b_learn_publish_prohibition
(COURSE_LESSON_ID, PROHIBITED_LESSON_ID)
VALUES ($contextCourseLessonId, $lessonId)";
}
else
{
$sql = "DELETE FROM b_learn_publish_prohibition
WHERE COURSE_LESSON_ID = $contextCourseLessonId
AND PROHIBITED_LESSON_ID = $lessonId";
}
$rc = $DB->Query($sql, true);
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
Bitrix\Learning\Integration\Search::indexLesson($lessonId);
return (true); // prohibition status changed
}
return (false); // prohibition status not changed
}
protected static function PublishProhibitionPurge ($in_lessonId, $in_purgeMode)
{
global $DB;
self::_EnsureArgsStrictlyCastableToIntegers ($in_lessonId, $in_purgeMode);
$lessonId = (int) $in_lessonId;
$purgeMode = (int) $in_purgeMode;
if ( ! in_array(
$purgeMode,
self::PUBLISH_PROHIBITION_PURGE_ALL_LESSONS_IN_COURSE_CONTEXT,
self::PUBLISH_PROHIBITION_PURGE_LESSON_IN_ALL_COURSE_CONTEXT,
self::PUBLISH_PROHIBITION_PURGE_BOTH // ORed previous two elements
),
true
)
)
{
throw new LearnException ('EA_PARAMS: purgeMode',
}
$arSqlCondition = array();
if ($purgeMode & self::PUBLISH_PROHIBITION_PURGE_ALL_LESSONS_IN_COURSE_CONTEXT)
$arSqlCondition[] = 'COURSE_LESSON_ID = ' . $lessonId;
if ($purgeMode & self::PUBLISH_PROHIBITION_PURGE_LESSON_IN_ALL_COURSE_CONTEXT)
$arSqlCondition[] = 'PROHIBITED_LESSON_ID = ' . $lessonId;
if (count($arSqlCondition) > 0)
{
$sqlCondition = implode(' OR ', $arSqlCondition);
$rc = $DB->Query(
"DELETE FROM b_learn_publish_prohibition
WHERE " . $sqlCondition,
true);
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
}
}
protected static function PublishProhibitionPurge_OnBeforeRelationRemove ($in_parentLessonId, $in_childLessonId)
{
global $DB;
/*
We must remove publish prohibition for all lessons-descendants of $in_childLessonId,
in context of courses-ancestors of $in_parentLessonId, that are will lost link (path).
General version of algorithm:
1) Get list of all descendants of $in_childLessonId (include $in_childLessonId itself).
2) Get list of publish prohibitions for lessons from step 1.
3) Checks every prohibition, that prohibited lesson still have path
to courseLessonId in context of which lesson is prohibited.
Remove prohibition, when check failed.
Optimized version of algorithm:
1) Get list of all ancectors (that are courses) of $in_parentLessonId (include
$in_parentLessonId itself).
EXPLAINATION: when DeleteRecursiveLikeHardlinks() function will work,
relations will be removed from top to bottom mainly. It means, that if
we will get list descendants on each step - it will be too many lessons.
So, we get ancestors instead.
2) Get list of publish prohibitions in context of courses from step 1.
3) Checks every prohibition, that prohibited lesson still have path
to courseLessonId in context of which lesson is prohibited.
Remove prohibition, when check failed.
One more optimization:
In optimized algorithm, we shouldn't exclude non-courses from ancestors list
on step 1, because, there is no non-courses can be in table
b_learn_publish_prohibition. So, if we can do
"SELECT *
FROM b_learn_publish_prohibition
WHERE COURSE_LESSON_ID IN (...list of all ancestors...)"
and result will be as expected when ancesotrs list includes only courses.
I'm sure, DB engine will do this job more fast, than my PHP-script excludes non-courses.
And one more optimization:
In step 1 of optimized algorithm we can limit tree of ancestors at $in_childLessonId
(in case, when tree of ancestors are cycled).
EXPLAINATION: $in_childLessonId will lost relation to parent lesson ($in_parentLessonId) only.
It means, that all descendants of $in_childLessonId (include $in_childLessonId itself)
will not lost link (path) to other immediate parents of $in_childLessonId and to
$in_childLessonId itself. So we don't need to check descendsnts in context of $in_childLessonId
or it's ancestors (except $in_parentLessonId and it's ancestros).
About checking that lesson after relation
remove still have path (link) to some course:
1) Get all ancestors of lesson with method self::GetListOfAncestors($lessonId, false,
false, $arIgnoreEdges). It will return ancestors in case, when all edges from $arIgnoreEdges
is interpreted as non-existing.
2) If course-lesson among this ancestors, that link will be still exists after relation removing.
This steps will be perfomed for every pair of finded prohibitions.
There is probability that prohibited lesson will be in few courses.
We can optimize steps by caching ancestors for prohibited lessons.
In spite of that probability is not good in general case, we should use cache,
because cache hit can save very-very much time. And caching itself don't gives
overhead for processor, it's only overheads RAM, but a little.
So, final algorithm:
1) Get list of all ancectors of $in_parentLessonId (include $in_parentLessonId itself).
Stop cycling BEFORE $in_childLessonId.
2) Get list of publish prohibitions in context of courses from step 1.
3) Checks every prohibition, that prohibited lesson still have path
to courseLessonId in context of which lesson is prohibited.
Remove prohibition, when check failed.
*/
// 1) Get list of all ancectors of $in_parentLessonId (include $in_parentLessonId itself).
// Stop cycling BEFORE $in_childLessonId.
$arAncestors = self::GetListOfAncestors ($in_parentLessonId, false, $in_childLessonId);
$arAncestors[] = (int) $in_parentLessonId; // include $in_parentLessonId itself
// convert ids to int
$arAncestorsInt = array();
foreach ($arAncestors as $ancestroId)
$arAncestorsInt[] = (int) $ancestroId;
// 2) Get list of publish prohibitions in context of courses from step 1.
$rc = $DB->Query(
"SELECT COURSE_LESSON_ID, PROHIBITED_LESSON_ID
FROM b_learn_publish_prohibition
WHERE COURSE_LESSON_ID IN (" . implode (',', $arAncestorsInt) . ")"
,
true);
if ($rc === false)
throw new LearnException ('EA_SQLERROR', LearnException::EXC_ERR_ALL_GIVEUP);
// This relation will be removed, so must be ignoredm when determine
// future ancestors (after relation removing)
$arIgnoreEdges = array(
'PARENT_LESSON' => (int) $in_parentLessonId,
'CHILD_LESSON' => (int) $in_childLessonId
)
);
$arCache_ancestorsOfLesson = array();
while ($arData = $rc->Fetch())
{
$prohibitedLessonId = (int) $arData['PROHIBITED_LESSON_ID'];
$contextLessonId = (int) $arData['COURSE_LESSON_ID'];
// Precache future ancestors (after relation removing)
// for lesson, if they are not precached yet.
if ( ! isset($arCache_ancestorsOfLesson[$prohibitedLessonId]) )
{
$arCache_ancestorsOfLesson[$prohibitedLessonId] =
$prohibitedLessonId,
false, // $stopAtLessonId
false, // $stopBeforeLessonId
$arIgnoreEdges
);
}
// Will prohibited lesson lost link to course $contextLessonId?
if ( ! in_array($contextLessonId, $arCache_ancestorsOfLesson[$prohibitedLessonId], true) )
{
// Yes, this lesson will not in subpathes of $contextLessonId,
// so accorded publish prohibition must be removed.
self::PublishProhibitionSetTo ($prohibitedLessonId, $contextLessonId, false);
}
}
}
}
if($_SERVER $defaultValue['REQUEST_METHOD']==="GET" &&!empty($RestoreDefaults) && $bizprocPerms==="W" &&check_bitrix_sessid())
Определения options.php:32
$arPathes
Определения options.php:293
static Delete($ID)
Определения test.php:156
static GetList($arOrder=array(), $arFilter=array(), $arNavParams=array())
Определения test.php:349
static GetList($arOrder=array(), $arFilter=array(), $arNavParams=array())
Определения certification.php:14
static CourseGetLinkedLesson($courseId)
Определения course.php:55
static Delete($ID)
Определения file.php:706
static Delete($ID)
Определения question.php:183
static GetList($arOrder=array(), $arFilter=array(), $bHz=false, $arNavParams=array(), $arSelect=array())
Определения question.php:318
static GetInstance($in_userId)
Определения clearnaccess.php:171
const OP_LESSON_UNLINK_FROM_PARENTS
Определения clearnaccess.php:143
const OP_LESSON_UNLINK_DESCENDANTS
Определения clearnaccess.php:145
const OP_LESSON_REMOVE
Определения clearnaccess.php:141
static CanUserAddLessonToParentLesson($arParams)
Определения clearnaccessmacroses.php:75
static CanUserAddLessonWithoutParentLesson($arParams=array())
Определения clearnaccessmacroses.php:58
static Update($id, $arInFields)
Определения ilearngraphnode.php:195
static Create($arInFields)
Определения ilearngraphnode.php:190
static Remove($id)
Определения ilearngraphnode.php:102
static GetByID($id)
Определения ilearngraphnode.php:138
static GetProperty($parentNodeId, $childNodeId, $propertyName)
Определения ilearngraphrelation.php:370
static SetProperty($parentNodeId, $childNodeId, $propertyName, $value)
Определения ilearngraphrelation.php:311
static Link($parentNodeId, $childNodeId, $arProperties)
Определения ilearngraphrelation.php:234
static ListImmediateNeighbours($nodeId)
Определения ilearngraphrelation.php:166
static Unlink($parentNodeId, $childNodeId)
Определения ilearngraphrelation.php:281
static ListImmediateChilds($nodeId)
Определения ilearngraphrelation.php:161
static ListImmediateParents($nodeId)
Определения ilearngraphrelation.php:156
static FilterCreate($fname, $vals, $type, &$bFullJoin, $cOperationType=false, $bSkipEmpty=true)
Определения clearnhelper.php:214
static MkOperationFilter($key)
Определения clearnhelper.php:143
Определения clearnlesson.php:422
const PUBLISH_PROHIBITION_PURGE_BOTH
Определения clearnlesson.php:437
static _ExtractAdditionalCourseFields(&$arFields)
Определения clearnlesson.php:552
static PublishProhibitionPurge_OnBeforeRelationRemove($in_parentLessonId, $in_childLessonId)
Определения clearnlesson.php:2356
static GetLinkedCourse($lessonId)
Определения clearnlesson.php:1198
static _EnsureArgsStrictlyCastableToIntegers()
Определения clearnlesson.php:1456
const GET_LIST_IMMEDIATE_PARENTS_OF
Определения clearnlesson.php:425
static _CanonizeAndCheckAdditionalParamsForAddCourse($arFields, $forUpdate=false)
Определения clearnlesson.php:591
static ListImmediateParents($lessonId)
Определения clearnlesson.php:1514
static Delete($lesson_id)
Определения clearnlesson.php:974
static RelationGet($parentLessonId, $childLessonId)
Определения clearnlesson.php:1495
static GetCourseToLessonMap($bRefreshCache=false)
Определения clearnlesson.php:1215
static GetCourseToLessonMap_ReloadCache()
Определения clearnlesson.php:1254
static GetListUni($arOrder=array(), $arFilter=array(), $arSelectFields=array(), $mode=self::GET_LIST_ALL, $lessonId=-1, $arNavParams=array())
Определения clearnlesson.php:1532
static GetByID($id)
Определения clearnlesson.php:1148
static _funcDelete_ParseOptions($lesson_id)
Определения clearnlesson.php:812
static DeleteRecursiveLikeHardlinks($in_data)
Определения clearnlesson.php:876
static GetListOfParentPathes($lessonId, $breakOnLessonId=false, $breakBeforeLesson=false, $arIgnoreEdges=array())
Определения clearnlesson.php:2116
static GetFilter($arFilter=array(), $mode)
Определения clearnlesson.php:1883
static Add($arFields, $isCourse=false, $parentLessonId=true, $arProperties=array('SORT'=> 500), $isCheckPermissions=true, $checkPermissionsForUserId=-1)
Определения clearnlesson.php:440
static RelationAdd($parentLessonId, $childLessonId, $arProperties)
Определения clearnlesson.php:1475
static IsPublishProhibited($in_lessonId, $in_contextCourseLessonId)
Определения clearnlesson.php:2218
static ListImmediateChilds($lessonId)
Определения clearnlesson.php:1520
static GetListOfAncestors($lessonId, $stopAtLessonId=false, $stopBeforeLessonId=false, $arIgnoreEdges=array())
Определения clearnlesson.php:2099
static GetCourseToLessonMap_LoadFromDB()
Определения clearnlesson.php:1261
static PublishProhibitionPurge($in_lessonId, $in_purgeMode)
Определения clearnlesson.php:2301
const GET_LIST_IMMEDIATE_CHILDS_OF
Определения clearnlesson.php:424
static CourseBecomeLesson($courseId)
Определения clearnlesson.php:1390
static RelationUpdate($parentLessonId, $childLessonId, $arProperties)
Определения clearnlesson.php:1486
static PublishProhibitionSetTo($in_lessonId, $in_contextCourseLessonId, $in_isProhibited)
Определения clearnlesson.php:2246
static CountImmediateChilds($lessonId)
Определения clearnlesson.php:2036
static ListImmediateNeighbours($lessonId)
Определения clearnlesson.php:1526
static BecomeCourse($lessonId, $arFields)
Определения clearnlesson.php:1321
static GetListOfParentPathesRecursive($arPathes, &$arAlreadyProcessedLessons, $arIgnoreEdges=array())
Определения clearnlesson.php:2154
static GetListOfImmediateChilds($lessonId, $arOrder=array(), $arFilter=array(), $arSelectFields=array(), $arNavParams=array())
Определения clearnlesson.php:1855
static GetByIDAsArr($id)
Определения clearnlesson.php:1154
static LessonIdByChapterId($chapterId)
Определения clearnlesson.php:2073
static GetListOfImmediateParents($lessonId, $arOrder=array(), $arFilter=array(), $arSelectFields=array(), $arNavParams=array())
Определения clearnlesson.php:1861
const PUBLISH_PROHIBITION_PURGE_ALL_LESSONS_IN_COURSE_CONTEXT
Определения clearnlesson.php:431
static Update($id, $arFields)
Определения clearnlesson.php:691
static GetTree( $lessonId, $arOrder=array('EDGE_SORT'=> 'asc'), $arFilter=array(), $publishProhibitionMode=true, $arSelectFields=array())
Определения clearnlesson.php:1867
static GetList($arOrder=array(), $arFilter=array(), $arSelectFields=array(), $arNavParams=array())
Определения clearnlesson.php:1849
static RelationRemove($parentLessonId, $childLessonId)
Определения clearnlesson.php:1504
const GET_LIST_ALL
Определения clearnlesson.php:423
const PUBLISH_PROHIBITION_PURGE_LESSON_IN_ALL_COURSE_CONTEXT
Определения clearnlesson.php:434
static StaticParser($arOptions, $arParseParams)
Определения clearnsharedargmanager.php:50
const EXC_ERR_ALL_PARAMS
Определения learnexception.php:7
const EXC_ERR_ALL_ACCESS_DENIED
Определения learnexception.php:8
const EXC_ERR_ALL_LOGIC
Определения learnexception.php:5
const EXC_ERR_ALL_GIVEUP
Определения learnexception.php:6
const EXC_ERR_LL_UNREMOVABLE_CL
Определения learnexception.php:31
$options
Определения commerceml2.php:49
$arFields
Определения dblapprove.php:5
$arPath
Определения file_edit.php:72
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
global $USER_FIELD_MANAGER
Определения attempt.php:6
Определения clearnlesson.php:10
static GetLinkedCourse($lessonId)
static GetListOfImmediateChilds($lessonId, $arOrder=array(), $arFilter=array(), $arSelectFields=array())
static ListImmediateParents($lessonId)
static IsPublishProhibited($lessonId, $contextCourseLessonId)
static RelationGet($parentLessonId, $childLessonId)
static Delete($id)
static GetByID($id)
static Add($arFields, $isCourse=false, $parentLessonId=true, $arProperties=array('SORT'=> 500))
static PublishProhibitionSetTo($lessonId, $contextCourseLessonId, $isProhibited)
static GetTree( $lessonId, $arOrder=array('EDGE_SORT'=> 'asc'), $arFilter=array(), $publishProhibitionMode=true)
static RelationAdd($parentLessonId, $childLessonId, $arProperties)
static DeleteRecursiveLikeHardlinks($id)
static ListImmediateChilds($lessonId)
static RelationUpdate($parentLessonId, $childLessonId, $arProperties)
static GetListOfParentPathes($lessonId, $breakOnLessonId=false, $breakBeforeLessonId=false, $arIgnoreEdges=array())
static CountImmediateChilds($lessonId)
static ListImmediateNeighbours($lessonId)
static GetListOfImmediateParents($lessonId, $arOrder=array(), $arFilter=array(), $arSelectFields=array())
static GetByIDAsArr($id)
static Update($id, $arFields)
static GetList($arOrder=array(), $arFilter=array())
static RelationRemove($parentLessonId, $childLessonId)
$oAccess
Определения options.php:19
global $DB
Определения cron_frame.php:29
global $USER
Определения csv_new_run.php:40
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
DelDuplicateSort(&$arSort)
Определения tools.php:2055
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
Определения tools.php:5177
GetMessage($name, $aReplace=null)
Определения tools.php:3397
$value
Определения Param.php:39
$order
Определения payment.php:8
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$i
Определения factura.php:643
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$val
Определения options.php:1793
$arRes
Определения options.php:104
$GLOBALS['_____370096793']
Определения update_client.php:1
$arFilter
Определения user_search.php:106
if( $site[ 'SERVER_NAME']==='') if($site['SERVER_NAME']==='') $arProperties
Определения yandex_run.php:644