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:
- โข Company/firm directory management
- โข Geographic filtering (country โ region โ department)
- โข Firm branch management
- โข Product catalog browsing
- โข Package offerings display
- โข File attachment handling
- โข AJAX-based filtering interface
- โข Multi-level navigation system
Primary Functions
- โ Hierarchical firm filtering (country/region/department)
- โ Company detail views
- โ Product catalog integration
- โ Branch location management
- โ Package offerings display
- โ File attachment management
- โ AJAX navigation interface
- โ Multi-language support (Arabic/English)
Related Controllers
- โข propertiesController.php - Property management
- โข ads.php - Advertisement management
---
๐๏ธ Database Tables
Primary Tables (Direct Operations)
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **firms** | Company master data | id, name, logo, departid | |
| **firmbranches** | Company branch locations | id, firmid, regionid | |
| **firmproducts** | Company product catalog | id, firmid, name, image | |
| **firmfiles** | Company file attachments | id, firmid, filename, filepath | |
| **packagefirms** | Company package offerings | id, firmid, packageid |
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **country** | Country master data | id, name, hide | |
| **region** | Regional divisions | id, name, countryid, hide | |
| **depart** | Business departments | id, name, image | |
| **package** | Package definitions | id, 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:
- โข All filters: Show specific firms in region/department
- โข Country + Region: Show departments in region
- โข Country only: Show departments in country
- โข No filters: Show all departments
Features:
- โข Geographic drill-down navigation
- โข Department-based filtering
- โข Dynamic template assignment
- โข Multi-language support
---
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
---
Workflow 2: Direct Firm Access
---
๐ URL Routes & Actions
| Route Pattern | Function Called | Description | |
|---|---|---|---|
| `/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 |
| Endpoint | Function Called | Purpose | |
|---|---|---|---|
| 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 |
Company Listings (showcompanies):
- โข
id- Comma-separated:{deptId},{countryId},{regionId} - โข Use
-1for "all" in any position
Company Details (companydetail):
- โข
id- Firm ID
Product Details (productdetail):
- โข
productid- Product ID - โข
search- Optional search context
---
๐ 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
- โข Images served from
/upload/directories - โข File paths validated before access
- โข No direct file system access from user input
SQL Injection Prevention
- โข Uses RedBeanPHP ORM for all database operations
- โข Parameterized queries throughout
- โข No raw SQL with user input
---
๐ 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:
- โข Add database indexes on JOIN columns
- โข Implement pagination for large result sets
- โข Cache department/region data
- โข Optimize image loading with lazy loading
---
๐งช 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
- โข CLAUDE.md - PHP 8.2 migration guide
- โข propertiesController.md - Property management
- โข ads.md - Advertisement management
---
Documented By: AI Assistant
Review Status: โ Complete
Next Review: When major changes occur