|
19 | 19 | use Joomla\CMS\Component\ComponentHelper; |
20 | 20 | use Joomla\CMS\Factory; |
21 | 21 | use Joomla\Database\DatabaseInterface; |
| 22 | +use Joomla\Database\ParameterType; |
22 | 23 | use Joomla\Database\QueryInterface; |
23 | 24 |
|
24 | 25 | /** |
@@ -204,37 +205,114 @@ public static function applySecurityFilter(QueryInterface $query, string $alias, |
204 | 205 | /** |
205 | 206 | * Return location IDs where the user has an associated teacher record. |
206 | 207 | * |
| 208 | + * Joins through both the many-to-many study_teachers table and the legacy |
| 209 | + * teacher_id column on studies to cover all assignment paths. |
| 210 | + * |
207 | 211 | * @param int $userId Joomla user ID. |
208 | 212 | * |
209 | 213 | * @return int[] Location IDs. |
210 | 214 | * |
211 | | - * @since 10.1.0 |
212 | | - * @todo Implement once a user_id column is added to #__bsms_teachers. |
213 | | - * When available, join: teachers.user_id = $userId |
214 | | - * → study_teachers.teacher_id → studies.location_id. |
| 215 | + * @since 10.3.0 |
215 | 216 | */ |
216 | 217 | public static function getTeacherLocations(int $userId): array |
217 | 218 | { |
218 | | - // Stub: teacher-to-user linkage requires a user_id field on #__bsms_teachers |
219 | | - // which is not present in the current schema. Return empty until Phase 2. |
220 | | - return []; |
| 219 | + if ($userId <= 0) { |
| 220 | + return []; |
| 221 | + } |
| 222 | + |
| 223 | + $db = Factory::getContainer()->get(DatabaseInterface::class); |
| 224 | + |
| 225 | + // Many-to-many path: teachers → study_teachers → studies |
| 226 | + $query1 = $db->getQuery(true) |
| 227 | + ->select('DISTINCT ' . $db->quoteName('s.location_id')) |
| 228 | + ->from($db->quoteName('#__bsms_teachers', 't')) |
| 229 | + ->innerJoin( |
| 230 | + $db->quoteName('#__bsms_study_teachers', 'st') |
| 231 | + . ' ON ' . $db->quoteName('st.teacher_id') . ' = ' . $db->quoteName('t.id') |
| 232 | + ) |
| 233 | + ->innerJoin( |
| 234 | + $db->quoteName('#__bsms_studies', 's') |
| 235 | + . ' ON ' . $db->quoteName('s.id') . ' = ' . $db->quoteName('st.study_id') |
| 236 | + ) |
| 237 | + ->where($db->quoteName('t.user_id') . ' = :userId1') |
| 238 | + ->where($db->quoteName('s.location_id') . ' IS NOT NULL') |
| 239 | + ->where($db->quoteName('s.location_id') . ' > 0') |
| 240 | + ->bind(':userId1', $userId, ParameterType::INTEGER); |
| 241 | + |
| 242 | + // Legacy path: teachers → studies.teacher_id |
| 243 | + $query2 = $db->getQuery(true) |
| 244 | + ->select('DISTINCT ' . $db->quoteName('s.location_id')) |
| 245 | + ->from($db->quoteName('#__bsms_teachers', 't')) |
| 246 | + ->innerJoin( |
| 247 | + $db->quoteName('#__bsms_studies', 's') |
| 248 | + . ' ON ' . $db->quoteName('s.teacher_id') . ' = ' . $db->quoteName('t.id') |
| 249 | + ) |
| 250 | + ->where($db->quoteName('t.user_id') . ' = :userId2') |
| 251 | + ->where($db->quoteName('s.location_id') . ' IS NOT NULL') |
| 252 | + ->where($db->quoteName('s.location_id') . ' > 0') |
| 253 | + ->bind(':userId2', $userId, ParameterType::INTEGER); |
| 254 | + |
| 255 | + $db->setQuery('(' . $query1 . ') UNION (' . $query2 . ')'); |
| 256 | + |
| 257 | + return array_map('intval', $db->loadColumn() ?: []); |
221 | 258 | } |
222 | 259 |
|
223 | 260 | /** |
224 | 261 | * Determine whether a user is a teacher of a specific message. |
225 | 262 | * |
| 263 | + * Checks both the many-to-many study_teachers table and the legacy |
| 264 | + * teacher_id column on the study record. |
| 265 | + * |
226 | 266 | * @param int $userId Joomla user ID. |
227 | 267 | * @param int $messageId Message (study) ID. |
228 | 268 | * |
229 | 269 | * @return bool |
230 | 270 | * |
231 | | - * @since 10.1.0 |
232 | | - * @todo Implement once a user_id column is added to #__bsms_teachers. |
| 271 | + * @since 10.3.0 |
233 | 272 | */ |
234 | 273 | public static function userIsTeacher(int $userId, int $messageId): bool |
235 | 274 | { |
236 | | - // Stub: see getTeacherLocations() note. |
237 | | - return false; |
| 275 | + if ($userId <= 0 || $messageId <= 0) { |
| 276 | + return false; |
| 277 | + } |
| 278 | + |
| 279 | + $db = Factory::getContainer()->get(DatabaseInterface::class); |
| 280 | + |
| 281 | + // Check many-to-many path |
| 282 | + $query = $db->getQuery(true) |
| 283 | + ->select('1') |
| 284 | + ->from($db->quoteName('#__bsms_teachers', 't')) |
| 285 | + ->innerJoin( |
| 286 | + $db->quoteName('#__bsms_study_teachers', 'st') |
| 287 | + . ' ON ' . $db->quoteName('st.teacher_id') . ' = ' . $db->quoteName('t.id') |
| 288 | + ) |
| 289 | + ->where($db->quoteName('t.user_id') . ' = :userId') |
| 290 | + ->where($db->quoteName('st.study_id') . ' = :studyId') |
| 291 | + ->bind(':userId', $userId, ParameterType::INTEGER) |
| 292 | + ->bind(':studyId', $messageId, ParameterType::INTEGER); |
| 293 | + |
| 294 | + $db->setQuery($query, 0, 1); |
| 295 | + |
| 296 | + if ($db->loadResult()) { |
| 297 | + return true; |
| 298 | + } |
| 299 | + |
| 300 | + // Check legacy teacher_id path |
| 301 | + $query2 = $db->getQuery(true) |
| 302 | + ->select('1') |
| 303 | + ->from($db->quoteName('#__bsms_teachers', 't')) |
| 304 | + ->innerJoin( |
| 305 | + $db->quoteName('#__bsms_studies', 's') |
| 306 | + . ' ON ' . $db->quoteName('s.teacher_id') . ' = ' . $db->quoteName('t.id') |
| 307 | + ) |
| 308 | + ->where($db->quoteName('t.user_id') . ' = :userId2') |
| 309 | + ->where($db->quoteName('s.id') . ' = :studyId2') |
| 310 | + ->bind(':userId2', $userId, ParameterType::INTEGER) |
| 311 | + ->bind(':studyId2', $messageId, ParameterType::INTEGER); |
| 312 | + |
| 313 | + $db->setQuery($query2, 0, 1); |
| 314 | + |
| 315 | + return (bool) $db->loadResult(); |
238 | 316 | } |
239 | 317 |
|
240 | 318 | /** |
|
0 commit comments