diff options
| author | Lester Caine <lester@lsces.co.uk> | 2026-06-11 19:26:25 +0100 |
|---|---|---|
| committer | Lester Caine <lester@lsces.co.uk> | 2026-06-11 19:26:25 +0100 |
| commit | 64aae1e41d9288a6d9709781af29b06fe6adb5ca (patch) | |
| tree | d5d5e74420cee938d7e8ff90b9e6792d5f44cc77 | |
| parent | 27c615a0a26edb985543e520587e3043d91489f6 (diff) | |
| download | contact-64aae1e41d9288a6d9709781af29b06fe6adb5ca.tar.gz contact-64aae1e41d9288a6d9709781af29b06fe6adb5ca.tar.bz2 contact-64aae1e41d9288a6d9709781af29b06fe6adb5ca.zip | |
Introduce ContactPerson and ContactBusiness subclasses
Splits the Contact class into ContactPerson (content_type_guid='contactperson')
and ContactBusiness (content_type_guid='contactbusiness'), each using 'contact'
as the shared package-level xref schema. Replaces the $isPerson/$00 xref hack
with proper class identity via instanceof.
- ContactPerson.php, ContactBusiness.php: new subclasses
- Contact.php: loadXrefTypeList() reads type tags directly from liberty_xref;
getAvailableTypeItems() for edit form (schema-driven with pre-upgrade fallback);
getDisplayUrl() now points to display_contact.php
- Type item codes: P01/P02 (person), B01-B04 (business, B01=Service new)
- list_people.php, list_businesses.php: separate list pages per type
- list_contacts.php: combined display-layer merge of both types
- 5.0.3.php: upgrade script migrating existing data to new content types and codes
- Templates: isPerson flag from instanceof; horizontal type checkboxes; list.tpl
accepts $listTitle; menu adds People/Businesses entries
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| -rw-r--r-- | add_business.php | 11 | ||||
| -rw-r--r-- | add_person.php | 6 | ||||
| -rwxr-xr-x | admin/admin_contact_inc.php | 5 | ||||
| -rwxr-xr-x | admin/schema_inc.php | 39 | ||||
| -rw-r--r-- | admin/upgrades/5.0.3.php | 112 | ||||
| -rwxr-xr-x | display_contact.php | 1 | ||||
| -rwxr-xr-x | edit.php | 23 | ||||
| -rw-r--r-- | export_contacts.php | 4 | ||||
| -rw-r--r-- | import/ImportContactCSV.php | 12 | ||||
| -rw-r--r-- | import/load_contacts_csv.php | 2 | ||||
| -rwxr-xr-x | includes/bit_setup_inc.php | 17 | ||||
| -rwxr-xr-x | includes/classes/Contact.php | 85 | ||||
| -rw-r--r-- | includes/classes/ContactBusiness.php | 28 | ||||
| -rw-r--r-- | includes/classes/ContactPerson.php | 29 | ||||
| -rwxr-xr-x | includes/classes/ContactType.php | 41 | ||||
| -rw-r--r-- | includes/lookup_contact.php | 2 | ||||
| -rwxr-xr-x | includes/lookup_contact_inc.php | 10 | ||||
| -rwxr-xr-x | list1.php | 3 | ||||
| -rwxr-xr-x | list2.php | 3 | ||||
| -rw-r--r-- | list_businesses.php | 36 | ||||
| -rwxr-xr-x | list_contacts.php | 27 | ||||
| -rw-r--r-- | list_people.php | 30 | ||||
| -rwxr-xr-x | templates/display_contact.tpl | 2 | ||||
| -rwxr-xr-x | templates/display_type_header.tpl | 4 | ||||
| -rwxr-xr-x | templates/edit.tpl | 6 | ||||
| -rwxr-xr-x | templates/edit_type_header.tpl | 19 | ||||
| -rwxr-xr-x | templates/list.tpl | 2 | ||||
| -rwxr-xr-x | templates/menu_contact.tpl | 6 |
28 files changed, 449 insertions, 116 deletions
diff --git a/add_business.php b/add_business.php index 4164768..685423d 100644 --- a/add_business.php +++ b/add_business.php @@ -4,7 +4,7 @@ * @subpackage functions */ -use Bitweaver\Contact\Contact; +use Bitweaver\Contact\ContactBusiness; use Bitweaver\KernelTools; require_once '../kernel/includes/setup_inc.php'; @@ -14,7 +14,7 @@ global $gBitSystem, $gBitSmarty, $gBitUser; $gBitSystem->verifyPackage( 'contact' ); $gBitSystem->verifyPermission( 'p_contact_update' ); -$gContent = new Contact(); +$gContent = new ContactBusiness(); if( !empty( $_REQUEST['fCancel'] ) ) { KernelTools::bit_redirect( CONTACT_PKG_URL ); @@ -37,12 +37,11 @@ if( !empty( $_REQUEST['fSaveContact'] ) ) { } } -// Load all business-relevant types ($01 and above) for optional checkboxes -$allTypes = $gContent->getXrefSourceList(); -$businessTypes = array_filter( $allTypes, fn($t) => $t['item'] !== '$00' && $t['item'] !== '$01' ); +// ContactBusiness type markers are $02+ only ($00/$01 live under contactperson/deprecated) +$businessTypes = $gContent->getXrefSourceList(); $gBitSmarty->assign( 'gContent', $gContent ); -$gBitSmarty->assign( 'businessTypes', array_values( $businessTypes ) ); +$gBitSmarty->assign( 'businessTypes', array_values( (array)$businessTypes ) ); $gBitSmarty->assign( 'errors', $gContent->mErrors ); $gBitSystem->display( 'bitpackage:contact/add_business.tpl', KernelTools::tra( 'Add Business' ), [ 'display_mode' => 'edit' ] ); diff --git a/add_person.php b/add_person.php index eda69c7..68e3599 100644 --- a/add_person.php +++ b/add_person.php @@ -4,7 +4,7 @@ * @subpackage functions */ -use Bitweaver\Contact\Contact; +use Bitweaver\Contact\ContactPerson; use Bitweaver\KernelTools; require_once '../kernel/includes/setup_inc.php'; @@ -14,7 +14,7 @@ global $gBitSystem, $gBitSmarty, $gBitUser; $gBitSystem->verifyPackage( 'contact' ); $gBitSystem->verifyPermission( 'p_contact_update' ); -$gContent = new Contact(); +$gContent = new ContactPerson(); if( !empty( $_REQUEST['fCancel'] ) ) { KernelTools::bit_redirect( CONTACT_PKG_URL ); @@ -22,7 +22,7 @@ if( !empty( $_REQUEST['fCancel'] ) ) { } if( !empty( $_REQUEST['fSaveContact'] ) ) { - $_REQUEST['contact_types'] = [ '$00' ]; + $_REQUEST['contact_types'] = [ 'P01' ]; if( $gContent->store( $_REQUEST ) ) { KernelTools::bit_redirect( CONTACT_PKG_URL.'edit.php?content_id='.$gContent->mContentId ); die; diff --git a/admin/admin_contact_inc.php b/admin/admin_contact_inc.php index 5ea1ae2..dd47e5d 100755 --- a/admin/admin_contact_inc.php +++ b/admin/admin_contact_inc.php @@ -7,8 +7,7 @@ use Bitweaver\Contact\ContactType; -$mTypes = new ContactType(); -$mTypes->setup(); +$contactTypeMarkers = ContactType::getTypeMarkerList(); $formContactListFeatures = [ "contact_list_id" => [ @@ -41,7 +40,7 @@ $formContactListFeatures = [ ]; $gBitSmarty->assign( 'formContactListFeatures',$formContactListFeatures ); -foreach( $mTypes->mContactType as $key => $type ) { +foreach( $contactTypeMarkers as $key => $type ) { $option = 'contact_default_'.$key; $contactChecks[] = $option; $contactTypeDefaults[$option] = $type; diff --git a/admin/schema_inc.php b/admin/schema_inc.php index 50fc188..0fd9ebf 100755 --- a/admin/schema_inc.php +++ b/admin/schema_inc.php @@ -64,6 +64,7 @@ $gBitInstaller->registerPackageInfo( CONTACT_PKG_NAME, [ 'dependencies' => 'liberty', ] ); + // ### Indexes $indices = [ 'contact_parent_id_idx' => [ 'table' => 'contact', 'cols' => 'parent_id', 'opts' => null ], @@ -75,24 +76,32 @@ $gBitInstaller->registerSchemaIndexes( CONTACT_PKG_NAME, $indices ); $gBitInstaller->registerSchemaSequences( CONTACT_PKG_NAME, [] ); // ### Defaults -// xref configuration now lives in liberty_xref_group and liberty_xref_item (content_type_guid='contact'). -// These replace the old contact_xref_type and contact_xref_source table defaults. +// Xref schema: shared groups/items at content_type_guid='contact'; type markers split by sub-type. +// contactperson: 'type' group + $00 item. contactbusiness: 'type' group + $02-$05 items. $gBitInstaller->registerSchemaDefault( CONTACT_PKG_NAME, [ - // --- liberty_xref_group (formerly contact_xref_type: integer xref_type → sort_order, source text → x_group) --- - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_group` (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES ('type', 'contact','Contact Type List', 0,3,'')", - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_group` (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES ('contact','contact','General Contact Details', 1,3,'')", - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_group` (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES ('links', 'contact','Linked Contact Items', 2,3,'')", - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_group` (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES ('account','contact','Account Details', 3,3,'')", + // --- liberty_content_types — sub-type handlers for person and business --- + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_content_types` (`content_type_guid`,`content_name`,`content_name_plural`,`handler_class`,`handler_package`,`handler_file`,`maintainer_url`) VALUES ('contactperson','Person Contact','Person Contacts','ContactPerson','contact','ContactPerson.php','http://lsces.co.uk')", + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_content_types` (`content_type_guid`,`content_name`,`content_name_plural`,`handler_class`,`handler_package`,`handler_file`,`maintainer_url`) VALUES ('contactbusiness','Business Contact','Business Contacts','ContactBusiness','contact','ContactBusiness.php','http://lsces.co.uk')", + + // --- liberty_xref_group --- + // 'type' group split: one per sub-type (sort_order=0 = type-marker group, excluded from loadXrefInfo display) + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_group` (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES ('type','contactperson', 'Person Type', 0,3,'')", + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_group` (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES ('type','contactbusiness','Business Type List',0,3,'')", + // shared groups stay at 'contact' level (loaded via dual-guid IN filter) + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_group` (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES ('contact','contact','General Contact Details',1,3,'')", + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_group` (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES ('links', 'contact','Linked Contact Items', 2,3,'')", + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_group` (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES ('account','contact','Account Details', 3,3,'')", - // --- liberty_xref_item (formerly contact_xref_source) --- - // group: type - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('\$00','contact','type','Personal', 0,3,'/contact/?type=0', NULL)", - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('\$01','contact','type','Business', 0,3,'/contact/?type=1', NULL)", - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('\$02','contact','type','Manufacturer', 0,3,'/contact/?type=2', NULL)", - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('\$03','contact','type','Distributor', 0,3,'/contact/?type=3', NULL)", - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('\$04','contact','type','Supplier', 0,3,'/contact/?type=4', NULL)", - "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('\$05','contact','type','MERG Kit Elf', 0,3,'/contact/?type=5', NULL)", + // --- liberty_xref_item --- + // group: type — person types + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('P01','contactperson','type','Personal', 0,3,'',NULL)", + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('P02','contactperson','type','MERG Kit Elf', 0,3,'',NULL)", + // group: type — business subtypes + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('B01','contactbusiness','type','Service', 0,3,'',NULL)", + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('B02','contactbusiness','type','Manufacturer', 0,3,'',NULL)", + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('B03','contactbusiness','type','Distributor', 0,3,'',NULL)", + "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('B04','contactbusiness','type','Supplier', 0,3,'',NULL)", // group: contact "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('#C','contact','contact','Contact Address', 0,3,'../nlpg/?uprn=', 'address')", "INSERT INTO `" . BIT_DB_PREFIX . "liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) VALUES ('#E','contact','contact','eMail Address', 1,3,'../contact/?contact_id=','text' )", diff --git a/admin/upgrades/5.0.3.php b/admin/upgrades/5.0.3.php new file mode 100644 index 0000000..87c4989 --- /dev/null +++ b/admin/upgrades/5.0.3.php @@ -0,0 +1,112 @@ +<?php +/** + * 5.0.3 — Introduce ContactPerson and ContactBusiness subclasses. + * + * Steps: + * 1. Insert liberty_content_types rows for contactperson and contactbusiness. + * 2. Insert liberty_xref_group 'type' rows at contactperson and contactbusiness level. + * 3. Insert xref_item rows with new P01/P02 and B01-B04 codes. + * 4. Delete the now-superseded 'type' group and $0x items from content_type_guid='contact'. + * 5. Migrate liberty_content: records with a $00 xref → contactperson; remainder → contactbusiness. + * 6. Rename existing liberty_xref type-tag rows from $0x to P0x/B0x. + * + * @package contact + */ + +global $gBitInstaller; + +$X = BIT_DB_PREFIX; + +$gBitInstaller->registerPackageUpgrade( + [ + 'package' => 'contact', + 'version' => '5.0.3', + 'description' => 'Introduce ContactPerson and ContactBusiness content type subclasses.', + ], + [ + // --- Step 1: register content types --- + [ 'QUERY' => [ 'SQL92' => [ + "UPDATE OR INSERT INTO `{$X}liberty_content_types` + (`content_type_guid`,`content_name`,`content_name_plural`,`handler_class`,`handler_package`,`handler_file`,`maintainer_url`) + VALUES ('contactperson','Person Contact','Person Contacts','ContactPerson','contact','ContactPerson.php','http://lsces.co.uk') + MATCHING (`content_type_guid`)", + "UPDATE OR INSERT INTO `{$X}liberty_content_types` + (`content_type_guid`,`content_name`,`content_name_plural`,`handler_class`,`handler_package`,`handler_file`,`maintainer_url`) + VALUES ('contactbusiness','Business Contact','Business Contacts','ContactBusiness','contact','ContactBusiness.php','http://lsces.co.uk') + MATCHING (`content_type_guid`)", + ]]], + + // --- Step 2: xref_group 'type' rows --- + [ 'QUERY' => [ 'SQL92' => [ + "UPDATE OR INSERT INTO `{$X}liberty_xref_group` + (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) + VALUES ('type','contactperson','Person Type',0,3,'') + MATCHING (`x_group`,`content_type_guid`)", + "UPDATE OR INSERT INTO `{$X}liberty_xref_group` + (`x_group`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) + VALUES ('type','contactbusiness','Business Type List',0,3,'') + MATCHING (`x_group`,`content_type_guid`)", + ]]], + + // --- Step 3: xref_item rows with new codes --- + [ 'QUERY' => [ 'SQL92' => [ + // person types + "UPDATE OR INSERT INTO `{$X}liberty_xref_item` + (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) + VALUES ('P01','contactperson','type','Personal',0,3,'',NULL) + MATCHING (`item`,`content_type_guid`)", + "UPDATE OR INSERT INTO `{$X}liberty_xref_item` + (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) + VALUES ('P02','contactperson','type','MERG Kit Elf',0,3,'',NULL) + MATCHING (`item`,`content_type_guid`)", + // business subtypes + "UPDATE OR INSERT INTO `{$X}liberty_xref_item` + (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) + VALUES ('B01','contactbusiness','type','Service',0,3,'',NULL) + MATCHING (`item`,`content_type_guid`)", + "UPDATE OR INSERT INTO `{$X}liberty_xref_item` + (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) + VALUES ('B02','contactbusiness','type','Manufacturer',0,3,'',NULL) + MATCHING (`item`,`content_type_guid`)", + "UPDATE OR INSERT INTO `{$X}liberty_xref_item` + (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) + VALUES ('B03','contactbusiness','type','Distributor',0,3,'',NULL) + MATCHING (`item`,`content_type_guid`)", + "UPDATE OR INSERT INTO `{$X}liberty_xref_item` + (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`) + VALUES ('B04','contactbusiness','type','Supplier',0,3,'',NULL) + MATCHING (`item`,`content_type_guid`)", + ]]], + + // --- Step 4: remove old 'type' group and $0x items from contact --- + [ 'QUERY' => [ 'SQL92' => [ + "DELETE FROM `{$X}liberty_xref_item` WHERE `content_type_guid` = 'contact' AND `x_group` = 'type'", + "DELETE FROM `{$X}liberty_xref_group` WHERE `content_type_guid` = 'contact' AND `x_group` = 'type'", + ]]], + + // --- Step 5: migrate liberty_content records --- + // Person detection uses old $00 item (still present in liberty_xref at this point) + [ 'QUERY' => [ 'SQL92' => [ + "UPDATE `{$X}liberty_content` SET `content_type_guid` = 'contactperson' + WHERE `content_type_guid` = 'contact' + AND `content_id` IN ( + SELECT `content_id` FROM `{$X}liberty_xref` WHERE `item` = '\$00' + )", + "UPDATE `{$X}liberty_content` SET `content_type_guid` = 'contactbusiness' + WHERE `content_type_guid` = 'contact'", + ]]], + + // --- Step 6: rename existing liberty_xref type-tag rows --- + // $00 (Personal name tag) → P01; $05 (Kit Elf) → P02 + // $02 (Manufacturer) → B02; $03 (Distributor) → B03; $04 (Supplier) → B04 + // $01 (deprecated Business) — deleted; B01 (Service) is new, no existing data + [ 'QUERY' => [ 'SQL92' => [ + "UPDATE `{$X}liberty_xref` SET `item` = 'P01' WHERE `item` = '\$00'", + "UPDATE `{$X}liberty_xref` SET `item` = 'P02' WHERE `item` = '\$05'", + "UPDATE `{$X}liberty_xref` SET `item` = 'B02' WHERE `item` = '\$02'", + "UPDATE `{$X}liberty_xref` SET `item` = 'B03' WHERE `item` = '\$03'", + "UPDATE `{$X}liberty_xref` SET `item` = 'B04' WHERE `item` = '\$04'", + "DELETE FROM `{$X}liberty_xref` WHERE `item` = '\$01'", + ]]], + ] +); diff --git a/display_contact.php b/display_contact.php index 891cd16..6082ccb 100755 --- a/display_contact.php +++ b/display_contact.php @@ -51,6 +51,7 @@ if ($gContent->isCommentable()) { } } +$gBitSmarty->assign( 'isPerson', $gContent instanceof \Bitweaver\Contact\ContactPerson ); $gBitSmarty->assign( 'gXrefInfo', $gContent->mXrefInfo ); $gBitSystem->setBrowserTitle( $gContent->mInfo['title'] ); @@ -73,15 +73,28 @@ if( empty( $formInfo ) ) { $formInfo = &$gContent->mInfo; } -$isPerson = !empty( $gContent->mInfo['contact_types'][0]['content_id'] ); +$isPerson = $gContent instanceof \Bitweaver\Contact\ContactPerson; $gContent->loadXrefInfo(); $gBitSmarty->assign( 'gXrefInfo', $gContent->mXrefInfo ); $gBitSmarty->assign( 'isPerson', $isPerson ); -$allTypes = $gContent->getXrefSourceList(); -$formInfo['contact_type_list'] = $isPerson - ? [] - : array_values( array_filter( $allTypes, fn($t) => $t['item'] > '$01' ) ); +// Build type toggle list: available options from schema (or hard-coded pre-upgrade fallback), +// checked state from contact_types (currently set items in liberty_xref). +$setItems = []; +foreach ( $gContent->mInfo['contact_types'] ?? [] as $ct ) { + if ( !empty( $ct['content_id'] ) ) { + $setItems[ $ct['item'] ] = true; + } +} +$typeToggle = []; +foreach ( $gContent->getAvailableTypeItems() as $m ) { + $typeToggle[] = [ + 'item' => $m['item'], + 'name' => $m['name'], + 'checked' => isset( $setItems[ $m['item'] ] ), + ]; +} +$gContent->mInfo['contact_type_list'] = $typeToggle; $gBitSmarty->assign( 'pageInfo', $formInfo ); $gBitSmarty->assign( 'errors', $gContent->mErrors ); diff --git a/export_contacts.php b/export_contacts.php index 380d94c..608988c 100644 --- a/export_contacts.php +++ b/export_contacts.php @@ -27,7 +27,7 @@ $sql = "SELECT lc.`content_id`, lc.`title`, FROM `" . BIT_DB_PREFIX . "liberty_content` lc LEFT JOIN `" . BIT_DB_PREFIX . "liberty_xref` x00 ON x00.`content_id` = lc.`content_id` AND x00.`item` = '\$00' LEFT JOIN `" . BIT_DB_PREFIX . "liberty_xref` xsc ON xsc.`content_id` = lc.`content_id` AND xsc.`item` = 'SCREF' - WHERE lc.`content_type_guid` = 'contact' + WHERE lc.`content_type_guid` IN ('contactperson','contactbusiness') ORDER BY lc.`title`"; $result = $gBitDb->query( $sql ); @@ -56,7 +56,7 @@ $sql = "SELECT x.`content_id`, x.`item`, xi.`cross_ref_title`, xi.`template`, x.`xkey`, x.`xkey_ext`, x.`data`, x.`xorder`, ap.`add1`, ap.`add2`, ap.`add3`, ap.`add4`, ap.`town`, ap.`county` FROM `" . BIT_DB_PREFIX . "liberty_xref` x - JOIN `" . BIT_DB_PREFIX . "liberty_xref_item` xi ON xi.`item` = x.`item` AND xi.`content_type_guid` = 'contact' + JOIN `" . BIT_DB_PREFIX . "liberty_xref_item` xi ON xi.`item` = x.`item` AND xi.`content_type_guid` IN ('contact','contactperson','contactbusiness') LEFT JOIN `" . BIT_DB_PREFIX . "address_postcode` ap ON ap.`postcode` = x.`xkey` WHERE ( x.`end_date` IS NULL OR x.`end_date` > CURRENT_TIMESTAMP ) AND x.`content_id` IN (" . implode( ',', array_keys( $contacts ) ) . ") diff --git a/import/ImportContactCSV.php b/import/ImportContactCSV.php index ada5732..a6e6b1d 100644 --- a/import/ImportContactCSV.php +++ b/import/ImportContactCSV.php @@ -24,6 +24,8 @@ namespace Bitweaver\Liberty; use Bitweaver\Contact\Contact; +use Bitweaver\Contact\ContactPerson; +use Bitweaver\Contact\ContactBusiness; /** * Delete any existing xref for ($contentId, $item) then re-insert if either $xkey or @@ -95,14 +97,16 @@ function contactCsvImportRow( array $row, int $rowNum ): array { return $result; } - // --- Find existing or create new via Contact class --- + // --- Find existing or create new via Contact subclass --- + $isPerson = ( $type === '$00' ); + $contentId = $gBitDb->getOne( "SELECT `content_id` FROM `" . BIT_DB_PREFIX . "liberty_content` - WHERE `content_type_guid` = 'contact' AND `title` = ?", + WHERE `content_type_guid` IN ('contactperson','contactbusiness','contact') AND `title` = ?", [ $title ] ); - $contact = new Contact( null, $contentId ?: null ); + $contact = $isPerson ? new ContactPerson( null, $contentId ?: null ) : new ContactBusiness( null, $contentId ?: null ); if( $contentId ) { $contact->load(); } @@ -118,7 +122,7 @@ function contactCsvImportRow( array $row, int $rowNum ): array { if( !empty( $type ) && $type[0] === '$' ) { $pHash['contact_types'] = [ $type ]; - if( $type === '$00' ) { + if( $isPerson ) { $pHash['name'] = $personName; } } diff --git a/import/load_contacts_csv.php b/import/load_contacts_csv.php index 3a75030..4e8adc7 100644 --- a/import/load_contacts_csv.php +++ b/import/load_contacts_csv.php @@ -52,7 +52,7 @@ if( !file_exists( $csvFile ) ) { if( empty( $title ) ) continue; $contentId = $gBitDb->getOne( "SELECT `content_id` FROM `" . BIT_DB_PREFIX . "liberty_content` - WHERE `content_type_guid` = 'contact' AND `title` = ?", + WHERE `content_type_guid` IN ('contactperson','contactbusiness') AND `title` = ?", [ $title ] ); if( $contentId ) { diff --git a/includes/bit_setup_inc.php b/includes/bit_setup_inc.php index 8d2b144..c973854 100755 --- a/includes/bit_setup_inc.php +++ b/includes/bit_setup_inc.php @@ -21,6 +21,23 @@ define( 'CONTACT_IMPORT_PATH', STORAGE_PKG_PATH . 'contact/' ); $gBitSystem->registerPackage( $pRegisterHash ); if( $gBitSystem->isPackageActive( 'contact' ) ) { + // Register sub-type content types at startup so getLibertyObject() can resolve them. + // registerContentType() is a no-op in memory once the row exists in the DB. + $gLibertySystem->registerContentType( 'contactperson', [ + 'content_type_guid' => 'contactperson', + 'content_name' => 'Person Contact', + 'handler_class' => 'ContactPerson', + 'handler_package' => 'contact', + 'handler_file' => 'ContactPerson.php', + ] ); + $gLibertySystem->registerContentType( 'contactbusiness', [ + 'content_type_guid' => 'contactbusiness', + 'content_name' => 'Business Contact', + 'handler_class' => 'ContactBusiness', + 'handler_package' => 'contact', + 'handler_file' => 'ContactBusiness.php', + ] ); + $menuHash = [ 'package_name' => CONTACT_PKG_NAME, 'index_url' => CONTACT_PKG_URL . 'index.php', diff --git a/includes/classes/Contact.php b/includes/classes/Contact.php index f5bc6c4..43ae07f 100755 --- a/includes/classes/Contact.php +++ b/includes/classes/Contact.php @@ -15,6 +15,8 @@ use Bitweaver\Liberty\LibertyContent; // Contact base class require_once CONTACT_PKG_PATH.'lib/phpcoord-2.3.php'; define( 'CONTACT_CONTENT_TYPE_GUID', 'contact' ); +defined( 'CONTACTPERSON_CONTENT_TYPE_GUID' ) || define( 'CONTACTPERSON_CONTENT_TYPE_GUID', 'contactperson' ); +defined( 'CONTACTBUSINESS_CONTENT_TYPE_GUID' ) || define( 'CONTACTBUSINESS_CONTENT_TYPE_GUID', 'contactbusiness' ); class Contact extends LibertyContent { @@ -53,7 +55,64 @@ class Contact extends LibertyContent { $this->mAdminContentPerm = 'p_contact_admin'; $this->mTypes = new ContactType(); - $this->mTypes->setup(); + } + + /** + * Load type-tag xref rows (P01/P02/B01–B04) directly from liberty_xref. + * + * The schema-driven getContentTypeMarkers() requires liberty_xref_item rows to + * exist at the contactperson/contactbusiness level — they don't exist until the + * 5.0.3 upgrade runs. Reading liberty_xref directly makes type tags visible in + * both pre- and post-upgrade states. Schema labels are enriched where available. + */ + public function loadXrefTypeList(): void { + if ( !$this->isValid() || !empty( $this->mInfo[$this->mXrefTypeKey] ) ) return; + + $result = $this->mDb->query( + "SELECT x.`item`, x.`xkey_ext`, x.`content_id`, + COALESCE( (SELECT FIRST 1 i2.`cross_ref_title` + FROM `".BIT_DB_PREFIX."liberty_xref_item` i2 + WHERE i2.`item` = x.`item`), + x.`item` ) AS `cross_ref_title` + FROM `".BIT_DB_PREFIX."liberty_xref` x + WHERE x.`content_id` = ? + AND ( x.`item` STARTING WITH 'P' + OR x.`item` STARTING WITH 'B' + OR x.`item` STARTING WITH '\$' ) + ORDER BY x.`item`", + [ $this->mContentId ] + ); + + $this->mInfo[$this->mXrefTypeKey] = []; + while ( $row = $result->fetchRow() ) { + $this->mInfo[$this->mXrefTypeKey][] = $row; + } + } + + /** + * Return all available type-tag options for this contact's edit form. + * + * Uses the schema (liberty_xref_item via getTypeMarkers) post-upgrade. + * Falls back to a hard-coded list pre-upgrade so edit checkboxes always appear. + * P01 is always excluded — it is implied for every person and is not a user choice. + * + * @return array[] Each element: ['item' => string, 'name' => string] + */ + public function getAvailableTypeItems(): array { + $markers = $this->xrefType()->getTypeMarkers(); + if ( !empty( $markers ) ) { + return array_values( array_filter( $markers, fn( $m ) => $m['item'] !== 'P01' ) ); + } + // Pre-upgrade fallback — schema rows not yet migrated + if ( $this->mContentTypeGuid === CONTACTPERSON_CONTENT_TYPE_GUID ) { + return [ [ 'item' => 'P02', 'name' => 'MERG Kit Elf' ] ]; + } + return [ + [ 'item' => 'B01', 'name' => 'Service' ], + [ 'item' => 'B02', 'name' => 'Manufacturer' ], + [ 'item' => 'B03', 'name' => 'Distributor' ], + [ 'item' => 'B04', 'name' => 'Supplier' ], + ]; } /** @@ -77,7 +136,7 @@ class Contact extends LibertyContent { LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON (uue.`user_id` = lc.`modifier_user_id`) LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON (uuc.`user_id` = lc.`user_id`) LEFT JOIN `".BIT_DB_PREFIX."liberty_xref` img ON img.`content_id` = con.`content_id` AND img.`item` = 'IMG' - LEFT JOIN `".BIT_DB_PREFIX."liberty_xref` x00 ON x00.`content_id` = con.`content_id` AND x00.`item` = '$00' + LEFT JOIN `".BIT_DB_PREFIX."liberty_xref` x00 ON x00.`content_id` = con.`content_id` AND x00.`item` = 'P01' LEFT JOIN `".BIT_DB_PREFIX."liberty_xref` xhA ON xhA.`content_id` = con.`content_id` AND xhA.`item` = '#S' AND ( xhA.`end_date` IS NULL OR xhA.`end_date` > CURRENT_TIMESTAMP ) LEFT JOIN `".BIT_DB_PREFIX."liberty_xref` xhL ON xhL.`content_id` = con.`content_id` AND xhL.`item` = '#L' AND ( xhL.`end_date` IS NULL OR xhL.`end_date` > CURRENT_TIMESTAMP ) LEFT JOIN `".BIT_DB_PREFIX."address_postcode` ap ON ap.`postcode` = xhA.`xkey` @@ -203,20 +262,17 @@ class Contact extends LibertyContent { $result = $this->mDb->associateInsert( $atable, $pParamHash['contact_store'] ); } if( !empty( $pParamHash['contact_types'] ) ) { - $query = "DELETE FROM `".BIT_DB_PREFIX."liberty_xref` WHERE `content_id` = ? AND `item` LIKE '$%'"; - $result = $this->mDb->query($query, [$this->mContentId ] ); - foreach ( $pParamHash['contact_types'] as $key => $source ) { - if ( $source == '$00' ) { + $query = "DELETE FROM `".BIT_DB_PREFIX."liberty_xref` WHERE `content_id` = ? AND (`item` STARTING WITH 'P' OR `item` STARTING WITH 'B')"; + $result = $this->mDb->query($query, [ $this->mContentId ] ); + foreach ( $pParamHash['contact_types'] as $key => $source ) { + if ( $source === 'P01' ) { $query = "INSERT INTO `".BIT_DB_PREFIX."liberty_xref` (`xref_id`, `content_id`, `item`, `xkey_ext`, `last_update_date`) VALUES ( ?, ?, ?, ?, NULL )"; $result = $this->mDb->query($query, [ $this->mDb->GenID('liberty_xref_seq'), $this->mContentId, $source, $pParamHash['name'] ] ); - } else if ( $source == '$01' ) { - $query = "INSERT INTO `".BIT_DB_PREFIX."liberty_xref` (`xref_id`, `content_id`, `item`, `xkey_ext`, `last_update_date`) VALUES ( ?, ?, ?, ?, NULL )"; - $result = $this->mDb->query($query, [ $this->mDb->GenID('liberty_xref_seq'), $this->mContentId, $source, $pParamHash['organisation'] ] ); } else { $query = "INSERT INTO `".BIT_DB_PREFIX."liberty_xref` (`xref_id`, `content_id`, `item`, `last_update_date`) VALUES ( ?, ?, ?, NULL )"; $result = $this->mDb->query($query, [ $this->mDb->GenID('liberty_xref_seq'), $this->mContentId, $source ] ); } - } + } } // load before completing transaction as firebird isolates results $this->load(); @@ -267,7 +323,7 @@ class Contact extends LibertyContent { $pContentId = $this->mContentId; } - return CONTACT_PKG_URL.'index.php?content_id='.$pContentId; + return CONTACT_PKG_URL.'display_contact.php?content_id='.$pContentId; } /** @@ -444,12 +500,7 @@ class Contact extends LibertyContent { return $ret; } - /** @return array Map of item code → label from the ContactType setup. */ - public function getContactTypes() { - return $this->mTypes->mContactType; - } - - /** +/** * Load contacts that reference this one via the '#A' xref item into $this->mInfo['client_list']. * * Used for contacts handled by a third party (e.g. alarm maintainer, call centre). diff --git a/includes/classes/ContactBusiness.php b/includes/classes/ContactBusiness.php new file mode 100644 index 0000000..1b75b0e --- /dev/null +++ b/includes/classes/ContactBusiness.php @@ -0,0 +1,28 @@ +<?php +/** + * Business contact — extends Contact with content_type_guid='contactbusiness'. + * + * Business-specific xref types ($02+ subtypes) are registered at the 'contactbusiness' + * level; shared contact fields live at the 'contact' package level. + * + * @package contact + */ +namespace Bitweaver\Contact; + +class ContactBusiness extends Contact { + + public function __construct( $pContactId = NULL, $pContentId = NULL ) { + parent::__construct( $pContactId, $pContentId ); + $this->mContentTypeGuid = CONTACTBUSINESS_CONTENT_TYPE_GUID; + $this->registerContentType( CONTACTBUSINESS_CONTENT_TYPE_GUID, [ + 'content_type_guid' => CONTACTBUSINESS_CONTENT_TYPE_GUID, + 'content_name' => 'Business Contact', + 'handler_class' => 'ContactBusiness', + 'handler_package' => 'contact', + 'handler_file' => 'ContactBusiness.php', + 'maintainer_url' => 'http://lsces.co.uk', + ] ); + // mPackageGuid='contact' is set automatically by registerContentType() + // because handler_package('contact') != content_type_guid('contactbusiness'). + } +} diff --git a/includes/classes/ContactPerson.php b/includes/classes/ContactPerson.php new file mode 100644 index 0000000..5393355 --- /dev/null +++ b/includes/classes/ContactPerson.php @@ -0,0 +1,29 @@ +<?php +/** + * Person contact — extends Contact with content_type_guid='contactperson'. + * + * Person-specific xref items ($00 type etc.) are registered at the 'contactperson' + * level; shared contact fields (addresses, SCREF etc.) live at the 'contact' + * package level and are picked up via the dual-guid xref pattern. + * + * @package contact + */ +namespace Bitweaver\Contact; + +class ContactPerson extends Contact { + + public function __construct( $pContactId = NULL, $pContentId = NULL ) { + parent::__construct( $pContactId, $pContentId ); + $this->mContentTypeGuid = CONTACTPERSON_CONTENT_TYPE_GUID; + $this->registerContentType( CONTACTPERSON_CONTENT_TYPE_GUID, [ + 'content_type_guid' => CONTACTPERSON_CONTENT_TYPE_GUID, + 'content_name' => 'Person Contact', + 'handler_class' => 'ContactPerson', + 'handler_package' => 'contact', + 'handler_file' => 'ContactPerson.php', + 'maintainer_url' => 'http://lsces.co.uk', + ] ); + // mPackageGuid='contact' is set automatically by registerContentType() + // because handler_package('contact') != content_type_guid('contactperson'). + } +} diff --git a/includes/classes/ContactType.php b/includes/classes/ContactType.php index 47b837f..45607d1 100755 --- a/includes/classes/ContactType.php +++ b/includes/classes/ContactType.php @@ -8,6 +8,7 @@ namespace Bitweaver\Contact; use Bitweaver\BitBase; +use Bitweaver\Liberty\LibertyXrefType; class ContactType extends BitBase { public $mContactType; @@ -17,31 +18,21 @@ class ContactType extends BitBase { } /** - * Populate $this->mContactType from liberty_xref_item (sort_order=0 groups) - * and assign 'contContactTypes' to Smarty for use in list/filter templates. + * Return all contact type markers (person + business) as item => title array. + * + * Each sub-type is queried independently via LibertyXrefType so the two sets + * of items are never mixed in a single query. + * + * @return array<string,string> e.g. ['$00' => 'Personal', '$04' => 'Supplier', ...] */ - public function setup() { - global $gBitUser, $gBitSmarty; - - $roles = array_keys($gBitUser->mRoles ?? []) ?: [-1]; - $bindVars = []; - $bindVars = array_merge( $bindVars, $roles, [ $gBitUser->mUserId ] ); - - $sql = "SELECT r.`item`, r.`cross_ref_title` - 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` = r.`content_type_guid` - 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` = 'contact' AND t.`sort_order` = 0 AND (r.`role_id` IN(". implode(',', array_fill(0, count($roles), '?')) ." ) OR purm.`user_id`=?) - ORDER BY r.`item`"; - - $result = $this->mDb->query( $sql, $bindVars ); - - while( $res = $result->fetchRow() ) { - $this->mContactType[ $res['item']] = $res['cross_ref_title']; + public static function getTypeMarkerList(): array { + $ret = []; + foreach ( [ 'contactperson', 'contactbusiness' ] as $guid ) { + foreach ( ( new LibertyXrefType( $guid ) )->getTypeMarkers() as $m ) { + $ret[ $m['item'] ] = $m['name']; + } } - -// asort($this->mContactType); - $gBitSmarty->assign( 'contContactTypes', $this->mContactType ); + return $ret; } /** @@ -87,7 +78,7 @@ class ContactType extends BitBase { $bindVars[] = $pOptionHash['title']; } - $guidWhere = " cxt.`content_type_guid` = 'contact' "; + $guidWhere = " cxt.`content_type_guid` IN ('contact','contactperson','contactbusiness') "; $where = $where ? $where . " AND $guidWhere" : " WHERE $guidWhere"; $query = "SELECT cxt.* @@ -100,7 +91,7 @@ class ContactType extends BitBase { while( $res = $result->fetchRow() ) { $res["num_types"] = $gBitSystem->mDb->getOne( - "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."liberty_xref_item` WHERE `x_group` = ? AND `content_type_guid` = 'contact'", + "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."liberty_xref_item` WHERE `x_group` = ? AND `content_type_guid` IN ('contact','contactperson','contactbusiness')", [ $res["x_group"] ] ); $ret[] = $res; diff --git a/includes/lookup_contact.php b/includes/lookup_contact.php index e477fb9..098bca1 100644 --- a/includes/lookup_contact.php +++ b/includes/lookup_contact.php @@ -31,7 +31,7 @@ $rows = $gBitDb->getArray( (SELECT FIRST 1 sx.xkey FROM ".BIT_DB_PREFIX."liberty_xref sx WHERE sx.content_id=lc.content_id AND sx.item='SCREF') AS scref FROM ".BIT_DB_PREFIX."liberty_content lc - WHERE lc.content_type_guid='contact' + WHERE lc.content_type_guid IN ('contactperson','contactbusiness') AND (LOWER(lc.title) LIKE ? OR EXISTS ( SELECT 1 FROM ".BIT_DB_PREFIX."liberty_xref sx WHERE sx.content_id=lc.content_id AND sx.item='SCREF' AND LOWER(sx.xkey) LIKE ? diff --git a/includes/lookup_contact_inc.php b/includes/lookup_contact_inc.php index 1c77c99..6804d9d 100755 --- a/includes/lookup_contact_inc.php +++ b/includes/lookup_contact_inc.php @@ -10,13 +10,17 @@ */ use Bitweaver\BitBase; use Bitweaver\Contact\Contact; -//require_once( TASKS_PKG_PATH.'Tasks.php'); +use Bitweaver\Liberty\LibertyContent; // if we already have a gContent, we assume someone else created it for us, and has properly loaded everything up. if( empty( $gContent ) || !is_object( $gContent ) ) { if( BitBase::verifyId( $_REQUEST['content_id'] ?? 0 ) ) { - $gContent = new Contact( NULL, $_REQUEST['content_id'] ); - $gContent->load(); + // getLibertyObject returns ContactPerson or ContactBusiness (already loaded) + $gContent = LibertyContent::getLibertyObject( (int)$_REQUEST['content_id'] ); + if( !( $gContent instanceof Contact ) ) { + // Fallback: content_id exists but is not a contact type + $gContent = new Contact( NULL, (int)$_REQUEST['content_id'] ); + } } else { $gContent = new Contact(); } @@ -16,6 +16,7 @@ require_once '../kernel/includes/setup_inc.php'; use Bitweaver\Contact\Contact; +use Bitweaver\Contact\ContactType; use Bitweaver\KernelTools; $gBitSystem->verifyPackage( 'contact' ); @@ -24,7 +25,7 @@ $gBitSystem->verifyPermission( 'p_contact_view' ); $gContent = new Contact( ); $gContent->invokeServices( 'content_list_function', $_REQUEST ); -// Handle the request hash storing into the session. +$gBitSmarty->assign( 'contContactTypes', ContactType::getTypeMarkerList() ); $gContent->mTypes->processRequestHash($_REQUEST, $_SESSION['contact']); $listHash = $_REQUEST; @@ -16,6 +16,7 @@ require_once '../kernel/includes/setup_inc.php'; use Bitweaver\Contact\Contact; +use Bitweaver\Contact\ContactType; use Bitweaver\KernelTools; $gBitSystem->verifyPackage( 'contact' ); @@ -24,7 +25,7 @@ $gBitSystem->verifyPermission( 'p_contact_view' ); $gContent = new Contact( ); $gContent->invokeServices( 'content_list_function', $_REQUEST ); -// Handle the request hash storing into the session. +$gBitSmarty->assign( 'contContactTypes', ContactType::getTypeMarkerList() ); $gContent->mTypes->processRequestHash($_REQUEST, $_SESSION['contact']); $listHash = $_REQUEST; diff --git a/list_businesses.php b/list_businesses.php new file mode 100644 index 0000000..b4dd4b1 --- /dev/null +++ b/list_businesses.php @@ -0,0 +1,36 @@ +<?php +/** + * @package contact + */ + +require_once '../kernel/includes/setup_inc.php'; + +use Bitweaver\Contact\ContactBusiness; +use Bitweaver\Contact\ContactType; +use Bitweaver\KernelTools; +use Bitweaver\Liberty\LibertyXrefType; + +$gBitSystem->verifyPackage( 'contact' ); +$gBitSystem->verifyPermission( 'p_contact_view' ); + +$gContent = new ContactBusiness(); +$gContent->invokeServices( 'content_list_function', $_REQUEST ); +$gContent->mTypes->processRequestHash( $_REQUEST, $_SESSION['contact'] ); + +// Business type filter: contactbusiness type markers only (never mix with contactperson) +$businessTypes = ( new LibertyXrefType( CONTACTBUSINESS_CONTENT_TYPE_GUID ) )->getTypeMarkers(); +$gBitSmarty->assign( 'contContactTypes', array_column( $businessTypes, 'name', 'item' ) ); + +$listHash = $_REQUEST; +$listcontacts = $gContent->getList( $listHash ); + +if( $listHash['listInfo']['count'] == 1 ) { + KernelTools::bit_redirect( CONTACT_PKG_URL . "display_contact.php?content_id=" . $listcontacts[0]['content_id'] ); +} + +$gBitSmarty->assign( 'listcontacts', $listcontacts ); +$gBitSmarty->assign( 'listInfo', $listHash['listInfo'] ); +$gBitSmarty->assign( 'listTitle', KernelTools::tra( 'Businesses' ) ); + +$gBitSystem->setBrowserTitle( KernelTools::tra( 'Businesses' ) ); +$gBitSystem->display( 'bitpackage:contact/list.tpl', NULL, [ 'display_mode' => 'list' ] ); diff --git a/list_contacts.php b/list_contacts.php index 9aa8ca9..0d1899e 100755 --- a/list_contacts.php +++ b/list_contacts.php @@ -6,19 +6,34 @@ require_once '../kernel/includes/setup_inc.php'; -use Bitweaver\Contact\Contact; +use Bitweaver\Contact\ContactPerson; +use Bitweaver\Contact\ContactBusiness; use Bitweaver\KernelTools; $gBitSystem->verifyPackage( 'contact' ); $gBitSystem->verifyPermission( 'p_contact_view' ); -$gContent = new Contact(); -$gContent->invokeServices( 'content_list_function', $_REQUEST ); +// Persons and businesses are separate types — each has its own getList(). +// The combined display is a view-layer concern: merge, sort, and let the +// template select the row template by content_type_guid. +$personContent = new ContactPerson(); +$businessContent = new ContactBusiness(); -$listHash = $_REQUEST; -$listcontacts = $gContent->getList( $listHash ); +$personHash = $_REQUEST; +$businessHash = $_REQUEST; -if( $listHash['listInfo']['count'] == 1 ) { +$persons = $personContent->getList( $personHash ); +$businesses = $businessContent->getList( $businessHash ); + +$listcontacts = array_merge( $persons, $businesses ); +usort( $listcontacts, fn( $a, $b ) => strcasecmp( $a['title'] ?? '', $b['title'] ?? '' ) ); + +// listInfo: sum the two counts; use personHash's pagination metadata as base +$listHash = $personHash; +$listHash['cant'] = ( $personHash['cant'] ?? 0 ) + ( $businessHash['cant'] ?? 0 ); +$listHash['listInfo']['count'] = $listHash['cant']; + +if( $listHash['cant'] == 1 ) { KernelTools::bit_redirect( CONTACT_PKG_URL."display_contact.php?content_id=".$listcontacts[0]['content_id'] ); } diff --git a/list_people.php b/list_people.php new file mode 100644 index 0000000..56ba8ad --- /dev/null +++ b/list_people.php @@ -0,0 +1,30 @@ +<?php +/** + * @package contact + */ + +require_once '../kernel/includes/setup_inc.php'; + +use Bitweaver\Contact\ContactPerson; +use Bitweaver\KernelTools; + +$gBitSystem->verifyPackage( 'contact' ); +$gBitSystem->verifyPermission( 'p_contact_view' ); + +$gContent = new ContactPerson(); +$gContent->invokeServices( 'content_list_function', $_REQUEST ); +$gContent->mTypes->processRequestHash( $_REQUEST, $_SESSION['contact'] ); + +$listHash = $_REQUEST; +$listcontacts = $gContent->getList( $listHash ); + +if( $listHash['listInfo']['count'] == 1 ) { + KernelTools::bit_redirect( CONTACT_PKG_URL . "display_contact.php?content_id=" . $listcontacts[0]['content_id'] ); +} + +$gBitSmarty->assign( 'listcontacts', $listcontacts ); +$gBitSmarty->assign( 'listInfo', $listHash['listInfo'] ); +$gBitSmarty->assign( 'listTitle', KernelTools::tra( 'People' ) ); + +$gBitSystem->setBrowserTitle( KernelTools::tra( 'People' ) ); +$gBitSystem->display( 'bitpackage:contact/list.tpl', NULL, [ 'display_mode' => 'list' ] ); diff --git a/templates/display_contact.tpl b/templates/display_contact.tpl index 8512d33..2a3ba39 100755 --- a/templates/display_contact.tpl +++ b/templates/display_contact.tpl @@ -9,7 +9,7 @@ <div class="clear"></div> </div> {/if} - {if $gContent->mInfo.contact_types.0.content_id} + {if $isPerson} <div class="form-group"> {formlabel label="Name"} {forminput} diff --git a/templates/display_type_header.tpl b/templates/display_type_header.tpl index 350ce1c..f8647a7 100755 --- a/templates/display_type_header.tpl +++ b/templates/display_type_header.tpl @@ -1,8 +1,8 @@ <div class="form-group"> - {formlabel label="{if $gContent->mInfo.contact_types.0.content_id}Personal Contact{else}Business Contact{/if}"} + {formlabel label="{if $isPerson}Personal Contact{else}Business Contact{/if}"} {forminput} {foreach from=$gContent->mInfo.contact_types key=type_id item=type} - {if isset($type.content_id) && $type.item gt '$01'}{$type.cross_ref_title}<br/>{/if} + {if isset($type.content_id) && $type.item neq 'P01'}{$type.cross_ref_title}<br/>{/if} {/foreach} {/forminput} <div class="clear"></div> diff --git a/templates/edit.tpl b/templates/edit.tpl index 9caf1d9..e164291 100755 --- a/templates/edit.tpl +++ b/templates/edit.tpl @@ -51,11 +51,9 @@ <div class="clear"></div> </div> - {if !$isPerson} - {include file="bitpackage:contact/edit_type_header.tpl"} - {/if} + {include file="bitpackage:contact/edit_type_header.tpl"} - {if $gContent->mInfo.name || $gContent->mInfo.contact_types.0.content_id || !isset( $gContent->mInfo.contact_types ) } + {if $isPerson} <div class="form-group"> {formlabel label="Title" for="prefix"} {forminput} diff --git a/templates/edit_type_header.tpl b/templates/edit_type_header.tpl index 3d42abb..c4f6756 100755 --- a/templates/edit_type_header.tpl +++ b/templates/edit_type_header.tpl @@ -1,19 +1,12 @@ <div class="form-group"> - {formlabel label="Contact Types" for=content_types} + {formlabel label="Contact Types"} {forminput} - {if isset( $gContent->mInfo.contact_types ) } - {foreach from=$gContent->mInfo.contact_types key=type_id item=type} - {if $type.item gt '$01'} - <input type="checkbox" name="contact_types[{$type_id}]" value="{$type.item}" {if isset($type.content_id) } checked="checked"{/if} /> {$type.cross_ref_title}<br/> - {/if} - {/foreach} - {else} - {foreach from=$gContent->mInfo.contact_type_list key=type_id item=type} - <input type="checkbox" name="contact_types[$type_id]" value="{$type.item}" />{$type.name}<br/> - {/foreach} - {/if} + {foreach from=$gContent->mInfo.contact_type_list item=type} + <label class="checkbox-inline"> + <input type="checkbox" name="contact_types[]" value="{$type.item|escape}"{if $type.checked} checked="checked"{/if} /> {$type.name|escape} + </label> + {/foreach} {/forminput} - {formhelp note=""} <div class="clear"></div> </div> diff --git a/templates/list.tpl b/templates/list.tpl index bba6f3c..b8cd94e 100755 --- a/templates/list.tpl +++ b/templates/list.tpl @@ -4,7 +4,7 @@ <div class="listing contacts"> <div class="header"> - <h1>{tr}Contacts{/tr}</h1> + <h1>{if $listTitle}{$listTitle|escape}{else}{tr}Contacts{/tr}{/if}</h1> </div> <div class="body"> diff --git a/templates/menu_contact.tpl b/templates/menu_contact.tpl index 56913cf..c53c197 100755 --- a/templates/menu_contact.tpl +++ b/templates/menu_contact.tpl @@ -1,8 +1,10 @@ {strip} {if $packageMenuTitle}<a class="dropdown-toggle" data-toggle="dropdown" href="#"> {tr}{$packageMenuTitle}{/tr} <b class="caret"></b></a>{/if} <ul class="{$packageMenuClass}"> - <li><a class="item" href="{$smarty.const.CONTACT_PKG_URL}list_contacts.php">{biticon ipackage="icons" iname="view-list" iexplain="List contacts" ilocation=menu}</a></li> - {if $gBitUser->isAdmin() || $gBitUser->hasPermission( 'p_contact_edit' ) } + <li><a class="item" href="{$smarty.const.CONTACT_PKG_URL}list_people.php">{biticon ipackage="icons" iname="view-list" iexplain="List People" ilocation=menu}</a></li> + <li><a class="item" href="{$smarty.const.CONTACT_PKG_URL}list_businesses.php">{biticon ipackage="icons" iname="view-list" iexplain="List Businesses" ilocation=menu}</a></li> + <li><a class="item" href="{$smarty.const.CONTACT_PKG_URL}list_contacts.php">{biticon ipackage="icons" iname="system-search" iexplain="All Contacts" ilocation=menu}</a></li> + {if $gBitUser->isAdmin() || $gBitUser->hasPermission( 'p_contact_update' ) } <li><a class="item" href="{$smarty.const.CONTACT_PKG_URL}add_person.php">{biticon ipackage="icons" iname="contact-new-symbolic" iexplain="Add Person" ilocation=menu}</a></li> <li><a class="item" href="{$smarty.const.CONTACT_PKG_URL}add_business.php">{biticon ipackage="icons" iname="address-book-new-symbolic" iexplain="Add Business" ilocation=menu}</a></li> {/if} |
