summaryrefslogtreecommitdiff
path: root/includes/classes/LibertyXrefType.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/classes/LibertyXrefType.php')
-rw-r--r--includes/classes/LibertyXrefType.php260
1 files changed, 257 insertions, 3 deletions
diff --git a/includes/classes/LibertyXrefType.php b/includes/classes/LibertyXrefType.php
index d90fd2a..d54e0c4 100644
--- a/includes/classes/LibertyXrefType.php
+++ b/includes/classes/LibertyXrefType.php
@@ -8,12 +8,52 @@ namespace Bitweaver\Liberty;
use Bitweaver\BitBase;
+/**
+ * Read-only query class for the xref schema tables.
+ *
+ * The xref system is defined by two DB tables before any data exists:
+ *
+ * liberty_xref_group — one row per logical group of xref slots for a content type
+ * (e.g. 'address', 'reference', 'quantity'). The group sets
+ * the display title, sort order, Smarty template, and role gate
+ * for all items within it.
+ *
+ * liberty_xref_item — one row per named slot within a group (e.g. '#P', 'REQN',
+ * 'SGL'). Defines the item key, display title, cardinality
+ * (multiple), role gate, and which Smarty template renders it.
+ *
+ * Neither table holds user data. Live data lives in liberty_xref.
+ *
+ * Methods are split into two groups:
+ *
+ * Runtime queries — role-filtered, content-type-scoped. Called via delegate
+ * methods on LibertyContent (e.g. $gContent->getXrefTypeList())
+ * or directly by page files that have already resolved
+ * the content type guid.
+ *
+ * Admin queries — unfiltered, with usage counts. Used by admin pages that
+ * need the full picture across all roles and content.
+ */
class LibertyXrefType extends LibertyBase {
public function __construct() {
parent::__construct();
}
+ /**
+ * Return all liberty_xref_item rows, optionally filtered.
+ *
+ * Each returned row is augmented with num_entries: the count of live liberty_xref
+ * rows that use that item key (across all content). Useful for admin listings.
+ *
+ * Supported keys in $pOptionHash:
+ * content_type_guid — restrict to one content type
+ * active_role — restrict to items visible to one role_id
+ * item — restrict to one item key
+ *
+ * @param array|null $pOptionHash optional filter hash
+ * @return array[] liberty_xref_item rows with num_entries appended
+ */
public static function getXrefTypeList( $pOptionHash = NULL ) {
global $gBitSystem;
@@ -52,7 +92,9 @@ class LibertyXrefType extends LibertyBase {
}
/**
- * Returns the distinct content_type_guid values present in liberty_xref_group.
+ * Return the distinct content_type_guid values that have at least one group defined.
+ *
+ * @return string[]
*/
public static function getContentTypeGuids(): array {
global $gBitSystem;
@@ -67,9 +109,221 @@ class LibertyXrefType extends LibertyBase {
return $ret;
}
+ // -------------------------------------------------------------------------
+ // Runtime queries — role-filtered, content-type-scoped.
+ // These are the methods called from page files and delegates on LibertyContent.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Return display groups (sort_order > 0) for a content type, filtered to the
+ * current user's roles.
+ *
+ * Used by add-xref pages to build the group selector. Sort_order = 0 is the
+ * 'type' group (category markers); that is excluded here and loaded separately
+ * via getContentTypeMarkers().
+ *
+ * @param string $contentTypeGuid e.g. 'contact', 'stockassembly'
+ * @return array[] liberty_xref_group rows ordered by sort_order
+ */
+ public static function getDisplayGroups( string $contentTypeGuid ): array {
+ global $gBitSystem, $gBitUser;
+ $roles = array_keys( $gBitUser->mRoles ?? [] ) ?: [-1];
+ $bindVars = array_merge( $roles, [ $gBitUser->mUserId ] );
+ $result = $gBitSystem->mDb->query(
+ "SELECT g.* FROM `".BIT_DB_PREFIX."liberty_xref_group` g
+ LEFT OUTER JOIN `".BIT_DB_PREFIX."users_roles_map` purm
+ ON purm.`user_id` = ".$gBitUser->mUserId." AND purm.`role_id` = g.`role_id`
+ WHERE g.`content_type_guid` = '$contentTypeGuid' AND g.`sort_order` > 0
+ AND (g.`role_id` IN(".implode(',', array_fill(0, count($roles), '?')).") OR purm.`user_id` = ?)
+ ORDER BY g.`sort_order`",
+ $bindVars
+ );
+ $ret = [];
+ while( $res = $result->fetchRow() ) {
+ $ret[] = $res;
+ }
+ return $ret;
+ }
+
+ /**
+ * Return sort_order=0 item slots for a content type, filtered to the current
+ * user's roles.
+ *
+ * These are top-level type/category markers (e.g. contact's $00/$02+ person/
+ * business subtypes). Used by type-selector forms in add_business.php, edit.php
+ * and similar.
+ *
+ * @param string $contentTypeGuid
+ * @return array[] [{item: string, name: string}, ...] ordered by item key
+ */
+ public static function getTypeMarkers( string $contentTypeGuid ): array {
+ global $gBitSystem, $gBitUser;
+ $roles = array_keys( $gBitUser->mRoles ?? [] ) ?: [-1];
+ $bindVars = array_merge( $roles, [ $gBitUser->mUserId ] );
+ $result = $gBitSystem->mDb->query(
+ "SELECT g.`cross_ref_title` AS `type_name`, g.`item`
+ FROM `".BIT_DB_PREFIX."liberty_xref_item` g
+ JOIN `".BIT_DB_PREFIX."liberty_xref_group` t
+ ON t.`x_group` = g.`x_group` AND t.`content_type_guid` = '$contentTypeGuid'
+ LEFT OUTER JOIN `".BIT_DB_PREFIX."users_roles_map` purm
+ ON purm.`user_id` = ".$gBitUser->mUserId." AND purm.`role_id` = g.`role_id`
+ WHERE g.`content_type_guid` = '$contentTypeGuid' AND t.`sort_order` = 0
+ AND (g.`role_id` IN(".implode(',', array_fill(0, count($roles), '?')).") OR purm.`user_id` = ?)
+ ORDER BY g.`item`",
+ $bindVars
+ );
+ $ret = [];
+ $cnt = 0;
+ while( $res = $result->fetchRow() ) {
+ $ret[$cnt]['item'] = $res['item'];
+ $ret[$cnt++]['name'] = trim( $res['type_name'] );
+ }
+ return $ret;
+ }
+
+ /**
+ * Return available item slots for the add-xref type selector.
+ *
+ * Three modes controlled by the arguments:
+ * $xrefTemplate set — all items whose template matches, regardless of group
+ * $xrefGroup > -1 — items in the group at that sort_order, excluding slots
+ * already filled for this content item (single-cardinality
+ * items that already have an active row)
+ * $xrefGroup == -1 — same but across all groups (sort_order > 0)
+ *
+ * Returns ['list' => [item => display_name, ...], 'type' => [item => template, ...]]
+ * where template defaults to 'generic' when the DB value is empty.
+ *
+ * @param string $contentTypeGuid
+ * @param int $contentId liberty_content.content_id of the current item
+ * @param int $xrefGroup sort_order of the target group, or -1 for all
+ * @param string|null $xrefTemplate filter by template name instead of group
+ * @return array{list: array<string,string>, type: array<string,string>}
+ */
+ public static function getAvailableItems( string $contentTypeGuid, int $contentId, int $xrefGroup = 0, ?string $xrefTemplate = null ): array {
+ global $gBitSystem;
+ $db = $gBitSystem->mDb;
+ if( $xrefTemplate ) {
+ $result = $db->query(
+ "SELECT s.`cross_ref_title` AS `type_name`, s.`item`, s.`template`
+ FROM `".BIT_DB_PREFIX."liberty_xref_item` s
+ WHERE s.`content_type_guid` = '$contentTypeGuid' AND s.`template` = ?
+ ORDER BY s.`cross_ref_title`",
+ [ $xrefTemplate ]
+ );
+ } elseif( $xrefGroup > -1 ) {
+ $result = $db->query(
+ "SELECT s.`cross_ref_title` AS `type_name`, s.`item`, s.`template`
+ FROM `".BIT_DB_PREFIX."liberty_xref_item` s
+ JOIN `".BIT_DB_PREFIX."liberty_xref_group` t
+ ON t.`x_group` = s.`x_group` AND t.`content_type_guid` = '$contentTypeGuid'
+ LEFT JOIN `".BIT_DB_PREFIX."liberty_xref` x
+ ON x.`item` = s.`item` AND x.`content_id` = ? AND (x.`end_date` IS NULL OR x.`end_date` > CURRENT_TIMESTAMP)
+ WHERE s.`content_type_guid` = '$contentTypeGuid' AND t.`sort_order` = ?
+ AND (x.`xref_id` IS NULL OR x.`xorder` > 0)
+ ORDER BY s.`cross_ref_title`",
+ [ $contentId, $xrefGroup ]
+ );
+ } else {
+ $result = $db->query(
+ "SELECT s.`cross_ref_title` AS `type_name`, s.`item`, s.`template`
+ FROM `".BIT_DB_PREFIX."liberty_xref_item` s
+ JOIN `".BIT_DB_PREFIX."liberty_xref_group` t
+ ON t.`x_group` = s.`x_group` AND t.`content_type_guid` = '$contentTypeGuid'
+ LEFT JOIN `".BIT_DB_PREFIX."liberty_xref` x
+ ON x.`item` = s.`item` AND x.`content_id` = ? AND (x.`end_date` IS NULL OR x.`end_date` > CURRENT_TIMESTAMP)
+ WHERE s.`content_type_guid` = '$contentTypeGuid' AND t.`sort_order` > 0
+ AND (x.`xref_id` IS NULL OR x.`xorder` > 0)
+ ORDER BY s.`cross_ref_title`",
+ [ $contentId ]
+ );
+ }
+ $ret = [];
+ while( $res = $result->fetchRow() ) {
+ $ret['list'][$res['item']] = trim( $res['type_name'] );
+ $ret['type'][$res['item']] = trim( $res['template'] ) !== '' ? trim( $res['template'] ) : 'generic';
+ }
+ return $ret;
+ }
+
+ /**
+ * Return the distinct template format names defined across all item slots for
+ * a content type, filtered to the current user's roles.
+ *
+ * Used by the add-xref UI to know which item template types are available.
+ * Empty template values are normalised to 'generic'.
+ *
+ * @param string $contentTypeGuid
+ * @return string[]
+ */
+ public static function getTemplateFormats( string $contentTypeGuid ): array {
+ global $gBitSystem, $gBitUser;
+ $roles = array_keys( $gBitUser->mRoles ?? [] ) ?: [-1];
+ $bindVars = array_merge( $roles, [ $gBitUser->mUserId ] );
+ $result = $gBitSystem->mDb->query(
+ "SELECT DISTINCT g.`template`
+ FROM `".BIT_DB_PREFIX."liberty_xref_item` g
+ LEFT OUTER JOIN `".BIT_DB_PREFIX."users_roles_map` purm
+ ON purm.`user_id` = ".$gBitUser->mUserId." AND purm.`role_id` = g.`role_id`
+ WHERE g.`content_type_guid` = '$contentTypeGuid'
+ AND (g.`role_id` IN(".implode(',', array_fill(0, count($roles), '?')).") OR purm.`user_id` = ?)
+ ORDER BY g.`template`",
+ $bindVars
+ );
+ $ret = [];
+ while( $res = $result->fetchRow() ) {
+ $ret[] = trim( $res['template'] ) !== '' ? trim( $res['template'] ) : 'generic';
+ }
+ return $ret;
+ }
+
+ /**
+ * Return sort_order=0 type markers for a content item, showing which apply.
+ *
+ * Queries all item slots at sort_order=0 for the content type and left-joins
+ * liberty_xref to show which ones have an active row for the given content item.
+ * Each row includes 'content_id' (non-null when the marker is set on the item).
+ *
+ * @param string $contentTypeGuid
+ * @param int $contentId liberty_content.content_id of the item to check
+ * @return array[]
+ */
+ public static function getContentTypeMarkers( string $contentTypeGuid, int $contentId ): array {
+ global $gBitSystem, $gBitUser;
+ $roles = array_keys( $gBitUser->mRoles ?? [] ) ?: [-1];
+ $bindVars = array_merge( [ $contentId ], $roles, [ $gBitUser->mUserId ] );
+ $result = $gBitSystem->mDb->query(
+ "SELECT r.`item`, r.`cross_ref_title`, d.`content_id`
+ FROM `".BIT_DB_PREFIX."liberty_xref_item` r
+ JOIN `".BIT_DB_PREFIX."liberty_xref_group` t
+ ON t.`x_group` = r.`x_group` AND t.`content_type_guid` = '$contentTypeGuid'
+ LEFT JOIN `".BIT_DB_PREFIX."liberty_xref` d ON d.`content_id` = ? AND d.`item` = r.`item`
+ LEFT OUTER JOIN `".BIT_DB_PREFIX."users_roles_map` purm
+ ON purm.`user_id` = ".$gBitUser->mUserId." AND purm.`role_id` = r.`role_id`
+ WHERE r.`content_type_guid` = '$contentTypeGuid' AND t.`sort_order` = 0
+ AND (r.`role_id` IN(".implode(',', array_fill(0, count($roles), '?')).") OR purm.`user_id` = ?)
+ ORDER BY r.`item`",
+ $bindVars
+ );
+ $ret = [];
+ while( $res = $result->fetchRow() ) {
+ $ret[] = $res;
+ }
+ return $ret;
+ }
+
+ // -------------------------------------------------------------------------
+ // Admin queries — unfiltered, with usage counts.
+ // -------------------------------------------------------------------------
+
/**
- * Returns liberty_xref_group rows, optionally filtered by content_type_guid.
- * Each row includes num_sources: count of sources defined for that group.
+ * Return liberty_xref_group rows, optionally filtered by content_type_guid.
+ *
+ * Each row is augmented with num_sources: count of liberty_xref_item rows
+ * defined for that group. Rows are ordered by content_type_guid, sort_order.
+ *
+ * @param array|null $pOptionHash optional; supports key 'content_type_guid'
+ * @return array[]
*/
public static function getGroupList( $pOptionHash = NULL ): array {
global $gBitSystem;