diff options
| -rwxr-xr-x | includes/classes/LibertyContent.php | 28 | ||||
| -rw-r--r-- | includes/classes/LibertyXrefType.php | 217 |
2 files changed, 123 insertions, 122 deletions
diff --git a/includes/classes/LibertyContent.php b/includes/classes/LibertyContent.php index 13d0f4d..b68c173 100755 --- a/includes/classes/LibertyContent.php +++ b/includes/classes/LibertyContent.php @@ -132,6 +132,12 @@ class LibertyContent extends LibertyBase implements BitCacheable { */ public $mContentTypeGuid; + /** Set when handler_package differs from content_type_guid (e.g. 'stock' for stockcomponent/stockassembly). Used to scope xref_item lookups via IN(). */ + public string $mPackageGuid = ''; + + /** Lazy-initialised by xrefType(); reset to null in registerContentType(). */ + protected ?LibertyXrefType $mXrefType = null; + /** * mInfo key used by loadXrefTypeList(); subclasses may override (e.g. 'contact_types') */ @@ -1883,6 +1889,9 @@ class LibertyContent extends LibertyBase implements BitCacheable { global $gLibertySystem; $gLibertySystem->registerContentType( $pContentGuid, $pTypeParams ); $this->mType = $pTypeParams; + $pkg = $pTypeParams['handler_package'] ?? ''; + $this->mPackageGuid = ( $pkg && $pkg !== $pContentGuid ) ? $pkg : ''; + $this->mXrefType = null; } /** @@ -3914,24 +3923,25 @@ class LibertyContent extends LibertyBase implements BitCacheable { // LibertyXref / LibertyXrefInfo (data logic). // ========================================================================= - /** @see LibertyXrefType::getDisplayGroups() */ + /** Return a LibertyXrefType scoped to this content object's type and package guids. */ + private function xrefType(): LibertyXrefType { + return $this->mXrefType ??= new LibertyXrefType( $this->mContentTypeGuid, $this->mPackageGuid ?: null ); + } + public function getXrefGroupList(): array { - return LibertyXrefType::getDisplayGroups( $this->mContentTypeGuid ); + return $this->xrefType()->getDisplayGroups(); } - /** @see LibertyXrefType::getTypeMarkers() */ public function getXrefSourceList(): array { - return LibertyXrefType::getTypeMarkers( $this->mContentTypeGuid ); + return $this->xrefType()->getTypeMarkers(); } - /** @see LibertyXrefType::getAvailableItems() */ public function getXrefTypeList( $xrefGroup = 0, $xrefTemplate = null ): array { - return LibertyXrefType::getAvailableItems( $this->mContentTypeGuid, $this->mContentId, $xrefGroup, $xrefTemplate ); + return $this->xrefType()->getAvailableItems( $this->mContentId, $xrefGroup, $xrefTemplate ); } - /** @see LibertyXrefType::getTemplateFormats() */ public function getXrefFormatList(): array { - return LibertyXrefType::getTemplateFormats( $this->mContentTypeGuid ); + return $this->xrefType()->getTemplateFormats(); } /** @@ -3945,7 +3955,7 @@ class LibertyContent extends LibertyBase implements BitCacheable { */ public function loadXrefTypeList(): void { if( $this->isValid() && empty( $this->mInfo[$this->mXrefTypeKey] ) ) { - $this->mInfo[$this->mXrefTypeKey] = LibertyXrefType::getContentTypeMarkers( $this->mContentTypeGuid, $this->mContentId ); + $this->mInfo[$this->mXrefTypeKey] = $this->xrefType()->getContentTypeMarkers( $this->mContentId ); } } diff --git a/includes/classes/LibertyXrefType.php b/includes/classes/LibertyXrefType.php index 9ee67d8..34ebd2d 100644 --- a/includes/classes/LibertyXrefType.php +++ b/includes/classes/LibertyXrefType.php @@ -6,8 +6,6 @@ namespace Bitweaver\Liberty; -use Bitweaver\BitBase; - /** * Read-only query class for the xref schema tables. * @@ -24,108 +22,32 @@ use Bitweaver\BitBase; * * 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. + * Instance methods are content-type-scoped runtime queries, called via LibertyContent. + * Static methods are unfiltered admin queries across all content types. */ -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; - - $where = ''; - $bindVars = []; - - if( !empty( $pOptionHash['content_type_guid'] ) ) { - $where = " WHERE cxs.`content_type_guid` = ? "; - $bindVars[] = $pOptionHash['content_type_guid']; - } - if( !empty( $pOptionHash['active_role'] ) ) { - $where = " WHERE cxs.`role_id` = ? "; - $bindVars[] = $pOptionHash['active_role']; - } - if( !empty( $pOptionHash['item'] ) ) { - $where = " WHERE cxs.`item` = ? "; - $bindVars[] = $pOptionHash['item']; - } - - $query = "SELECT cxs.* - FROM `".BIT_DB_PREFIX."liberty_xref_item` cxs - $where ORDER BY cxs.`x_group`, cxs.`item`"; - - $result = $gBitSystem->mDb->query( $query, $bindVars ); - - $ret = []; - while( $res = $result->fetchRow() ) { - $res["num_entries"] = $gBitSystem->mDb->getOne( - "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."liberty_xref` WHERE `item` = ?", - [ $res["item"] ] - ); - $ret[] = $res; - } +class LibertyXrefType { - return $ret; - } - - /** - * Return the distinct content_type_guid values that have at least one group defined. - * - * @return string[] - */ - public static function getContentTypeGuids(): array { - global $gBitSystem; - $result = $gBitSystem->mDb->query( - "SELECT DISTINCT `content_type_guid` FROM `".BIT_DB_PREFIX."liberty_xref_group` ORDER BY `content_type_guid`", - [] - ); - $ret = []; - while ( $res = $result->fetchRow() ) { - $ret[] = $res['content_type_guid']; - } - return $ret; - } + public function __construct( + private string $contentTypeGuid, + private ?string $packageGuid = null + ) {} // ------------------------------------------------------------------------- // Runtime queries — role-filtered, content-type-scoped. - // These are the methods called from page files and delegates on LibertyContent. + // Called via LibertyContent::xrefType()->method(). // ------------------------------------------------------------------------- /** - * Return display groups (sort_order > 0) for a content type, filtered to the + * Return display groups (sort_order > 0) for this 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 { + public function getDisplayGroups(): array { global $gBitSystem, $gBitUser; $roles = array_keys( $gBitUser->mRoles ?? [] ) ?: [-1]; $bindVars = array_merge( $roles, [ $gBitUser->mUserId ] ); @@ -133,7 +55,7 @@ class LibertyXrefType extends LibertyBase { "SELECT g.* FROM `".BIT_DB_PREFIX."liberty_xref_group` g LEFT OUTER JOIN `".BIT_DB_PREFIX."users_roles_map` purm ON purm.`user_id` = ".(int)($gBitUser->mUserId ?? 0)." AND purm.`role_id` = g.`role_id` - WHERE g.`content_type_guid` = '$contentTypeGuid' AND g.`sort_order` > 0 + WHERE g.`content_type_guid` = '$this->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 @@ -146,17 +68,16 @@ class LibertyXrefType extends LibertyBase { } /** - * Return sort_order=0 item slots for a content type, filtered to the current + * Return sort_order=0 item slots for this 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 { + public function getTypeMarkers(): array { global $gBitSystem, $gBitUser; $roles = array_keys( $gBitUser->mRoles ?? [] ) ?: [-1]; $bindVars = array_merge( $roles, [ $gBitUser->mUserId ] ); @@ -164,10 +85,10 @@ class LibertyXrefType extends LibertyBase { "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' + ON t.`x_group` = g.`x_group` AND t.`content_type_guid` = '$this->contentTypeGuid' LEFT OUTER JOIN `".BIT_DB_PREFIX."users_roles_map` purm ON purm.`user_id` = ".(int)($gBitUser->mUserId ?? 0)." AND purm.`role_id` = g.`role_id` - WHERE g.`content_type_guid` = '$contentTypeGuid' AND t.`sort_order` = 0 + WHERE g.`content_type_guid` = '$this->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 @@ -191,23 +112,26 @@ class LibertyXrefType extends LibertyBase { * 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. + * When a packageGuid was supplied at construction, item/group rows for both guids + * are included; each item only joins its own group (guid-consistent join). * - * @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 { + public function getAvailableItems( int $contentId, int $xrefGroup = 0, ?string $xrefTemplate = null ): array { global $gBitSystem; + $db = $gBitSystem->mDb; + $guidFilter = $this->packageGuid + ? "IN ('$this->contentTypeGuid', '$this->packageGuid')" + : "= '$this->contentTypeGuid'"; 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` = ? + WHERE s.`content_type_guid` $guidFilter AND s.`template` = ? ORDER BY s.`cross_ref_title`", [ $xrefTemplate ] ); @@ -216,10 +140,10 @@ class LibertyXrefType extends LibertyBase { "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' + ON t.`x_group` = s.`x_group` AND t.`content_type_guid` = s.`content_type_guid` 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` = ? + WHERE s.`content_type_guid` $guidFilter AND t.`sort_order` = ? AND (x.`xref_id` IS NULL OR x.`xorder` > 0) ORDER BY s.`cross_ref_title`", [ $contentId, $xrefGroup ] @@ -229,10 +153,10 @@ class LibertyXrefType extends LibertyBase { "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' + ON t.`x_group` = s.`x_group` AND t.`content_type_guid` = s.`content_type_guid` 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 + WHERE s.`content_type_guid` $guidFilter AND t.`sort_order` > 0 AND (x.`xref_id` IS NULL OR x.`xorder` > 0) ORDER BY s.`cross_ref_title`", [ $contentId ] @@ -248,15 +172,14 @@ class LibertyXrefType extends LibertyBase { /** * Return the distinct template format names defined across all item slots for - * a content type, filtered to the current user's roles. + * this 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 { + public function getTemplateFormats(): array { global $gBitSystem, $gBitUser; $roles = array_keys( $gBitUser->mRoles ?? [] ) ?: [-1]; $bindVars = array_merge( $roles, [ $gBitUser->mUserId ] ); @@ -265,7 +188,7 @@ class LibertyXrefType extends LibertyBase { FROM `".BIT_DB_PREFIX."liberty_xref_item` g LEFT OUTER JOIN `".BIT_DB_PREFIX."users_roles_map` purm ON purm.`user_id` = ".(int)($gBitUser->mUserId ?? 0)." AND purm.`role_id` = g.`role_id` - WHERE g.`content_type_guid` = '$contentTypeGuid' + WHERE g.`content_type_guid` = '$this->contentTypeGuid' AND (g.`role_id` IN(".implode(',', array_fill(0, count($roles), '?')).") OR purm.`user_id` = ?) ORDER BY g.`template`", $bindVars @@ -280,15 +203,14 @@ class LibertyXrefType extends LibertyBase { /** * 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 + * Queries all item slots at sort_order=0 for this 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 + * @param int $contentId liberty_content.content_id of the item to check * @return array[] */ - public static function getContentTypeMarkers( string $contentTypeGuid, int $contentId ): array { + public function getContentTypeMarkers( int $contentId ): array { global $gBitSystem, $gBitUser; $roles = array_keys( $gBitUser->mRoles ?? [] ) ?: [-1]; $bindVars = array_merge( [ $contentId ], $roles, [ $gBitUser->mUserId ] ); @@ -296,11 +218,11 @@ class LibertyXrefType extends LibertyBase { "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' + ON t.`x_group` = r.`x_group` AND t.`content_type_guid` = '$this->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` = ".(int)($gBitUser->mUserId ?? 0)." AND purm.`role_id` = r.`role_id` - WHERE r.`content_type_guid` = '$contentTypeGuid' AND t.`sort_order` = 0 + WHERE r.`content_type_guid` = '$this->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 @@ -317,6 +239,75 @@ class LibertyXrefType extends LibertyBase { // ------------------------------------------------------------------------- /** + * 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; + + $where = ''; + $bindVars = []; + + if( !empty( $pOptionHash['content_type_guid'] ) ) { + $where = " WHERE cxs.`content_type_guid` = ? "; + $bindVars[] = $pOptionHash['content_type_guid']; + } + if( !empty( $pOptionHash['active_role'] ) ) { + $where = " WHERE cxs.`role_id` = ? "; + $bindVars[] = $pOptionHash['active_role']; + } + if( !empty( $pOptionHash['item'] ) ) { + $where = " WHERE cxs.`item` = ? "; + $bindVars[] = $pOptionHash['item']; + } + + $query = "SELECT cxs.* + FROM `".BIT_DB_PREFIX."liberty_xref_item` cxs + $where ORDER BY cxs.`x_group`, cxs.`item`"; + + $result = $gBitSystem->mDb->query( $query, $bindVars ); + + $ret = []; + while( $res = $result->fetchRow() ) { + $res["num_entries"] = $gBitSystem->mDb->getOne( + "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."liberty_xref` WHERE `item` = ?", + [ $res["item"] ] + ); + $ret[] = $res; + } + + return $ret; + } + + /** + * Return the distinct content_type_guid values that have at least one group defined. + * + * @return string[] + */ + public static function getContentTypeGuids(): array { + global $gBitSystem; + $result = $gBitSystem->mDb->query( + "SELECT DISTINCT `content_type_guid` FROM `".BIT_DB_PREFIX."liberty_xref_group` ORDER BY `content_type_guid`", + [] + ); + $ret = []; + while ( $res = $result->fetchRow() ) { + $ret[] = $res['content_type_guid']; + } + return $ret; + } + + /** * Return liberty_xref_group rows, optionally filtered by content_type_guid. * * Each row is augmented with num_sources: count of liberty_xref_item rows |
