diff --git a/main/admin/career_diagram.php b/main/admin/career_diagram.php new file mode 100644 index 0000000000..38cd9ae959 --- /dev/null +++ b/main/admin/career_diagram.php @@ -0,0 +1,95 @@ + 'index.php', + 'name' => get_lang('PlatformAdmin'), +); +$interbreadcrumb[] = array( + 'url' => 'career_dashboard.php', + 'name' => get_lang('CareersAndPromotions'), +); + +$interbreadcrumb[] = array( + 'url' => 'careers.php', + 'name' => get_lang('Careers'), +); + +$action = isset($_GET['action']) ? $_GET['action'] : null; + +$check = Security::check_token('request'); +$token = Security::get_token(); + +if ($action == 'add') { + $interbreadcrumb[] = array('url' => 'careers.php', 'name' => get_lang('Careers')); + $tool_name = get_lang('Add'); +} elseif ($action == 'edit') { + $interbreadcrumb[] = array('url' => 'careers.php', 'name' => get_lang('Careers')); + $interbreadcrumb[] = array('url' => '#', 'name' => get_lang('Edit')); + $tool_name = get_lang('Edit'); +} else { + $tool_name = get_lang('Careers'); +} + +$career = new Career(); +$careerInfo = $career->get($careerId); +if (empty($careerInfo)) { + api_not_allowed(true); +} + +$extraFieldValue = new ExtraFieldValue('career'); +$item = $extraFieldValue->get_values_by_handler_and_field_variable( + $careerId, + 'career_diagram', + false, + false, + false +); + +if (!empty($item) && isset($item['value']) && !empty($item['value'])) { + $graph = unserialize($item['value']); + $html = Display::page_header($careerInfo['name']); + $html .= Career::renderDiagram($graph); + $tpl = new Template(''); + $tpl->assign('content', $html); + $tpl->display_one_col_template(); +} diff --git a/main/admin/careers.php b/main/admin/careers.php index c3aa5e97b8..3fb89cfd81 100755 --- a/main/admin/careers.php +++ b/main/admin/careers.php @@ -81,9 +81,16 @@ $extra_params['autowidth'] = 'true'; //height auto $extra_params['height'] = 'auto'; +$diagramLink = ''; +$allow = api_get_configuration_value('allow_career_diagram'); +if ($allow) { + $diagramLink = ''.get_lang('Diagram').''; +} + //With this function we can add actions to the jgrid (edit, delete, etc) $action_links = 'function action_formatter(cellvalue, options, rowObject) { return \''.Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL).''. + $diagramLink. ' '.Display::return_icon('copy.png', get_lang('Copy'), '', ICON_SIZE_SMALL).''. ' '.Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).''. '\'; diff --git a/main/cron/import_csv.php b/main/cron/import_csv.php index 95e32a62f3..88817210f7 100755 --- a/main/cron/import_csv.php +++ b/main/cron/import_csv.php @@ -4,6 +4,13 @@ use Chamilo\CourseBundle\Entity\CCalendarEvent; use Chamilo\CourseBundle\Entity\CItemProperty; use Chamilo\PluginBundle\Entity\StudentFollowUp\CarePost; +use Fhaculty\Graph\Graph; +use Graphp\GraphViz\GraphViz; +use Monolog\Logger; +use Monolog\Handler\StreamHandler; +use Monolog\Handler\NativeMailerHandler; +use Monolog\Handler\RotatingFileHandler; +use Monolog\Handler\BufferHandler; if (PHP_SAPI != 'cli') { die('Run this script through the command line or comment this line in the code'); @@ -33,6 +40,8 @@ class ImportCsv 'course' => 'external_course_id', 'user' => 'external_user_id', 'calendar_event' => 'external_calendar_event_id', + 'career' => 'external_career_id', + 'career_diagram' => 'career_diagram', ); public $defaultAdminId = 1; public $defaultSessionVisibility = 1; @@ -137,10 +146,13 @@ class ImportCsv $method = 'importUnsubsessionsExtidStatic'; } + if ($method == 'importCareersdiagram') { + $method = 'importCareersDiagram'; + } + if ($method == 'importSubsessionsextidStatic') { $method = 'importSubscribeUserToCourseSessionExtStatic'; } - if (method_exists($this, $method)) { if (( $method == 'importSubscribeStatic' || @@ -186,6 +198,8 @@ class ImportCsv 'courseinsert-static', 'unsubscribe-static', 'care', + 'careers', + 'careersdiagram' ); foreach ($sections as $section) { @@ -291,6 +305,25 @@ class ImportCsv 'display_text' => 'External calendar event id', ) ); + + $extraField = new ExtraField('career'); + $extraField->save( + array( + 'visible_to_self' => 1, + 'field_type' => ExtraField::FIELD_TYPE_TEXT, + 'variable' => $this->extraFieldIdNameList['career'], + 'display_text' => 'External career id', + ) + ); + + $extraField->save( + array( + 'visible_to_self' => 1, + 'field_type' => ExtraField::FIELD_TYPE_TEXTAREA, + 'variable' => $this->extraFieldIdNameList['career_diagram'], + 'display_text' => 'Career diagram', + ) + ); } /** @@ -2192,6 +2225,255 @@ class ImportCsv return $date; } + /** + * @param $file + * @param bool $moveFile + * @param array $teacherBackup + * @param array $groupBackup + * @return bool + */ + private function importCareers( + $file, + $moveFile = false, + &$teacherBackup = array(), + &$groupBackup = array() + ) { + $data = Import::csv_reader($file); + + if (!empty($data)) { + $this->logger->addInfo(count($data)." records found."); + $extraFieldValue = new ExtraFieldValue('career'); + $extraFieldName = $this->extraFieldIdNameList['career']; + $externalEventId = null; + + $extraField = new ExtraField('career'); + $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable( + $extraFieldName + ); + + if (empty($extraFieldInfo)) { + return false; + } + + foreach ($data as $row) { + foreach ($row as $key => $value) { + $key = (string)trim($key); + // Remove utf8 bom + $key = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $key); + $row[$key] = $value; + } + + $itemId = $row['CareerId']; + $item = $extraFieldValue->get_item_id_from_field_variable_and_field_value( + $extraFieldName, + $itemId, + false, + false, + false + ); + + $career = new Career(); + if (empty($item)) { + $params = [ + 'status' => 1, + 'name' => $row['CareerName'] + ]; + $careerId = $career->save($params); + if ($careerId) { + $params = [ + 'item_id' => $careerId, + 'extra_'.$extraFieldName => $itemId, + ]; + $extraFieldValue->saveFieldValues($params); + } + } else { + if (isset($item['item_id'])) { + $params = [ + 'id' => $item['item_id'], + 'name' => $row['CareerName'] + ]; + $career->update($params); + } + } + } + } + } + + /** + * @param $file + * @param bool $moveFile + * @param array $teacherBackup + * @param array $groupBackup + */ + private function importCareersDiagram( + $file, + $moveFile = false, + &$teacherBackup = array(), + &$groupBackup = array() + ) { + $data = Import::csv_reader($file); + + $extraFieldValue = new ExtraFieldValue('career'); + $extraFieldName = $this->extraFieldIdNameList['career']; + $externalEventId = null; + + $extraField = new ExtraField('career'); + $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable( + $extraFieldName + ); + + $careerDiagramExtraFieldName = $this->extraFieldIdNameList['career_diagram']; + $extraFieldDiagramInfo = $extraField->get_handler_field_info_by_field_variable( + $careerDiagramExtraFieldName + ); + + if (empty($extraFieldInfo) || empty($extraFieldDiagramInfo)) { + return false; + } + + if (!empty($data)) { + $this->logger->addInfo(count($data)." records found."); + $values = []; + foreach ($data as $row) { + foreach ($row as $key => $value) { + $key = (string) trim($key); + // Remove utf8 bom + $key = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $key); + $row[$key] = $value; + } + $values[$row['Column']][] = $row; + } + + $careerList = []; + $careerNameList = []; + ksort($values); + $careerChamiloIdList = []; + // 1. First create all items + foreach ($values as $column => $rowList) { + foreach ($rowList as $row) { + $careerId = $row['CareerId']; + + $item = $extraFieldValue->get_item_id_from_field_variable_and_field_value( + $extraFieldName, + $careerId, + false, + false, + false + ); + + $chamiloCareerName = ''; + if (empty($item)) { + $this->logger->addInfo("Career not found: $careerId"); + continue; + } else { + if (isset($item['item_id'])) { + $careerChamiloId = $item['item_id']; + $career = new Career(); + $career = $career->find($careerChamiloId); + $chamiloCareerName = $career['name']; + $careerNameList[$careerId] = $chamiloCareerName; + $careerChamiloIdList[$careerId] = $careerChamiloId; + } else { + continue; + } + } + + if (empty($chamiloCareerName)) { + $this->logger->addInfo("Career not found: $careerId"); + continue; + } + + if (isset($careerList[$careerId])) { + $graph = $careerList[$careerId]; + } else { + $graph = new Graph($careerId); + $graph->setAttribute('graphviz.graph.rankdir', 'LR'); + $careerList[$careerId] = $graph; + } + + $currentCourseId = (int)$row['CourseId']; + $name = $row['CourseName']; + $hasColor = $row['HasColor']; + $notes = $row['Notes']; + + if ($graph->hasVertex($currentCourseId)) { + // Avoid double insertion + continue; + } else { + $current = $graph->createVertex($currentCourseId); + $current->setAttribute('graphviz.label', $name); + $current->setAttribute('HasColor', $hasColor); + $current->setAttribute('Notes', $notes); + //$current->setAttribute('graphviz.color', 'blue'); + $current->setAttribute('graphviz.shape', 'box'); + $current->setGroup($column); + } + } + } + + // 2. Create connections + // $column start with 1 (depending in Column row) + foreach ($values as $column => $rowList) { + foreach ($rowList as $row) { + $careerId = $row['CareerId']; + if (isset($careerList[$careerId])) { + $graph = $careerList[$careerId]; + } else { + continue; + } + + $currentCourseId = (int) $row['CourseId']; + if ($graph->hasVertex($currentCourseId)) { + $current = $graph->getVertex($currentCourseId); + } else { + continue; + } + + if (isset($row['DependedOn']) && !empty($row['DependedOn'])) { + $parentList = explode(',', $row['DependedOn']); + foreach ($parentList as $parentId) { + $parentId = (int) $parentId; + echo $parentId.PHP_EOL; + if ($graph->hasVertex($parentId)) { + $parent = $graph->getVertex($parentId); + /*$parent->setAttribute('graphviz.color', 'red'); + $parent->setAttribute('graphviz.label', $name); + $parent->setAttribute('graphviz.shape', 'square');*/ + $parent->createEdgeTo($current); + } + } + } + } + } + + // 2. Transform the graph into a jsplumb graph + $html = ''; + /** @var Graph $graph */ + foreach ($careerList as $id => $graph) { + if ($id != 631) { + //continue; + } + + if (isset($careerChamiloIdList[$id])) { + $params = [ + 'item_id' => $careerChamiloIdList[$id], + 'extra_'.$careerDiagramExtraFieldName => serialize($graph), + 'extra_'.$extraFieldName => $id, + ]; + $extraFieldValue->saveFieldValues($params); + } + } + } + } + + /** * @param string $file * @param bool $moveFile @@ -2451,15 +2733,8 @@ class ImportCsv Database::query($sql); } } - } -use Monolog\Logger; -use Monolog\Handler\StreamHandler; -use Monolog\Handler\NativeMailerHandler; -use Monolog\Handler\RotatingFileHandler; -use Monolog\Handler\BufferHandler; - $logger = new Logger('cron'); $emails = isset($_configuration['cron_notification_mails']) ? $_configuration['cron_notification_mails'] : null; diff --git a/main/inc/ajax/sequence.ajax.php b/main/inc/ajax/sequence.ajax.php index 4a8d8cd60a..e3ad693fed 100644 --- a/main/inc/ajax/sequence.ajax.php +++ b/main/inc/ajax/sequence.ajax.php @@ -5,6 +5,7 @@ use Chamilo\CoreBundle\Entity\Sequence; use Chamilo\CoreBundle\Entity\SequenceResource; use Fhaculty\Graph\Graph; use Fhaculty\Graph\Vertex; +use Graphp\GraphViz\GraphViz; /** * Responses to AJAX calls @@ -37,7 +38,7 @@ switch ($action) { if ($sequence->hasGraph()) { $graph = $sequence->getUnSerializeGraph(); $graph->setAttribute('graphviz.node.fontname', 'arial'); - $graphviz = new \Graphp\GraphViz\GraphViz(); + $graphviz = new GraphViz(); $graphImage = ''; try { $graphImage = $graphviz->createImageHtml($graph); diff --git a/main/inc/lib/career.lib.php b/main/inc/lib/career.lib.php index b870b4d399..b84e86e8eb 100755 --- a/main/inc/lib/career.lib.php +++ b/main/inc/lib/career.lib.php @@ -275,4 +275,151 @@ class Career extends Model return parent::update($params); } + + /** + * @param \Fhaculty\Graph\Graph $graph + * + * @return string + */ + public static function renderDiagram($graph) + { + if (!($graph instanceof \Fhaculty\Graph\Graph)) { + return ''; + } + + $debug = false; + $maxColumn = 0; + foreach ($graph->getVertices() as $vertex) { + $groupId = (int) $vertex->getGroup(); + if ($groupId > $maxColumn) { + $maxColumn = $groupId; + } + } + + $width = 80 / $maxColumn; + //var_dump($maxColumn); + //$width = 100; + //$groupWidth = $width + 30; + $defaultSpace = 40; + $group = 0; + /** @var \Fhaculty\Graph\Vertex $vertex */ + $counter = 0; + $html = ''; + foreach ($graph->getVertices() as $vertex) { + $id = $vertex->getId(); + $windowId = "window_$id"; + $groupId = $vertex->getGroup(); + $groupJsId = "group_$groupId"; + + if ($group != $vertex->getGroup()) { + if ($group > 0) { + $counter = 0; + $html .= ''.PHP_EOL; + } + + $left = ($defaultSpace).'px'; + if ($group == 0) { + $left = 0; + } + $html .= PHP_EOL.'