Firms Documentation

Firms Controller Documentation

File: /controllers/firms.php

Purpose: Manages company/firm directory with hierarchical filtering by country, region, and department

Last Updated: December 20, 2024

Total Functions: 9

Lines of Code: 368

---

๐Ÿ“‹ Overview

The Firms Controller is a directory management system that provides hierarchical navigation through firms based on geographic and business department filtering. It handles:

Primary Functions

Related Controllers

---

๐Ÿ—„๏ธ Database Tables

Primary Tables (Direct Operations)

Table NamePurposeKey Columns
**firms**Company master dataid, name, logo, departid
**firmbranches**Company branch locationsid, firmid, regionid
**firmproducts**Company product catalogid, firmid, name, image
**firmfiles**Company file attachmentsid, firmid, filename, filepath
**packagefirms**Company package offeringsid, firmid, packageid
### Reference Tables

Table NamePurposeKey Columns
**country**Country master dataid, name, hide
**region**Regional divisionsid, name, countryid, hide
**depart**Business departmentsid, name, image
**package**Package definitionsid, name, image
---

๐Ÿ”‘ Key Functions

1. index() / Default Action - Hierarchical Firm Directory

Location: Line 33

Purpose: Display firms filtered by geographic and department hierarchy

Function Signature:

public function index()
// Triggered when: no action specified or main directory access

Process Flow:

1. Parse incoming filter parameters (country, region, department)

2. Apply hierarchical filtering logic

3. Execute appropriate SQL query based on filter combination

4. Load supporting data (countries, regions, departments)

5. Display via filter.html and departments.html templates

Filter Combinations:

Features:

---

2. getregions() - AJAX Region Loading

Location: Line 97

Purpose: Load regions for selected country via AJAX

Function Signature:

public function getregions()
// Triggered via: AJAX POST with countryId

Process Flow:

1. Receive country ID from POST

2. Query regions for specified country

3. Build HTML option list for dropdown

4. Query departments available in country

5. Generate department display cards

6. Return JSON response with both datasets

Response Format:

{
  "result1": "<option>...</option>",  // Region dropdown options
  "result2": "<li><div>...</div></li>" // Department cards HTML
}

---

3. getdepts() - AJAX Department Loading

Location: Line 133

Purpose: Load departments for selected country/region combination

Function Signature:

public function getdepts()
// Triggered via: AJAX POST with countryId, regionId

Process Flow:

1. Receive country and region IDs

2. Query departments with firms in specified region

3. Build dropdown options and display cards

4. Include department images and firm count links

5. Return formatted JSON response

---

4. getfirms() - AJAX Firm Loading

Location: Line 169

Purpose: Load firms for selected department/region combination

Function Signature:

public function getfirms()
// Triggered via: AJAX POST with deptId, regionId

Process Flow:

1. Query firms matching department and region

2. Generate firm display cards with logos

3. Include links to firm detail pages

4. Return HTML-formatted firm listings

---

5. showcompanies() - Company Listing Page

Location: Line 202

Purpose: Display paginated company listings based on filter criteria

Function Signature:

public function showcompanies()
// Triggered when: accessing firms by department/region

Process Flow:

1. Parse filter parameters from URL

2. Execute complex filtering logic

3. Load supporting reference data

4. Display via firms.html template

Filter Logic:

if ($regionId != -1 && $countryId != -1) {
    // Specific region and department
} elseif ($regionId == -1 && $countryId != -1) {
    // Country and department only
} elseif ($countryId == -1 && $regionId != -1) {
    // Region and department only
} else {
    // Department only
}

---

6. companydetail() - Company Detail View

Location: Line 258

Purpose: Display comprehensive company information

Function Signature:

public function companydetail()
// Triggered when: accessing individual company details

Process Flow:

1. Load firm master data

2. Retrieve all branch locations

3. Load product catalog

4. Get package offerings with details

5. Load file attachments

6. Process package metadata

7. Display via company.html template

Data Enhancement:

foreach ($firmPackages as $firmPackage) {
    $package = R::load('package', $firmPackage->packageid);
    $firmPackage->packName = $package->name;
    $firmPackage->packPhoto = $package->image;
}

---

7. productdetail() - Product Detail View

Location: Line 284

Purpose: Display individual product information

Function Signature:

public function productdetail()
// Triggered when: accessing product details from firm catalog

Process Flow:

1. Load product data by ID

2. Preserve search context

3. Display via product.html template

---

8. getcomps() - Advanced AJAX Company Filtering

Location: Line 298

Purpose: Handle complex AJAX filtering with multiple parameters

Function Signature:

public function getcomps()
// Triggered via: AJAX POST with complex filter parameters

Process Flow:

1. Process multiple filter parameters

2. Apply same filtering logic as showcompanies()

3. Handle special cases (country changes)

4. Return JSON with options and display HTML

---

๐Ÿ”„ Workflows

Workflow 1: Hierarchical Firm Discovery

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
START: Access Firms Directory
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
1Load Initial View
- Display all countries
- Show all departments
- Set filter state to "show all"
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
2User Selects Country
AJAX call: getregions()
โ”‚
โ†’ Load regions for country
โ”‚
โ†’ Load departments in country
โ”‚
โ”‚ โ””โ”€โ†’ Update dropdowns and display โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
3User Selects Region
AJAX call: getdepts()
โ”‚
โ†’ Load departments in region
โ”‚
โ”‚ โ””โ”€โ†’ Update department display โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
4User Selects Department
AJAX call: getfirms()
โ”‚
โ†’ Load firms in department/region
โ”‚
โ”‚ โ””โ”€โ†’ Display firm cards with logos โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
5User Clicks Firm Details
Navigate to: companydetail()
โ”‚
โ†’ Load firm master data
โ”‚
โ†’ Load branches, products, packages
โ”‚
โ”‚ โ””โ”€โ†’ Display comprehensive firm profile โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

