Select Git revision
RouteMap.php
Forked from
Stud.IP / Stud.IP
Source project has a limited visibility.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Modul.php 37.18 KiB
<?php
/**
* Modul.php
* Model class for Module (table mvv_modul)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* @author Peter Thienel <thienel@data-quest.de>
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
* @category Stud.IP
* @since 3.5
*/
class Modul extends ModuleManagementModelTreeItem
{
protected static function configure($config = [])
{
$config['db_table'] = 'mvv_modul';
$config['has_one']['deskriptoren'] = [
'class_name' => ModulDeskriptor::class,
'assoc_foreign_key' => 'modul_id',
'on_delete' => 'delete',
'on_store' => 'store'
];
$config['belongs_to']['start_semester'] = [
'class_name' => Semester::class,
'foreign_key' => 'start',
];
$config['belongs_to']['end_semester'] = [
'class_name' => Semester::class,
'foreign_key' => 'end',
];
$config['has_many']['modulteile'] = [
'class_name' => Modulteil::class,
'assoc_foreign_key' => 'modul_id',
'on_delete' => 'delete',
'on_store' => 'store',
'order_by' => 'ORDER BY position'
];
// Ist Novellierung von (quelle)
$config['has_one']['modul_quelle'] = [
'class_name' => Modul::class,
'foreign_key' => 'quelle',
'assoc_func' => 'findCached',
];
// Ist Variante von (variante)
$config['has_one']['modul_variante'] = [
'class_name' => Modul::class,
'foreign_key' => 'variante',
'assoc_func' => 'findCached',
];
// hauptverantwortliche Einrichtung
$config['has_one']['responsible_institute'] = [
'class_name' => ModulInst::class,
'assoc_func' => 'findPrimarilyResponsibleInstitute',
'on_delete' => 'delete',
'on_store' => 'store'
];
// beteiligte Einrichtungen
$config['has_many']['assigned_institutes'] = [
'class_name' => ModulInst::class,
'assoc_func' => 'findOtherResponsibleInstitutes',
'on_delete' => 'delete',
'on_store' => 'store'
];
$config['has_many']['contact_assignments'] = [
'class_name' => MvvContactRange::class,
'assoc_foreign_key' => 'range_id',
'order_by' => 'ORDER BY position',
'on_delete' => 'delete',
'on_store' => 'store'
];
$config['has_many']['abschnitte_modul'] = [
'class_name' => StgteilabschnittModul::class,
'assoc_foreign_key' => 'modul_id',
'order_by' => 'ORDER BY position,mkdate',
'on_delete' => 'delete',
'on_store' => 'store'
];
$config['has_and_belongs_to_many']['abschnitte'] = [
'class_name' => StgteilAbschnitt::class,
'thru_table' => 'mvv_stgteilabschnitt_modul',
'thru_key' => 'modul_id',
'thru_assoc_key' => 'abschnitt_id',
'order_by' => 'ORDER BY position,mkdate'
];
// Assigned languages of instruction
$config['has_many']['languages'] = [
'class_name' => ModulLanguage::class,
'assoc_foreign_key' => 'modul_id',
'order_by' => 'ORDER BY position,mkdate',
'on_delete' => 'delete',
'on_store' => 'store'
];
$config['additional_fields']['count_modulteile']['get'] =
function ($modul) { return $modul->count_modulteile; };
$config['additional_fields']['count_modulteile']['set'] = false;
$config['additional_fields']['languagesofinstruction']['get'] =
function ($modul) { return $modul->languages; };
$config['additional_fields']['languagesofinstruction']['set'] = false;
$config['additional_fields']['display_name']['get'] =
function ($modul) { return $modul->getDisplayName(); };
$config['alias_fields']['flexnow_id'] = 'flexnow_modul';
$config['default_values']['stat'] = $GLOBALS['MVV_MODUL']['STATUS']['default'];
parent::configure($config);
}
/**
* The default language of the deskriptor (defined in config).
*
* @var string
*/
private $default_language;
/**
* The number of modulteile.
*
* @var int
*/
private $count_modulteile;
public function __construct($id = null)
{
parent::__construct($id);
$this->object_real_name = _('Modul');
$this->setDefaultLanguage();
}
/**
* @see ModuleManagementModel::getClassDisplayName
*/
public static function getClassDisplayName($long = false)
{
return _('Modul');
}
/**
* Retrieves the module and all related data and some additional fields.
*
* @param string $modul_id The id of the module.
* @return object The module with additional data or a new module.
*/
public static function getEnriched($modul_id)
{
$modul = parent::getEnrichedByQuery('
SELECT mvv_modul.*, mvv_modul_deskriptor.bezeichnung AS bezeichnung,
COUNT(DISTINCT(mvv_modulteil.modulteil_id)) AS count_modulteile
FROM mvv_modul
LEFT JOIN mvv_modul_deskriptor
ON mvv_modul.modul_id = mvv_modul_deskriptor.modul_id
LEFT JOIN mvv_modulteil
ON mvv_modul.modul_id = mvv_modulteil.modul_id
LEFT JOIN mvv_modul_inst
ON (mvv_modul.modul_id = mvv_modul_inst.modul_id
AND mvv_modul_inst.gruppe = ?)
WHERE mvv_modul.modul_id = ?',
[
'hauptverantwortlich',
$modul_id
]
);
if (sizeof($modul)) {
return $modul[$modul_id];
}
return self::get();
}
/**
* Returns all or a specified (by row count and offset) number of
* Module sorted and filtered by given parameters and enriched with some
* additional fields. This function is mainly used in the list view.
*
* @param string $sortby Field name to order by.
* @param string $order ASC or DESC direction of order.
* @param int $row_count The max number of objects to return.
* @param int $offset The first object to return in a result set.
* @param array $filter Key-value pairs of filed names and values
* to filter the result set.
* @return SimpleORMapCollection A collection of module objects.
*/
public static function getAllEnriched($sortby = 'chdate', $order = 'ASC',
$row_count = null, $offset = null, $filter = null)
{
$sortby = self::createSortStatement($sortby, $order, 'bezeichnung,chdate',
words('bezeichnung count_modulteile chdate'));
return parent::getEnrichedByQuery('
SELECT mvv_modul.*, mvv_modul_deskriptor.bezeichnung AS bezeichnung,
COUNT(DISTINCT(mvv_modulteil.modulteil_id)) AS count_modulteile
FROM mvv_modul
LEFT JOIN mvv_modul_deskriptor
ON mvv_modul.modul_id = mvv_modul_deskriptor.modul_id
LEFT JOIN mvv_modulteil
ON mvv_modul.modul_id = mvv_modulteil.modul_id
LEFT JOIN mvv_modul_inst
ON (mvv_modul.modul_id = mvv_modul_inst.modul_id
AND mvv_modul_inst.gruppe = ?)
LEFT JOIN semester_data start_sem
ON (mvv_modul.start = start_sem.semester_id)
LEFT JOIN semester_data end_sem
ON (mvv_modul.end = end_sem.semester_id) '
. self::getFilterSql($filter, true) . '
GROUP BY modul_id
ORDER BY ' . $sortby,
['hauptverantwortlich'],
$row_count,
$offset
);
}
/**
* Returns the number of modules optional filtered by $filter.
*
* @param array $filter Key-value pairs of filed names and values
* to filter the result set.
* @return int The number of modules
*/
public static function getCount($filter = null)
{
$query = '
SELECT COUNT(DISTINCT(mvv_modul.modul_id))
FROM mvv_modul
LEFT JOIN mvv_modul_inst
ON (mvv_modul.modul_id = mvv_modul_inst.modul_id
AND mvv_modul_inst.gruppe = ?)
LEFT JOIN semester_data as start_sem
ON (mvv_modul.start = start_sem.semester_id)
LEFT JOIN semester_data as end_sem
ON (mvv_modul.end = end_sem.semester_id) '
. self::getFilterSql($filter, true);
$db = DBManager::get()->prepare($query);
$db->execute(['hauptverantwortlich']);
return $db->fetchColumn(0);
}
/**
* @see MvvTreeItem::getTrailParentId()
*/
public function getTrailParentId()
{
return ($_SESSION['MVV/Modul/trail_parent_id']);
}
/**
* @see MvvTreeItem::getTrailParent()
*/
public function getTrailParent()
{
return Abschluss::findCached($this->getTrailParentId());
}
/**
* @see MvvTreeItem::getChildren()
*/
public function getChildren()
{
$_SESSION['MVV/Lvgruppe/trail_parent_id'] = $this->getId();
return Lvgruppe::getEnrichedByQuery('
SELECT ml.*
FROM mvv_lvgruppe ml
LEFT JOIN mvv_lvgruppe_modulteil USING (lvgruppe_id)
LEFT JOIN mvv_modulteil USING (modulteil_id)
WHERE modul_id = ? ',
[$this->getId()]
);
}
/**
* @see MvvTreeItem::hasChildren()
*/
public function hasChildren()
{
return count($this->getChildren()) > 0;
}
/**
* @see MvvTreeItem::getParents()
*/
public function getParents($mode = null)
{
return StgteilabschnittModul::findBySQL('modul_id = ?', [$this->id]);
}
public function getDisplayName($options = self::DISPLAY_DEFAULT) {
$options = ($options !== self::DISPLAY_DEFAULT)
? $options : self::DISPLAY_CODE;
$with_code = $options & self::DISPLAY_CODE;
if ($this->isNew()) {
return parent::getDisplayName($options);
}
$name = ($with_code && trim($this->code)) ? $this->code . ' - ' : '';
$name .= $this->deskriptoren->bezeichnung;
if ($options & self::DISPLAY_SEMESTER) {
$sem_validity = $this->getDisplaySemesterValidity();
if ($sem_validity) {
$name .= ', ' . $sem_validity;
}
}
return trim($name);
}
/**
* Returns a string representation of this module's validity by semesters.
*
* @return string The string with the validity by semesters.
*/
public function getDisplaySemesterValidity()
{
$ret = '';
$start_sem = Semester::find($this->start);
$end_sem = Semester::find($this->end);
if ($end_sem || $start_sem) {
if ($end_sem) {
if ($start_sem->name == $end_sem->name) {
$ret .= sprintf(_('gültig im %s'),
$start_sem->name);
} else {
$ret .= sprintf(_('gültig %s bis %s'),
$start_sem->name, $end_sem->name);
}
} else {
$ret .= sprintf(_('gültig ab %s'), $start_sem->name);
}
}
return $ret;
}
/**
* Sets the default language for the module descriptor. Takes the language
* previously set by ApplicationSimpleORMap::setLanguage() or the one
* defined as default in mvv_config.php.
*/
private function setDefaultLanguage()
{
if (isset($GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values']
[ModuleManagementModel::getLanguage()])) {
$this->default_language = ModuleManagementModel::getLanguage();
} else {
$this->default_language =
$GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['default'];
}
}
/**
* Returns the default language for the module descriptor.
*
* @return string Short name of language (see mvv_config.php)
*/
public function getDefaultLanguage()
{
return $this->default_language;
}
/**
* Returns the Deskriptor in the given language. A Modul has always a
* Deskriptor in the default language. If the given language is unknown, the
* method returns the deskriptor in the default language.
*
* @param string $language The id of the language
* @param bool If true returns always a new descriptor
* @return object The Deskriptor.
*/
public function getDeskriptor($language = null, $force_new = false) {
if (!isset($GLOBALS['MVV_MODUL_DESKRIPTOR']['SPRACHE']['values'][$language])) {
$language = $this->default_language;
}
if (!$this->deskriptoren) {
// the module is new and has no descriptor
// return a new descriptor in the default language
$deskriptor = new ModulDeskriptor();
$deskriptor->setNewId();
$deskriptor->modul_id = $this->getId();
$this->deskriptoren = $deskriptor;
}
return $this->deskriptoren;
}
/**
* Assigns the responsible institute to this Modul.
* A Modul has only one (but always one) responsible institute.
*
* @param string $institut_id The id of the institute to assign.
* @return boolean True if institute was successfully assigned.
*/
public function assignResponsibleInstitute($institut_id) {
$institute = Fachbereich::find($institut_id);
if (!$institute) {
return false;
}
if (!$this->responsible_institute || $this->responsible_institute->institut_id !== $institut_id) {
if ($this->responsible_institute) {
$this->responsible_institute->delete();
}
$this->responsible_institute = ModulInst::build([
'institut_id' => $institute->id,
'modul_id' => $this->id,
'gruppe' => 'hauptverantwortlich',
]);
}
$this->assigned_institutes->unsetBy('institut_id', $institute->id);
return true;
}
/**
* Assigns other institutes (by id) to this module.
*
* @param array $institut_ids Array of institute ids.
*/
public function assignInstitutes($institut_ids) {
$institutes = [];
foreach ($institut_ids as $pos => $institut_id) {
$modul_inst = new ModulInst();
$modul_inst->modul_id = $this->id;
$modul_inst->institut_id = $institut_id;
$modul_inst->gruppe = 'verantwortlich';
$modul_inst->position = $pos;
$institutes[] = $modul_inst;
}
$this->assigned_institutes = SimpleORMapCollection::createFromArray($institutes);
}
/**
* Assignes languages of instruction to this part-module.
*
* @param type $languages An array of language keys defined in mvv_config.php.
*/
public function assignLanguagesOfInstruction($languages)
{
$assigned_languages = [];
$languages_flipped = array_flip($languages);
foreach ($GLOBALS['MVV_MODUL']['SPRACHE']['values'] as $key => $language) {
if (isset($languages_flipped[$key])) {
$language = ModulLanguage::find([$this->id, $key]);
if (!$language) {
$language = new ModulLanguage();
$language->modul_id = $this->id;
$language->lang = $key;
}
$language->position = $languages_flipped[$key];
$assigned_languages[] = $language;
}
}
$this->languages = SimpleORMapCollection::createFromArray(
$assigned_languages);
}
public function getResponsibleInstitutes()
{
if ($this->responsible_institute) {
$inst = Institute::find($this->responsible_institute->institut_id);
if ($inst) {
return [$inst];
}
}
return parent::getResponsibleInstitutes();
}
/**
* Returns a "deep" copy of this object.
*
* @param boolean $deep Copy all assigned modulteile if true
* @return Modul A copy of this module.
*/
public function copy($deep = true, $with_assignments = false)
{
$copy = clone $this;
$copy->setNew(true);
$copy->setNewId();
// reset flexnow id because it's a unique foreign key.
$copy->flexnow_modul = '';
if ($this->responsible_institute) {
$copy->responsible_institute = clone $this->responsible_institute;
$copy->responsible_institute->modul_id = $copy->id;
$copy->responsible_institute->setNew(true);
}
$copy->deskriptoren = clone $this->deskriptoren;
$copy->deskriptoren->modul_id = $copy->id;
$copy->deskriptoren->setNewId();
$copy->deskriptoren->setNew(true);
$institutes = [];
foreach ($this->assigned_institutes as $assigned_institute) {
$cloned_inst = clone $assigned_institute;
$cloned_inst->modul_id = $copy->id;
$cloned_inst->setNew(true);
$institutes[] = $cloned_inst;
}
$copy->assigned_institutes = SimpleORMapCollection::createFromArray($institutes);
$contacts = [];
foreach ($this->contact_assignments as $contact) {
$position = 1;
$cloned_contact = clone $contact;
$cloned_contact->position = $position++;
$cloned_contact->range_id = $copy->id;
$cloned_contact->setNewId();
$cloned_contact->setNew(true);
$contacts[] = $cloned_contact;
}
$copy->contact_assignments = SimpleORMapCollection::createFromArray($contacts);
$languages = [];
foreach ($this->languages as $assigned_language) {
$cloned_language = clone $assigned_language;
$cloned_language->setNew(true);
$languages[] = $cloned_language;
}
$copy->languages = SimpleORMapCollection::createFromArray($languages);
if ($deep) {
$modulteile = [];
$position = 1;
foreach ($this->modulteile as $modulteil) {
$modulteil_copy = $modulteil->copy(true, $with_assignments);
$modulteil_copy->position = $position++;
$modulteile[] = $modulteil_copy;
}
$copy->modulteile = SimpleORMapCollection::createFromArray($modulteile);
if ($with_assignments) {
$abschnitte_modul = [];
foreach ($this->abschnitte_modul as $abschnitt_modul) {
$cloned_abschnitt_modul = clone $abschnitt_modul;
$cloned_abschnitt_modul->setNew(true);
$abschnitte_modul[] = $cloned_abschnitt_modul;
}
$copy->abschnitte_modul = SimpleORMapCollection::createFromArray($abschnitte_modul);
}
}
return $copy;
}
public static function findBySearchTerm($term, $filter = null)
{
$term = '%' . $term . '%';
return parent::getEnrichedByQuery("
SELECT mvv_modul.*,
CONCAT(mvv_modul_deskriptor.bezeichnung, ' (', code, ')') AS name
FROM mvv_modul
LEFT JOIN mvv_modul_deskriptor USING(modul_id)
LEFT JOIN mvv_modul_inst
ON (mvv_modul.modul_id = mvv_modul_inst.modul_id)
LEFT JOIN semester_data as start_sem
ON (mvv_modul.start = start_sem.semester_id)
LEFT JOIN semester_data as end_sem
ON (mvv_modul.end = end_sem.semester_id)
WHERE (code LIKE :term OR mvv_modul_deskriptor.bezeichnung LIKE :term) "
. self::getFilterSql($filter) . "
ORDER BY name",
[':term' => $term]
);
}
/**
* Returns all modules assigned to the given Studiengangteil-Abschnitt.
*
* @param string $abschnitt_id The id of a Studiengangteil-Abschnitt
* @param array $filter Key-value pairs of filed names and values
* to filter the result set.
* @return object A SimpleORMapCollection of modules.
*/
public static function findByStgteilAbschnitt($abschnitt_id, $filter)
{
return parent::getEnrichedByQuery('
SELECT mvv_modul.* FROM mvv_modul
LEFT JOIN mvv_stgteilabschnitt_modul USING(modul_id)
LEFT JOIN semester_data start_sem
ON (mvv_modul.start = start_sem.semester_id)
LEFT JOIN semester_data end_sem
ON (mvv_modul.end = end_sem.semester_id)
WHERE mvv_stgteilabschnitt_modul.abschnitt_id = ? '
. self::getFilterSql($filter) . '
ORDER BY position, mkdate',
[$abschnitt_id]
);
}
/**
* Primarily to find Module by Institute. Possible filters are all fields
* of the tables mvv_modul, mvv_modulteil, mvv_modul_inst and
* mvv_modul_deskriptor.
*
* Possible fileds to sort by are count_modulteile, bezeichnung (the name
* of the modul dereived from the descriptor in the default language) and
* all fields of table mvv_modul.
*
* @param string $sortby
* @param string $order
* @param array $filter
* @param int $row_count
* @param int $offset
* @return array Array of Module.
*/
public static function findByInstitut($sortby = 'chdate', $order = 'ASC',
$filter = [], $row_count = null, $offset = null)
{
$sortby = self::createSortStatement($sortby, $order, 'chdate',
['count_modulteile', 'bezeichnung']);
return parent::getEnrichedByQuery('
SELECT mvv_modul.*, mvv_modul_deskriptor.bezeichnung,
COUNT(DISTINCT(mvv_modulteil.modulteil_id)) AS count_modulteile
FROM mvv_modul
LEFT JOIN mvv_modulteil
ON mvv_modul.modul_id = mvv_modulteil.modul_id
INNER JOIN mvv_modul_inst
ON mvv_modul.modul_id = mvv_modul_inst.modul_id
LEFT JOIN mvv_modul_deskriptor
ON mvv_modul_deskriptor.modul_id = mvv_modul.modul_id
LEFT JOIN semester_data start_sem
ON (mvv_modul.start = start_sem.semester_id)
LEFT JOIN semester_data end_sem
ON (mvv_modul.end = end_sem.semester_id) '
. self::getFilterSql($filter, true) .'
GROUP BY modul_id
ORDER BY ' . $sortby,
[],
$row_count,
$offset
);
}
/**
* Returns all modules the given LV-Gruppe is assigned to at least
* one Modulteile.
*
* @param string $lvgruppe_id The id of a LV-Gruppe.
* @return object A SimpleORMapCollection of modules.
*/
public static function findByLvgruppe($lvgruppe_id)
{
return parent::getEnrichedByQuery('
SELECT mm.*
FROM mvv_modul mm
LEFT JOIN mvv_modulteil mmt USING(modul_id)
LEFT JOIN mvv_lvgruppe_modulteil mlm USING(modulteil_id)
WHERE mlm.lvgruppe_id = ? ',
[$lvgruppe_id]
);
}
/**
* Returns all Institutes assigned to the given modules.
*
* @param string $sortby Field to sort by.
* @param string $order Order of sorting (ASC or DESC).
* @param array $modul_ids Ids of modules.
* @return object a SimpleORMapColection of institutes.
*/
public static function getAssignedInstitutes($sortby = 'name',
$order = 'ASC', $modul_ids = [])
{
return self::getAllAssignedInstitutes($sortby, $order,
['mvv_modul.modul_id' => $modul_ids]);
}
/**
* Returns all institutes assigned to Module. Sorted and filtered by
* optional parameters.
*
* @param string $sortby DB field to sort by.
* @param string $order ASC or DESC
* @param array $filter Array of filter.
* @return array Array of found Fachbereiche.
*/
public static function getAllAssignedInstitutes($sortby = 'name',
$order = 'ASC', $filter = null, $row_count = null, $offset = null)
{
$sortby = Fachbereich::createSortStatement($sortby, $order, 'name',
['count_objects']);
return Fachbereich::getEnrichedByQuery('
SELECT Institute.*,
Institute.Name as `name`,
Institute.Institut_id AS institut_id,
COUNT(DISTINCT modul_id) as count_objects
FROM Institute
INNER JOIN mvv_modul_inst
ON Institute.Institut_id = mvv_modul_inst.institut_id
INNER JOIN mvv_modul USING(modul_id)
LEFT JOIN semester_data start_sem
ON (mvv_modul.start = start_sem.semester_id)
LEFT JOIN semester_data end_sem
ON (mvv_modul.end = end_sem.semester_id)
'.Fachbereich::getFilterSql($filter, true).'
GROUP BY institut_id ORDER BY ' . $sortby,
[],
$row_count,
$offset
);
}
/**
* Returns an array with all types of status found by given
* modul ids as key and the number of associated module as
* value.
*
* @see mvv_config.php for defined status.
* @param array $modul_ids
* @return array An array with status key as key and an array of name of
* status and number of Module with this status.
*/
public static function findStatusByIds($modul_ids = null)
{
if (is_array($modul_ids)) {
$stmt = DBManager::get()->prepare("
SELECT IFNULL(stat, '__undefined__') AS stat,
COUNT(modul_id) AS count_module
FROM mvv_modul WHERE modul_id IN (?)
GROUP BY stat
");
$stmt->execute([$modul_ids]);
} else {
$stmt = DBManager::get()->prepare("
SELECT IFNULL(stat, '__undefined__') AS stat,
COUNT(modul_id) AS count_module
FROM mvv_modul GROUP BY stat
");
$stmt->execute();
}
$result = [];
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $status) {
$result[$status['stat']] = [
'name' => $GLOBALS['MVV_MODUL']['STATUS']['values'][$status['stat']]['name'],
'count_objects' => $status['count_module']
];
}
return $result;
}
/**
* Returns an array with ids of all modules found by the given filter.
* The fields from tables mvv_modul and mvv_modul_inst are possible filter
* options.
* If no filter is set an empty array will be returned.
*
* @see ModuleManagementModel::getFilterSql()
* @param array $filter Key-value pairs of filed names and values
* to filter the result set.
* @return array An array of Modul ids.
*/
public static function findByFilter($filter)
{
$filter_sql = self::getFilterSql($filter, true);
if ($filter_sql == '') {
return [];
}
$stmt = DBManager::get()->prepare('
SELECT DISTINCT mvv_modul.modul_id
FROM mvv_modul
LEFT JOIN mvv_modulteil
ON mvv_modul.modul_id = mvv_modulteil.modul_id
LEFT JOIN mvv_modul_inst
ON (mvv_modul.modul_id = mvv_modul_inst.modul_id)
LEFT JOIN semester_data start_sem
ON (mvv_modul.start = start_sem.semester_id)
LEFT JOIN semester_data end_sem
ON (mvv_modul.end = end_sem.semester_id) '
. $filter_sql
);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
}
/**
* Retrieves all modules this module ia a variant of.
*
* @return array An array of all variants.
*/
public function getVariants()
{
$variants = [];
foreach (Modul::findBySql('variante = '
. DBManager::get()->quote($this->getId())) as $variant) {
$variants[$variant->getId()] = $variant;
}
return $variants;
}
/**
* Search modules by search term. This function is used in the
* search frontend for modules.
*
* @param string $search_term
* @param boolean $only_public If true search only for modules
* with public status.
*/
public static function search($search_term, $only_public = true)
{
$term = '%' . $search_term . '%';
if ($only_public) {
$public_status = ModuleManagementModel::getPublicStatus('Modul');
if (count($public_status)) {
$stmt = DBManager::get()->prepare('
SELECT mm.modul_id
FROM mvv_modul mm
INNER JOIN mvv_modul_deskriptor mmd USING(modul_id)
LEFT JOIN mvv_stgteilabschnitt_modul msm ON mmd.modul_id = msm.modul_id
LEFT JOIN mvv_stgteilabschnitt USING(abschnitt_id)
LEFT JOIN mvv_stgteilversion msv USING(version_id)
WHERE (
mm.code LIKE :term
OR mmd.bezeichnung LIKE :term
OR msm.bezeichnung LIKE :term
)
AND mm.stat IN (:stat)
AND msv.stat IN (:stat)
GROUP BY mm.modul_id
');
$stmt->execute([':term' => $term, ':stat' => $public_status]);
return $stmt->fetchAll(PDO::FETCH_COLUMN);
}
} else {
$stmt = DBManager::get()->prepare('
SELECT mm.modul_id
FROM mvv_modul mm
LEFT JOIN mvv_modul_deskriptor mmd USING(modul_id)
WHERE code LIKE :term OR mmd.bezeichnung LIKE :term
GROUP BY modul_id
');
$stmt->execute([':term' => $term]);
return $stmt->fetchAll(PDO::FETCH_COLUMN);
}
return [];
}
public function validate()
{
$ret = parent::validate();
if ($this->isDirty()) {
$messages = [];
$rejected = false;
if ($this->variante) {
$variante = Modul::find($this->variante);
if (is_null($variante)) {
$ret['variante'] = true;
$messages[] = _('Unbekanntes Modul als Vorlage.');
$rejected = true;
}
}
if (!$this->responsible_institute || !$this->responsible_institute->institut_id) {
$ret['rsponsible_institute'] = true;
$messages[] = _('Es muss mindestens eine verantwortliche Einrichtung zugewiesen werden.');
$rejected = true;
} else {
$this->responsible_institute->validate();
}
if ($this->start) {
$start_sem = Semester::find($this->start);
if (!$start_sem) {
$ret['start'] = true;
$messages[] = _('Ungültiges Semester.');
$rejected = true;
} else if ($this->end) {
$end_sem = Semester::find($this->end);
if ($end_sem) {
if ($start_sem->beginn > $end_sem->beginn) {
$ret['start'] = true;
$messages[] = _('Das Endsemester muss nach dem Startsemester liegen.');
$rejected = true;
}
} else {
$ret['end'] = true;
$messages[] = _('Ungültiges Endsemester.');
$rejected = true;
}
}
} else {
$ret['start'] = true;
$messages[] = _('Bitte ein Startsemester angeben.');
$rejected = true;
}
if (mb_strlen($this->code) < 3) {
$ret['code'] = true;
$messages[] = _('Der Modulcode ist zu kurz (mindestens 3 Zeichen).');
$rejected = true;
} else {
if ($this->isNew()) {
// The code of the Modul has to be unique
$existing = $this->findBySql('code = ' . DBManager::get()->quote($this->code));
if (sizeof($existing)) {
$ret['code'] = true;
$messages[] = sprintf(_('Es existiert bereits ein Modul mit dem Code "%s"!'),
$this->code);
$rejected = true;
}
}
}
if (!(preg_match('/\d{0,2}/', $this->dauer) && $this->dauer >= 1)) {
$ret['dauer'] = true;
$messages[] = _('Die Dauer (in Semestern) des Moduls muss angegeben werden.');
$rejected = true;
}
if (!((preg_match('/\d{0,4}/', $this->kapazitaet)
&& $this->kapazitaet > 0) || $this->kapazitaet === '')) {
$ret['kapazitaet'] = true;
$messages[] = _('Die Kapazität/Teilnehmendenzahl des Moduls muss angegeben werden.');
$rejected = true;
}
if (!(preg_match('/\d{1,3}/', $this->kp) && $this->kp >= 1)) {
$ret['kp'] = true;
$messages[] = _('Die Kreditpunkte müssen angegeben werden.');
$rejected = true;
}
if (!(is_float($this->faktor_note * 1.0) && $this->faktor_note >= 0.1)) {
$ret['faktor_note'] = true;
$messages[] = _('Der Notenfaktor für die Endnote des Studiengangs muss angegeben werden.');
$rejected = true;
}
if ($this->fassung_nr) {
if (!is_numeric($this->fassung_nr)) {
$ret['fassung_nr'] = true;
$messages[] = _('Für Fassung bitte eine Zahl angeben.');
$rejected = true;
}
if (!$GLOBALS['MVV_MODUL']['FASSUNG_TYP'][$this->fassung_typ]) {
$ret['fassung_typ'] = true;
$messages[] = _('Bitte einen Typ der Fassung angeben.');
$rejected = true;
}
}
if ($rejected) {
throw new InvalidValuesException(join("\n", $messages), $ret);
}
$this->deskriptoren->validate();
foreach ($this->assigned_institutes as $assigned_institute) {
$assigned_institute->validate();
}
}
return $ret;
}
/**
* Checks if modules with public status are available.
*
* @return boolean true if modules with public status available
*/
public static function publicModulesAvailable()
{
$public_status = ModuleManagementModel::getPublicStatus('Modul');
if (count($public_status)) {
$stmt = DBManager::get()->prepare('
SELECT 1
FROM mvv_modul mm
INNER JOIN mvv_modul_deskriptor mmd USING(modul_id)
INNER JOIN mvv_stgteilabschnitt_modul msm ON mmd.modul_id = msm.modul_id
INNER JOIN mvv_stgteilabschnitt USING(abschnitt_id)
INNER JOIN mvv_stgteilversion msv USING(version_id)
WHERE mm.stat IN (:stat)
AND msv.stat IN (:stat) LIMIT 1
');
$stmt->execute([':stat' => $public_status]);
return (bool)$stmt->fetchColumn();
}
return false;
}
/**
* Retrieves all courses this Modul is assigned by its parts and assigned
* LV-Gruppen.
* Filtered by a given semester considering the global visibility or the
* the visibility for a given user.
*
* @param string $semester_id The id of a semester.
* @param mixed $only_visible Boolean true retrieves only visible courses, false
* retrieves all courses. If $only_visible is an user id it depends on the users
* status which courses will be retrieved.
* @return array An array of course data.
*/
public function getAssignedCoursesBySemester($semester_id, $only_visible = true)
{
$courses = [];
foreach ($this->modulteile as $modulteil) {
$mt_courses = $modulteil->getAssignedCoursesBySemester($semester_id, $only_visible);
foreach ($mt_courses as $course) {
$courses[$course->id] = $course;
}
}
return $courses;
}
}