aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJan-Hendrik Willms <tleilax+studip@gmail.com>2022-11-24 10:29:24 +0000
committerJan-Hendrik Willms <tleilax+studip@gmail.com>2022-11-24 10:29:24 +0000
commit7dddea8ccca601bf2da28960f2e27a223fe60ea6 (patch)
treeb34ee92f9a4e0e4c1f7e4dcf5f15b396f9097d6f /lib
parent1231022837beceedef376e4bb8084ff38fbc7d93 (diff)
rework aux lock rules, use sorm model, deprecate old class and let name and description be translatable, fixes #1791
Closes #1791 Merge request studip/studip!1177
Diffstat (limited to 'lib')
-rw-r--r--lib/classes/AuxLockRules.class.php3
-rw-r--r--lib/classes/Markup.class.php2
-rw-r--r--lib/classes/StudipArrayObject.class.php8
-rw-r--r--lib/classes/WidgetContainer.php5
-rw-r--r--lib/models/AuxLockRule.php133
-rw-r--r--lib/models/DatafieldEntryModel.class.php82
6 files changed, 158 insertions, 75 deletions
diff --git a/lib/classes/AuxLockRules.class.php b/lib/classes/AuxLockRules.class.php
index 6a6dfd9..4d06ca2 100644
--- a/lib/classes/AuxLockRules.class.php
+++ b/lib/classes/AuxLockRules.class.php
@@ -23,6 +23,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+/**
+ * @deprecated since Stud.IP 5.3
+ */
class AuxLockRules
{
diff --git a/lib/classes/Markup.class.php b/lib/classes/Markup.class.php
index af298be..0f5a5c8 100644
--- a/lib/classes/Markup.class.php
+++ b/lib/classes/Markup.class.php
@@ -233,7 +233,7 @@ class Markup
* Create HTML purifier instance with Stud.IP-specific configuration.
*
* @param boolean $autoformat Apply the AutoFormat rules
- * @return HTMLPurifier A new instance of the HTML purifier.
+ * @return \HTMLPurifier A new instance of the HTML purifier.
*/
private static function createPurifier($autoformat)
{
diff --git a/lib/classes/StudipArrayObject.class.php b/lib/classes/StudipArrayObject.class.php
index bb5444c..f025ffb 100644
--- a/lib/classes/StudipArrayObject.class.php
+++ b/lib/classes/StudipArrayObject.class.php
@@ -436,4 +436,12 @@ class StudipArrayObject implements IteratorAggregate, ArrayAccess, Serializable,
throw new InvalidArgumentException("{$key} is a protected property, use a different key");
}
}
+
+ /**
+ * Returns whether the given value is in the underlying array.
+ */
+ public function contains($value): bool
+ {
+ return in_array($value, $this->storage);
+ }
}
diff --git a/lib/classes/WidgetContainer.php b/lib/classes/WidgetContainer.php
index b4aaa8c..108477a 100644
--- a/lib/classes/WidgetContainer.php
+++ b/lib/classes/WidgetContainer.php
@@ -46,10 +46,11 @@ abstract class WidgetContainer
/**
* Add a widget to the container.
*
- * @param Widget $widget The actual widget
+ * @template W of Widget
+ * @param W $widget The actual widget
* @param String $index Optional index/name of the widget, defaults to
* class name without "widget"
- * @return Widget The added widget to allow for easier handling
+ * @return W The added widget to allow for easier handling
*/
public function addWidget(Widget $widget, $index = null)
{
diff --git a/lib/models/AuxLockRule.php b/lib/models/AuxLockRule.php
index d0686a9..4bf8e8b 100644
--- a/lib/models/AuxLockRule.php
+++ b/lib/models/AuxLockRule.php
@@ -13,31 +13,75 @@
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
* @category Stud.IP
* @since 3.0
+ *
* @property string lock_id database column
* @property string id alias column for lock_id
* @property string name database column
* @property string description database column
- * @property string attributes database column
- * @property string sorting database column
+ * @property JSONArrayObject attributes database column
+ * @property JSONArrayObject sorting database column
* @property array datafields computed column
* @property string order computed column
- * @property Course course belongs_to Course
+ * @property Course[]|SimpleORMapCollection courses has_and_belongs_to_many Courses
*/
class AuxLockRule extends SimpleORMap
{
protected static function configure($config = [])
{
$config['db_table'] = 'aux_lock_rules';
- $config['belongs_to']['course'] = [
- 'class_name' => Course::class,
- 'foreign_key' => 'lock_id',
- 'assoc_foreign_key' => 'aux_lock_rule',
+
+ $config['has_many'] = [
+ 'courses' => [
+ 'class_name' => Course::class,
+ 'foreign_key' => 'lock_id',
+ 'assoc_foreign_key' => 'aux_lock_rule',
+ ],
+ ];
+
+ $config['additional_fields'] = [
+ 'datafields' => true
+ ];
+
+ $config['serialized_fields'] = [
+ 'attributes' => JSONArrayObject::class,
+ 'sorting' => JSONArrayObject::class,
];
- $config['additional_fields']['datafields'] = true;
- $config['additional_fields']['order'] = true;
+
+ $config['i18n_fields'] = [
+ 'name' => true,
+ 'description' => true,
+ ];
+
+ $config['registered_callbacks'] = [
+ 'before_store' => [
+ function (AuxLockRule $rule) {
+ $rule->sorting = array_filter($rule->sorting->getArrayCopy(), function ($id) use ($rule) {
+ return $rule->attributes->contains($id);
+ }, ARRAY_FILTER_USE_KEY);
+ },
+ ],
+ 'before_delete' => [
+ function (AuxLockRule $rule) {
+ return count($rule->courses) === 0;
+ },
+ ]
+ ];
+
parent::configure($config);
}
+ public static function findOneByCourse(Course $course): ?AuxLockRule
+ {
+ return self::findOneByCourseId($course->id);
+ }
+
+ public static function findOneByCourseId(string $course_id): ?AuxLockRule
+ {
+ $condition = "JOIN seminare ON lock_id = aux_lock_rule
+ WHERE Seminar_id = ?";
+ return self::findOneBySQL($condition, [$course_id]);
+ }
+
/**
* Cache to avoid loading datafields for a user more than once
*/
@@ -50,8 +94,8 @@ class AuxLockRule extends SimpleORMap
*/
public function getDatafields()
{
- $attributes = json_decode($this->attributes, true) ?: [];
- $sorting = json_decode($this->sorting, true) ?: [];
+ $attributes = $this->attributes->getArrayCopy();
+ $sorting = $this->sorting->getArrayCopy();
foreach ($attributes as $key => $attr) {
if (!$attr) {
@@ -64,11 +108,8 @@ class AuxLockRule extends SimpleORMap
/**
* Updates a datafield of a courseMember by the given data
- *
- * @param object $member
- * @param object $data
*/
- public function updateMember($member, $data)
+ public function updateMember(CourseMember $member, array $data)
{
foreach ($data as $key => $value) {
$datafield = current($this->getDatafield($member, $key));
@@ -88,23 +129,22 @@ class AuxLockRule extends SimpleORMap
*/
public function getCourseData($course = null, $display_only = false)
{
-
// set course
if (!$course) {
$course = $this->course;
}
$mapping = [
- 'vadozent' => join(', ', $course->members->findBy('status', 'dozent')->getUserFullname()),
+ 'vadozent' => join(', ', $course->members->findBy('status', 'dozent')->getUserFullname()),
'vasemester' => $course->start_semester->name,
- 'vatitle' => $course->name,
- 'vanr' => $course->VeranstaltungsNummer,
+ 'vatitle' => $course->name,
+ 'vanr' => $course->veranstaltungsnummer,
];
$head_mapping = [
- 'vadozent' => _('Dozenten'),
+ 'vadozent' => _('Dozenten'),
'vasemester' => _('Semester'),
- 'vatitle' => _('Veranstaltungstitel'),
- 'vanr' => _('Veranstaltungsnummer'),
+ 'vatitle' => _('Veranstaltungstitel'),
+ 'vanr' => _('Veranstaltungsnummer'),
];
// start collecting entries
@@ -145,38 +185,44 @@ class AuxLockRule extends SimpleORMap
return $result;
}
- public function getMemberData($member)
+ public function getMemberData(CourseMember $member)
{
$datafields = SimpleCollection::createFromArray(DatafieldEntryModel::findByModel($member));
$result = [];
- foreach (array_keys($this->datafields) as $field) {
+ foreach ($this->attributes as $field) {
// since we have no only datafields we have to filter!
- if ($new = $datafields->findOneBy('datafield_id', $field)) {
+ $new = $datafields->findOneBy('datafield_id', $field);
+ if ($new) {
$result[] = $new;
}
}
+
+ usort($result, function (DatafieldEntryModel $a, DatafieldEntryModel $b) {
+ $a_order = $this->sorting[$a->datafield_id] ?? 0;
+ $b_order = $this->sorting[$b->datafield_id] ?? 0;
+ return $a_order - $b_order;
+ });
+
return $result;
}
/**
* Caching for the datafields
- * @param type $member
- * @param type $fieldID
- * @return null
*/
- private function getDatafield($member, $fieldID)
+ private function getDatafield(CourseMember $member, $field_id): ?array
{
- if (mb_strlen($fieldID) == 32) {
- if (!array_key_exists($fieldID, $this->datafieldCache)) {
- $this->datafieldCache[$fieldID] = DataField::find($fieldID);
+ if (mb_strlen($field_id) === 32) {
+ if (!array_key_exists($field_id, $this->datafieldCache)) {
+ $this->datafieldCache[$field_id] = DataField::find($field_id);
}
- if (isset($this->datafieldCache[$fieldID])) {
- if ($this->datafieldCache[$fieldID]->object_type == 'usersemdata') {
- $field = current(DatafieldEntryModel::findByModel($member, $fieldID));
+ if (isset($this->datafieldCache[$field_id])) {
+ $field = null;
+ if ($this->datafieldCache[$field_id]->object_type === 'usersemdata') {
+ $field = current(DatafieldEntryModel::findByModel($member, $field_id));
}
- if ($this->datafieldCache[$fieldID]->object_type == 'user') {
- $field = current(DatafieldEntryModel::findByModel(User::find($member->user_id), $fieldID));
+ if ($this->datafieldCache[$field_id]->object_type === 'user') {
+ $field = current(DatafieldEntryModel::findByModel(User::find($member->user_id), $field_id));
}
if ($field) {
$range_id = $field->sec_range_id ? [$field->range_id, $field->sec_range_id] : $field->range_id;
@@ -185,6 +231,19 @@ class AuxLockRule extends SimpleORMap
}
}
}
+
+ return null;
}
+ public static function validateFields(array $fields): bool
+ {
+ $entries = DataField::getDataFields('usersemdata');
+ foreach ($entries as $entry) {
+ if (in_array($entry->id, $fields)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/lib/models/DatafieldEntryModel.class.php b/lib/models/DatafieldEntryModel.class.php
index fa7a878..882b37e 100644
--- a/lib/models/DatafieldEntryModel.class.php
+++ b/lib/models/DatafieldEntryModel.class.php
@@ -48,37 +48,44 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject
*/
public static function findByModel(SimpleORMap $model, $datafield_id = null)
{
- $mask = ["user" => 1, "autor" => 2, "tutor" => 4, "dozent" => 8, "admin" => 16, "root" => 32];
+ $mask = [
+ 'user' => 1,
+ 'autor' => 2,
+ 'tutor' => 4,
+ 'dozent' => 8,
+ 'admin' => 16,
+ 'root' => 32,
+ ];
$sec_range_id = null;
- if (is_a($model, "Course")) {
+ if ($model instanceof Course) {
$params[':institution_ids'] = $model->institutes->pluck('institut_id');
$object_class = SeminarCategories::GetByTypeId($model->status)->id;
$object_type = 'sem';
- $range_id = $model->getId();
- } elseif(is_a($model, "Institute")) {
- $params[':institution_ids'] = [$model->Institut_id];
+ $range_id = $model->id;
+ } elseif ($model instanceof Institute) {
+ $params[':institution_ids'] = [$model->id];
$object_class = $model->type;
$object_type = 'inst';
- $range_id = $model->getId();
- } elseif(is_a($model, "User")) {
+ $range_id = $model->id;
+ } elseif ($model instanceof User) {
$params[':institution_ids'] = $model->institute_memberships->pluck('institut_id');
$object_class = $mask[$model->perms];
$object_type = 'user';
- $range_id = $model->getId();
- } elseif(is_a($model, "CourseMember")) {
+ $range_id = $model->id;
+ } elseif($model instanceof CourseMember) {
$params[':institution_ids'] = $model->course->institutes->pluck('institut_id');
$object_class = $mask[$model->status];
$object_type = 'usersemdata';
$range_id = $model->user_id;
$sec_range_id = $model->seminar_id;
- } elseif(is_a($model, "InstituteMember")) {
+ } elseif($model instanceof InstituteMember) {
$params[':institution_ids'] = [$model->institut_id];
$object_class = $mask[$model->inst_perms];
$object_type = 'userinstrole';
$range_id = $model->user_id;
$sec_range_id = $model->institut_id;
- } elseif (is_a($model, 'ModulDeskriptor')) {
+ } elseif ($model instanceof ModulDeskriptor) {
$params[':institution_ids'] = '';
if (!empty($model->modul->responsible_institute->institut_id)) {
$params[':institution_ids'] = [$model->modul->responsible_institute->institut_id];
@@ -86,7 +93,7 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject
$object_class = $model->getVariant();
$object_type = 'moduldeskriptor';
$range_id = $model->deskriptor_id;
- } elseif (is_a($model, 'ModulteilDeskriptor')) {
+ } elseif ($model instanceof ModulteilDeskriptor) {
$params[':institution_ids'] = [$model->modulteil->modul->responsible_institute->institut_id];
$object_class = $model->getVariant();
$object_type = 'modulteildeskriptor';
@@ -106,46 +113,50 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject
$object_class = $model->getVariant();
$object_type = 'studycourse';
$range_id = $model->studiengang_id;
- }
-
- if (!$object_type) {
+ } else {
throw new InvalidArgumentException('Wrong type of model: ' . get_class($model));
}
- $one_datafield = '';
+
+ $query = "SELECT a.*, b.*, a.datafield_id, b.datafield_id AS isset_content
+ FROM datafields a
+ LEFT JOIN datafields_entries b
+ ON (a.datafield_id=b.datafield_id AND range_id = :range_id AND sec_range_id = :sec_range_id)
+ WHERE object_type = :object_type
+ AND (lang IS NULL OR lang = '')
+ AND (a.institut_id IS NULL OR a.institut_id IN (:institution_ids))";
+
if ($datafield_id !== null) {
- $one_datafield = ' AND a.datafield_id = ' . DBManager::get()->quote($datafield_id);
- } else {
- $one_datafield = '';
+ $query .= ' AND a.datafield_id = :one_datafield_id';
+ $params[':one_datafield_id'] = $datafield_id;
}
- $query = "SELECT a.*, b.*,a.datafield_id,b.datafield_id as isset_content ";
- $query .= "FROM datafields a LEFT JOIN datafields_entries b ON (a.datafield_id=b.datafield_id AND range_id = :range_id AND sec_range_id = :sec_range_id) ";
- $query .= "WHERE object_type = :object_type AND (ISNULL(lang) OR lang = '') AND (a.institut_id IS NULL OR a.institut_id IN (:institution_ids))";
-
if ($object_type === 'studycourse') {
- $query .= "AND (LOCATE(:object_class, object_class) OR LOCATE('all', object_class)) $one_datafield ORDER BY priority";
+ $query .= " AND (LOCATE(:object_class, object_class) OR LOCATE('all', object_class)) ORDER BY priority";
$params = array_merge($params,[
- ':range_id' => (string) $range_id,
+ ':range_id' => (string) $range_id,
':sec_range_id' => (string) $sec_range_id,
- ':object_type' => $object_type,
- ':object_class' => (string) $object_class]);
+ ':object_type' => $object_type,
+ ':object_class' => (string) $object_class,
+ ]);
} elseif ($object_type === 'moduldeskriptor'
|| $object_type === 'modulteildeskriptor') {
// find datafields by language (string)
- $query .= "AND (LOCATE(:object_class, object_class) OR object_class IS NULL) $one_datafield ORDER BY priority";
+ $query .= " AND (LOCATE(:object_class, object_class) OR object_class IS NULL) ORDER BY priority";
$params = array_merge($params,[
- ':range_id' => (string) $range_id,
+ ':range_id' => (string) $range_id,
':sec_range_id' => (string) $sec_range_id,
- ':object_type' => $object_type,
- ':object_class' => (string) $object_class]);
+ ':object_type' => $object_type,
+ ':object_class' => (string) $object_class,
+ ]);
} else {
// find datafields by perms or status (int)
- $query .= "AND ((object_class & :object_class) OR object_class IS NULL) $one_datafield ORDER BY priority";
+ $query .= " AND ((object_class & :object_class) OR object_class IS NULL) ORDER BY priority";
$params = array_merge($params, [
- ':range_id' => (string) $range_id,
+ ':range_id' => (string) $range_id,
':sec_range_id' => (string) $sec_range_id,
- ':object_type' => $object_type,
- ':object_class' => (int) $object_class]);
+ ':object_type' => $object_type,
+ ':object_class' => (int) $object_class,
+ ]);
}
$st = DBManager::get()->prepare($query);
@@ -181,6 +192,7 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject
}
return $ret;
}
+
public function setContentLanguage($language)
{
if (!Config::get()->CONTENT_LANGUAGES[$language]) {