Workflow 2: Direct Firm Access

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
START: Direct URL or Link Access
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
1Parse URL Parameters
- Extract department, country, region IDs
- Validate parameter combinations
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
2Execute Appropriate Query
IF all parameters present:
โ”‚
โ†’ Show firms in specific dept/region
โ”‚
ELSE IF region missing:
โ”‚
โ†’ Show firms in dept/country
โ”‚
ELSE:
โ”‚
โ”‚ โ””โ”€โ†’ Show all firms in department โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
3Load Supporting Data
- Load countries for filter dropdown
- Load regions if country specified
- Prepare navigation breadcrumbs
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
4Display Results
- Show firm listings with logos
- Enable filtering interface
- Provide detail page links
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

๐ŸŒ URL Routes & Actions

Route PatternFunction CalledDescription
`/firms/` or `/firms/index``index()`Main directory page
`/firms/showcompanies/{dept},{country},{region}``showcompanies()`Filtered company listings
`/firms/companydetail/{id}``companydetail()`Individual firm details
`/firms/productdetail/{productid}``productdetail()`Product detail page
### AJAX Endpoints

EndpointFunction CalledPurpose
POST `/firms/getregions``getregions()`Load regions for country
POST `/firms/getdepts``getdepts()`Load departments for region
POST `/firms/getfirms``getfirms()`Load firms for filters
POST `/firms/getcomps``getcomps()`Advanced firm filtering
### Required Parameters

Company Listings (showcompanies):

Company Details (companydetail):

Product Details (productdetail):

---

๐Ÿ”’ Security & Permissions

Input Sanitization

$companyId = filter_input(INPUT_GET, 'id');
$countryId = filter_input(INPUT_POST, 'countryId');
// All inputs filtered through filter_input()

File Access Control

SQL Injection Prevention

---

๐Ÿ“Š Performance Considerations

Database Optimization Tips

1. Indexes Required:

- firmbranches(regionid, firmid)

- firms(departid)

- firmproducts(firmid)

- region(countryid, hide)

2. Query Optimization:

- Complex JOINs in filtering queries

- DISTINCT clauses for unique results

- Consider materialized views for complex filters

3. Memory Management:

- Large datasets for major departments

- Image loading optimization needed

- AJAX pagination for large firm lists

Known Performance Issues

-- This query can be slow with many firms
SELECT distinct f.* from firms f
JOIN depart d ON d.id = f.departid
JOIN firmbranches b ON b.firmid = f.id
WHERE b.regionid = ? and f.departid = ?

-- Solution: Add composite index
CREATE INDEX idx_firm_branch_region ON firmbranches(regionid, firmid);
CREATE INDEX idx_firm_department ON firms(departid);

---

๐Ÿ› Common Issues & Troubleshooting

1. Missing Firm Images

Issue: Firms display without logos or broken image links

Cause: Missing files in /upload/firms/ directory

Debug:

// Check file existence before display
if (file_exists("../upload/firms/{$firm->logo}")) {
    echo $firm->logo;
} else {
    echo "default-logo.png";
}

2. AJAX Filtering Not Working

Issue: Dropdown changes don't trigger region/department updates

Cause: JavaScript errors or missing POST parameters

Debug:

// Check browser console for errors
// Verify POST data format
console.log("Sending:", {countryId: selectedValue});

3. Hierarchical Filtering Logic Errors

Issue: Wrong firms displayed for filter combination

Cause: Complex conditional logic in filtering functions

Debug:

-- Test filter queries directly
SELECT DISTINCT f.* FROM firms f
JOIN firmbranches b ON b.firmid = f.id
WHERE b.regionid = 5 AND f.departid = 3;

-- Check for missing relationships
SELECT f.id, f.name, COUNT(b.id) as branch_count
FROM firms f
LEFT JOIN firmbranches b ON b.firmid = f.id
GROUP BY f.id
HAVING branch_count = 0;

4. Slow Page Loading

Issue: Directory pages load slowly with large datasets

Cause: Complex queries without proper indexing

Solution:

---

๐Ÿงช Testing Scenarios

Test Case 1: Hierarchical Navigation

1. Access main firms directory
2. Select country from dropdown
3. Verify regions load correctly
4. Select region, verify departments update
5. Select department, verify firms display
6. Check all filter combinations work

Test Case 2: Direct URL Access

1. Access URL: /firms/showcompanies/5,2,3
2. Verify correct firms display
3. Test with -1 parameters for "all"
4. Verify breadcrumb navigation works

Test Case 3: Company Detail Page

1. Click firm from listings
2. Verify all sections load:
   - Company information
   - Branch locations
   - Product catalog
   - Package offerings
   - File attachments
3. Test product detail links

Test Case 4: AJAX Functionality

1. Test each AJAX endpoint individually
2. Verify JSON response format
3. Check error handling for invalid IDs
4. Test concurrent AJAX requests

---

๐Ÿ“š Related Documentation

---

Documented By: AI Assistant

Review Status: โœ… Complete

Next Review: When major changes occur