Add conf setting resource_sequence_show_dependency_in_course_intro - refs BT#20395

Allows to show the sequence graphic in the course intro
pull/4473/head
Angel Fernando Quiroz Campos 3 years ago
parent e9353ba96c
commit 4562ee16d0
  1. 33
      main/inc/ajax/sequence.ajax.php
  2. 38
      main/inc/introductionSection.inc.php
  3. 3
      main/install/configuration.dist.php
  4. 24
      main/template/default/sequence_resource/course_requirements.tpl
  5. 16
      main/template/default/sequence_resource/session_requirements.tpl
  6. 299
      src/Chamilo/CoreBundle/Entity/Repository/SequenceResourceRepository.php

@ -48,7 +48,7 @@ switch ($action) {
echo Display::img(
$graphImage,
get_lang('GraphDependencyTree'),
['class' => 'center-block'],
['class' => 'center-block img-responsive'],
false
);
} catch (UnexpectedValueException $e) {
@ -401,6 +401,7 @@ switch ($action) {
break;
case 'get_requirements':
case 'get_dependents':
$sessionId = isset($_REQUEST['sid']) ? (int) $_REQUEST['sid'] : 0;
$userId = api_get_user_id();
$resourceName = '';
@ -408,6 +409,7 @@ switch ($action) {
switch ($type) {
case SequenceResource::SESSION_TYPE:
$resourceData = api_get_session_info($id);
$resourceName = $resourceData['name'];
$template = 'session_requirements.tpl';
break;
@ -422,19 +424,38 @@ switch ($action) {
exit;
}
if ('get_requirements' === $action) {
$sequences = $sequenceResourceRepository->getRequirements($id, $type);
if (empty($sequences)) {
exit;
}
$sequenceList = $sequenceResourceRepository->checkRequirementsForUser($sequences, $type, $userId, $sessionId);
$allowSubscription = $sequenceResourceRepository->checkSequenceAreCompleted($sequenceList);
} else {
$sequences = $sequenceResourceRepository->getDependents($id, $type);
$sequenceList = $sequenceResourceRepository->checkDependentsForUser($sequences, $type, $userId, $sessionId);
$allowSubscription = $sequenceResourceRepository->checkSequenceAreCompleted(
$sequenceList,
SequenceResourceRepository::VERTICES_TYPE_DEP
);
}
$view = new Template(null, false, false, false, false, false);
$view->assign('sequences', $sequenceList);
$view->assign('sequence_type', $type);
$view->assign('allow_subscription', $allowSubscription);
$view->assign(
'item_type',
'get_requirements' === $action
? SequenceResourceRepository::VERTICES_TYPE_REQ
: SequenceResourceRepository::VERTICES_TYPE_DEP
);
$course = api_get_course_entity();
if ($course) {
$view->assign(
'current_requirement_is_completed',
$sequenceResourceRepository->checkCourseRequirements($userId, $course, $sessionId)
);
}
if ($allowSubscription) {
$view->assign(

@ -2,6 +2,7 @@
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\SequenceResource;
use Chamilo\CourseBundle\Entity\CToolIntro;
/**
@ -363,7 +364,18 @@ if (!api_is_anonymous()) {
$intro_content = AnnouncementManager::parseContent(api_get_user_id(), $intro_content, api_get_course_id());
}
$introduction_section .= '<div class="col-md-12">';
$showSequencesBlock = false;
if (api_get_configuration_value('resource_sequence_show_dependency_in_course_intro')) {
$sequenceResourceRepo = $em->getRepository(SequenceResource::class);
$sequences = $sequenceResourceRepo->getDependents($course_id, SequenceResource::COURSE_TYPE);
$firstSequence = current($sequences);
$showSequencesBlock = !empty($firstSequence['dependents']);
}
$introduction_section .= $showSequencesBlock ? '<div class="col-md-10">' : '<div class="col-md-12">';
if ($intro_dispDefault) {
if (!empty($intro_content)) {
$introduction_section .= '<div class="page-course">';
@ -380,7 +392,29 @@ if ($intro_dispDefault) {
$introduction_section .= $toolbar;
$introduction_section .= '</div>';
$introduction_section .= '</div>';
if ($showSequencesBlock) {
$sequenceUrl = http_build_query(
[
'a' => 'get_dependents',
'id' => $course_id,
'type' => SequenceResource::COURSE_TYPE,
'sid' => $session_id,
]
);
$introduction_section .= '<div class="col-md-2 text-center" id="resource-sequence">
<span class="fa fa-spinner fa-spin fa-fw" aria-hidden="true"></span>
</div>
<script>
$(function () {
$(\'#resource-sequence\').load(_p.web_ajax + \'sequence.ajax.php?'.$sequenceUrl.'\')
});
</script>
';
}
$introduction_section .= '</div>'; //div.row
$browser = api_get_navigator();

@ -1992,6 +1992,9 @@ $_configuration['auth_password_links'] = [
// Resource sequence: Validate course in the same session.
//$_configuration['course_sequence_valid_only_in_same_session'] = false;
// Allows to show the sequence graphic in the course intro
//$_configuration['resource_sequence_show_dependency_in_course_intro'] = false;
// Allow time per question. BT#17791
// Requires a question text extra field called "time", value in seconds.
// ALTER TABLE track_e_attempt ADD COLUMN seconds_spent INT;

@ -1,13 +1,29 @@
<h2 class="page-header">{{ 'RequiredCourses'|get_lang }}</h2>
{% if 'requirements' == item_type %}
<h3>{{ 'RequiredCourses'|get_lang }}</h3>
{% else %}
<h3>{{ 'Dependencies'|get_lang }}</h3>
{% endif %}
{% for key, item in sequences %}
{% if 'requirements' == item_type %}
{% set courses = item.requirements %}
{% else %}
{% set courses = item.dependents %}
{% endif %}
<h4>{{ item.name }}</h4>
<div id="parents">
{% for course in item.requirements %}
{% for c_id, course in courses %}
<div class="parent">
<div class="big-icon">
<img src="{{ 'item-sequence.png'|icon(48) }}" width="48" height="48">
<p class="sequence-course">{{ course.name }}</p>
<p class="sequence-course">
{% if current_requirement_is_completed %}
<a href="{{ _p.web_course ~ course.code ~ '/index.php?' ~ { 'id_session': _c.session_id }|url_encode }}">{{ course.name }}</a>
{% else %}
{{ course.name }}
{% endif %}
</p>
{% if _u.logged %}
<span class="label {{ course.status ? 'label-success' : 'label-danger' }}">
@ -21,7 +37,7 @@
</div>
</div>
{% if loop.index != item.requirements|length %}
{% if loop.index != courses|length %}
<em class="fa fa-plus fa-3x sequence-plus-icon"></em>
{% endif %}
{% endfor %}

@ -1,9 +1,19 @@
<h2 class="page-header">{{ 'RequiredSessions'|get_lang }}</h2>
{% if 'requirements' == item_type %}
<h3>{{ 'RequiredCourses'|get_lang }}</h3>
{% else %}
<h3>{{ 'Dependencies'|get_lang }}</h3>
{% endif %}
{% for item in sequences %}
{% if 'requirements' == item_type %}
{% set sessions = item.requirements %}
{% else %}
{% set sessions = item.dependents %}
{% endif %}
<h4>{{ item.name }}</h4>
<div id="parents">
{% for session in item.requirements %}
{% for session in sessions %}
<div class="parent">
<div class="big-icon">
<img src="{{ 'item-sequence.png'|icon(48) }}" width="48" height="48">
@ -21,7 +31,7 @@
</div>
</div>
{% if loop.index != item.requirements|length %}
{% if loop.index != sessions|length %}
<em class="fa fa-plus fa-3x sequence-plus-icon"></em>
{% endif %}
{% endfor %}

@ -6,6 +6,7 @@ namespace Chamilo\CoreBundle\Entity\Repository;
use Category;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\GradebookCategory;
use Chamilo\CoreBundle\Entity\SequenceResource;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CoreBundle\Entity\SessionRelUser;
@ -21,6 +22,9 @@ use SessionManager;
*/
class SequenceResourceRepository extends EntityRepository
{
public const VERTICES_TYPE_REQ = 'requirements';
public const VERTICES_TYPE_DEP = 'dependents';
/**
* Find the SequenceResource based in the resourceId and type.
*
@ -112,52 +116,15 @@ class SequenceResourceRepository extends EntityRepository
*/
public function getRequirements($resourceId, $type): array
{
$sequencesResource = $this->findBy(['resourceId' => $resourceId, 'type' => $type]);
$em = $this->getEntityManager();
$result = [];
/** @var SequenceResource $sequenceResource */
foreach ($sequencesResource as $sequenceResource) {
if (!$sequenceResource->hasGraph()) {
continue;
return $this->getRequirementsOrDependents($resourceId, $type, self::VERTICES_TYPE_REQ);
}
$sequence = $sequenceResource->getSequence();
$graph = $sequence->getUnSerializeGraph();
$vertex = $graph->getVertex($resourceId);
$from = $vertex->getVerticesEdgeFrom();
$sequenceInfo = [
'name' => $sequence->getName(),
'requirements' => [],
];
foreach ($from as $subVertex) {
$vertexId = $subVertex->getId();
$resource = null;
switch ($type) {
case SequenceResource::SESSION_TYPE:
$repo = $em->getRepository('ChamiloCoreBundle:Session');
$resource = $repo->find($vertexId);
break;
case SequenceResource::COURSE_TYPE:
$repo = $em->getRepository('ChamiloCoreBundle:Course');
$resource = $repo->find($vertexId);
break;
}
if (null === $resource) {
continue;
}
$sequenceInfo['requirements'][$vertexId] = $resource;
}
$result[$sequence->getId()] = $sequenceInfo;
}
return $result;
/**
* Get the requirements for a resource only.
*/
public function getDependents(int $resourceId, int $type): array
{
return $this->getRequirementsOrDependents($resourceId, $type, self::VERTICES_TYPE_DEP);
}
/**
@ -207,13 +174,139 @@ class SequenceResourceRepository extends EntityRepository
*/
public function checkRequirementsForUser(array $sequences, int $type, $userId, $sessionId = 0): array
{
$sequenceList = [];
return $this->checkRequirementsOrDependentsForUser(
$sequences,
$type,
self::VERTICES_TYPE_REQ,
$userId,
$sessionId
);
}
/**
* Check if the ser has completed the requirements for the sequences.
*
* @param array $sequences The sequences
* @param int $type The type of sequence resource
* @param int $userId
* @param int $sessionId
*/
public function checkDependentsForUser(array $sequences, int $type, $userId, $sessionId = 0): array
{
return $this->checkRequirementsOrDependentsForUser(
$sequences,
$type,
self::VERTICES_TYPE_DEP,
$userId,
$sessionId
);
}
public function checkCourseRequirements($userId, Course $course, $sessionId): bool
{
$em = $this->getEntityManager();
$sessionId = (int) $sessionId;
$gradebookCategoryRepo = $em->getRepository('ChamiloCoreBundle:GradebookCategory');
$gradebooks = $gradebookCategoryRepo->findBy(
[
'courseCode' => $course->getCode(),
'sessionId' => $sessionId,
'isRequirement' => true,
]
);
if (empty($gradebooks)) {
return false;
}
$status = true;
foreach ($gradebooks as $gradebook) {
$category = Category::createCategoryObjectFromEntity($gradebook);
$userFinishedCourse = Category::userFinishedCourse(
$userId,
$category,
true
);
if (0 === $sessionId) {
if (false === $userFinishedCourse) {
$status = false;
break;
}
} else {
if (false === $userFinishedCourse) {
$status = false;
break;
}
}
}
return $status;
}
/**
* Check if at least one sequence are completed.
*/
public function checkSequenceAreCompleted(array $sequences, $itemType = self::VERTICES_TYPE_REQ): bool
{
foreach ($sequences as $sequence) {
$status = true;
foreach ($sequence[$itemType] as $item) {
$status = $status && $item['status'];
}
if ($status) {
return true;
}
}
return false;
}
/**
* Get sessions from vertices.
*/
protected function findVerticesEdges(Vertices $verticesEdges, int $type): array
{
$sessionVertices = [];
$em = $this->getEntityManager();
foreach ($verticesEdges as $supVertex) {
$vertexId = $supVertex->getId();
switch ($type) {
case SequenceResource::SESSION_TYPE:
$resource = $em->getRepository('ChamiloCoreBundle:Session')->find($vertexId);
break;
case SequenceResource::COURSE_TYPE:
$resource = $em->getRepository('ChamiloCoreBundle:Course')->find($vertexId);
break;
}
if (empty($resource)) {
continue;
}
$sessionVertices[$vertexId] = $resource;
}
return $sessionVertices;
}
private function checkRequirementsOrDependentsForUser(
array $sequences,
int $resourceType,
string $itemType,
int $userId,
int $sessionId = 0
): array {
$sequenceList = [];
$em = $this->getEntityManager();
$gradebookCategoryRepo = $em->getRepository(GradebookCategory::class);
$sessionUserList = [];
$checkOnlySameSession = api_get_configuration_value('course_sequence_valid_only_in_same_session');
if (SequenceResource::COURSE_TYPE == $type) {
if (SequenceResource::COURSE_TYPE === $resourceType) {
if ($checkOnlySameSession) {
$sessionUserList = [$sessionId];
} else {
@ -231,12 +324,12 @@ class SequenceResourceRepository extends EntityRepository
foreach ($sequences as $sequenceId => $sequence) {
$item = [
'name' => $sequence['name'],
'requirements' => [],
$itemType => [],
];
$resourceItem = null;
foreach ($sequence['requirements'] as $resource) {
switch ($type) {
foreach ($sequence[$itemType] as $resource) {
switch ($resourceType) {
case SequenceResource::SESSION_TYPE:
/** @var Session $resource */
$id = $resource->getId();
@ -289,6 +382,7 @@ class SequenceResourceRepository extends EntityRepository
$resourceItem = [
'name' => $resource->getTitle(),
'code' => $resource->getCode(),
'status' => $status,
];
@ -299,7 +393,7 @@ class SequenceResourceRepository extends EntityRepository
continue;
}
$item['requirements'][$id] = $resourceItem;
$item[$itemType][$id] = $resourceItem;
}
$sequenceList[$sequenceId] = $item;
}
@ -307,94 +401,63 @@ class SequenceResourceRepository extends EntityRepository
return $sequenceList;
}
public function checkCourseRequirements($userId, Course $course, $sessionId): bool
{
$em = $this->getEntityManager();
$sessionId = (int) $sessionId;
$gradebookCategoryRepo = $em->getRepository('ChamiloCoreBundle:GradebookCategory');
$gradebooks = $gradebookCategoryRepo->findBy(
[
'courseCode' => $course->getCode(),
'sessionId' => $sessionId,
'isRequirement' => true,
]
);
if (empty($gradebooks)) {
return false;
}
$status = true;
foreach ($gradebooks as $gradebook) {
$category = Category::createCategoryObjectFromEntity($gradebook);
$userFinishedCourse = Category::userFinishedCourse(
$userId,
$category,
true
);
if (0 === $sessionId) {
if (false === $userFinishedCourse) {
$status = false;
break;
}
} else {
if (false === $userFinishedCourse) {
$status = false;
break;
}
}
}
return $status;
}
/**
* Check if at least one sequence are completed.
* Get the requirements or dependants for a resource only.
*/
public function checkSequenceAreCompleted(array $sequences): bool
private function getRequirementsOrDependents($resourceId, int $resourceType, string $itemType): array
{
foreach ($sequences as $sequence) {
$status = true;
$em = $this->getEntityManager();
foreach ($sequence['requirements'] as $item) {
$status = $status && $item['status'];
}
$sequencesResource = $this->findBy(['resourceId' => $resourceId, 'type' => $resourceType]);
$result = [];
if ($status) {
return true;
}
/** @var SequenceResource $sequenceResource */
foreach ($sequencesResource as $sequenceResource) {
if (!$sequenceResource->hasGraph()) {
continue;
}
return false;
$sequence = $sequenceResource->getSequence();
$graph = $sequence->getUnSerializeGraph();
$vertex = $graph->getVertex($resourceId);
if (self::VERTICES_TYPE_REQ === $itemType) {
$edges = $vertex->getVerticesEdgeFrom();
} else {
$edges = $vertex->getVerticesEdgeTo();
}
/**
* Get sessions from vertices.
*/
protected function findVerticesEdges(Vertices $verticesEdges, int $type): array
{
$sessionVertices = [];
$em = $this->getEntityManager();
$sequenceInfo = [
'name' => $sequence->getName(),
$itemType => [],
];
foreach ($verticesEdges as $supVertex) {
$vertexId = $supVertex->getId();
switch ($type) {
foreach ($edges as $edge) {
$vertexId = $edge->getId();
$resource = null;
switch ($resourceType) {
case SequenceResource::SESSION_TYPE:
$resource = $em->getRepository('ChamiloCoreBundle:Session')->find($vertexId);
$repo = $em->getRepository(Session::class);
$resource = $repo->find($vertexId);
break;
case SequenceResource::COURSE_TYPE:
$resource = $em->getRepository('ChamiloCoreBundle:Course')->find($vertexId);
$repo = $em->getRepository(Course::class);
$resource = $repo->find($vertexId);
break;
}
if (empty($resource)) {
if (null === $resource) {
continue;
}
$sessionVertices[$vertexId] = $resource;
$sequenceInfo[$itemType][$vertexId] = $resource;
}
return $sessionVertices;
$result[$sequence->getId()] = $sequenceInfo;
}
return $result;
}
}

Loading…
Cancel
Save