Skip to content

Location API Reference

Brent Cordis edited this page Feb 18, 2026 · 1 revision

Location API Reference

Developer reference for the Proclaim multi-campus location system introduced in 10.1.0.

Namespace: CWM\Component\Proclaim\Administrator\Helper\CwmlocationHelper File: admin/src/Helper/CwmlocationHelper.php


Overview

CwmlocationHelper is a static utility class that determines which campus locations a user can access. It uses a three-source model:

  1. Group Locations — locations explicitly mapped to the user's Joomla groups in component params
  2. Teacher Locations — locations inferred from linked teacher records (stub, planned for a future release)
  3. Unrestricted Locations — locations with no group mapping at all (visible to all authenticated users)

Super administrators always receive an empty array (meaning: no filter applied — see everything).


Core Methods

isEnabled(): bool

Returns whether location filtering is enabled in component configuration.

use CWM\Component\Proclaim\Administrator\Helper\CwmlocationHelper;

if (CwmlocationHelper::isEnabled()) {
    // Apply location filter
}

getUserLocations(int $userId = 0): int[]

Returns the location IDs visible to a user.

Return value Meaning
[] (empty) Super admin — no filter, can see everything
[1, 3, 5] Non-admin — can only see these location IDs
$locations = CwmlocationHelper::getUserLocations();        // current user
$locations = CwmlocationHelper::getUserLocations($userId); // specific user

Results are cached per request (keyed by user ID). Call resetCache() if you change the mapping or params within the same request.


getUserAccessibleLocationsForEdit(int $userId = 0, int $currentId = 0): int[]

Same as getUserLocations(), but ensures the currently-assigned location of a record is always included in the result — even if the user would not normally see that campus. This prevents saving from silently stripping a location that the editor cannot see.

$options = CwmlocationHelper::getUserAccessibleLocationsForEdit(
    userId: 0,          // current user
    currentId: $item->location_id
);

applyLocationFilter(QueryInterface $query, string $alias, int $userId = 0): void

Applies a WHERE location_id IN (...) clause to a query. Does nothing when location filtering is disabled or the user is a super admin.

$query = $db->getQuery(true)
    ->select('*')
    ->from($db->quoteName('#__bsms_studies', 'a'));

CwmlocationHelper::applyLocationFilter($query, 'a'); // filters a.location_id

applySecurityFilter(QueryInterface $query, string $alias, int $userId = 0): void

Combines location filtering with Joomla's standard view-level access filter. Use this instead of applyLocationFilter() when you need both checks.

CwmlocationHelper::applySecurityFilter($query, 'a');
// Equivalent to:
// CwmlocationHelper::applyLocationFilter($query, 'a');
// + $query->whereIn('a.access', $user->getAuthorisedViewLevels())

shouldShowWizard(): bool

Returns true when location filtering is enabled but no group mapping has been configured and the wizard has not been dismissed. Used by the CPanel dashboard to show the setup prompt.


getLocationUsage(int $locationId): array

Returns content counts for a location. Used by deletion safety checks.

$usage = CwmlocationHelper::getLocationUsage($locationId);
// ['messages' => 42]

getPublishedLocationCount(): int

Returns the total number of published locations.


resetCache(?int $userId = null): void

Clears the per-request location cache. Call after updating the group mapping or component params in the same request.

CwmlocationHelper::resetCache();           // clear all users
CwmlocationHelper::resetCache($userId);    // clear one user

Integrating Location Filtering in a List Model

The standard pattern used by all 11 Proclaim admin list models:

use CWM\Component\Proclaim\Administrator\Helper\CwmlocationHelper;

protected function getListQuery(): QueryInterface
{
    $db    = $this->getDatabase();
    $user  = $this->getCurrentUser();
    $query = $db->getQuery(true);

    $query->select('a.*')
        ->from($db->quoteName('#__bsms_studies', 'a'));

    // Apply location filter when enabled
    if (!$user->authorise('core.admin') && CwmlocationHelper::isEnabled()) {
        $accessible = CwmlocationHelper::getUserLocations((int) $user->id);
        if (!empty($accessible)) {
            $query->whereIn($db->quoteName('a.location_id'), $accessible);
        }
        // If $accessible is empty and user is not super admin:
        // that means no locations are mapped yet — show nothing
    }

    return $query;
}

Always use $this->getCurrentUser() (from CurrentUserTrait) in admin list models, never Factory::getApplication()->getIdentity().


Shared-Resource Pattern (Servers)

For resources that can be shared across all campuses (e.g. servers), use the hybrid NULL pattern:

-- NULL = shared (all campuses can see)
-- Specific ID = campus-restricted
ALTER TABLE `#__bsms_servers` ADD COLUMN `location_id` INT(3) DEFAULT NULL;

Query pattern with extendWhere() for (location_id IS NULL OR location_id IN (...)):

if (!$user->authorise('core.admin') && CwmlocationHelper::isEnabled()) {
    $accessible = CwmlocationHelper::getUserLocations((int) $user->id);

    if (!empty($accessible)) {
        $inClause = implode(',', array_map('intval', $accessible));
        $query->extendWhere(
            'AND',
            [
                $db->quoteName('server.location_id') . ' IS NULL',
                $db->quoteName('server.location_id') . ' IN (' . $inClause . ')',
            ],
            'OR'
        );
    } else {
        // No mapped locations — show only shared servers
        $query->where($db->quoteName('server.location_id') . ' IS NULL');
    }
}

Component Parameters

Param key Type Description
enable_location_filtering int (0/1) Master on/off switch
location_group_mapping JSON string {"locationId": [groupId, ...], ...}
location_system_dismissed int (0/1) Hides the CPanel wizard prompt

Read via:

$params  = ComponentHelper::getParams('com_proclaim');
$enabled = (bool) $params->get('enable_location_filtering', 0);
$mapping = json_decode($params->get('location_group_mapping', '{}'), true);

Database Tables

#__bsms_locations

Column Type Notes
id INT AUTO_INCREMENT Primary key
location_text VARCHAR Campus display name
published TINYINT 1 = published
access INT Joomla view level
checked_out INT Record locking
checked_out_time DATETIME Record locking

Location columns on other tables

Table Column Pattern
#__bsms_studies location_id NULL = shared
#__bsms_series location_id NULL = shared
#__bsms_podcast location_id NULL = shared
#__bsms_servers location_id NULL = shared (all campuses)

Frontend vs. Backend Behavior

Context Behavior
Backend admin lists Non-super-admin users see only records matching their accessible locations
Frontend site model CwmsermonsModel::setModuleState() supports location_filter parameter from mod_proclaim
mod_proclaim module Three modes: all, specific, user (dynamic per-visitor)
Smart Search Location name indexed as taxonomy facet; visitors can filter by campus

Testing

use CWM\Component\Proclaim\Administrator\Helper\CwmlocationHelper;

// After modifying params in a test, reset the cache
CwmlocationHelper::resetCache();

// Test: super admin gets empty array
$this->assertSame([], CwmlocationHelper::getUserLocations($superAdminId));

// Test: regular user gets their accessible locations
$locations = CwmlocationHelper::getUserLocations($regularUserId);
$this->assertContains($expectedLocationId, $locations);

See tests/unit/Admin/Helper/ for existing test coverage patterns.


Known Limitations & Future Work

Item Status
Teacher Locations (source 2) Stub — requires user_id column on #__bsms_teachers
Smart Search runtime filtering Location taxonomy is indexed; runtime per-user filtering not yet implemented
Frontend access control Location filtering currently applies to admin backend only; frontend relies on Joomla access levels

Clone this wiki locally