This is a Laravel application that identifies affiliates within 100km of Gambling.com Group's Dublin office. The system reads affiliate data from a text file and displays matching affiliates sorted by affiliate_id, using precise geographic calculations with the great-circle distance formula.
This Laravel application features:
- Clean web interface with simple HTML/CSS styling
- JSON API endpoint demonstrating service layer reuse
- Service pattern implementation for business logic separation
- Error handling with email notifications
- Caching system for performance optimization
- Comprehensive Unit and Feature tests
- Production-ready code structure
- Geographic Distance Calculation: Uses the great-circle distance formula for accurate distance calculations from Dublin office (53.3340285, -6.2535495)
- Web Interface: Simple, clean HTML interface with basic styling
- JSON API: RESTful API endpoint for programmatic access to affiliate data
- Service Pattern: Clean separation of business logic using Service classes with reuse across web and API controllers
- Caching: File-based caching of affiliate data with configurable TTL
- Error Handling: Exception handling with optional email notifications
- Testing: Comprehensive Feature and Unit tests
- PHP 8.2 or higher
- Composer
- Laravel 12
# Step 1 - Clone the repository
git clone https://github.com/marcovie/gambling.com_affiliate_invites_tech_test
cd gambling.com_affiliate_invites_tech_test-main
# Step 2 - Install PHP dependencies
composer install -o
# Step 3 - Copy environment file
cp .env.example .env
# Step 4 - Generate application key
php artisan key:generate
# Step 5 - Start the development server
php artisan serveThe application will be available at: http://127.0.0.1:8000
The JSON API endpoint will be available at: http://127.0.0.1:8000/api/affiliates
The application works out of the box, but you can customize these settings in .env:
# Cache TTL for affiliate data (default: 3600 seconds)
AFFILIATE_CACHE_TTL=3600
# Distance limit (default: 100km)
AFFILIATE_DISTANCE_LIMIT_KM=100
# Dublin office coordinates (defaults provided)
DUBLIN_OFFICE_LATITUDE=53.3340285
DUBLIN_OFFICE_LONGITUDE=-6.2535495This Laravel application follows MVC architecture with the following key components:
app/Http/Controllers/AffiliateController.php- Main invokable controller handling affiliate displayapp/Http/Controllers/Api/AffiliateApiController.php- API controller providing JSON responses
app/Services/AffiliateService.php- Core business logic for affiliate distance calculations, caching, and file processing
app/DTOs/AffiliateDTO.php- Affiliate data structureapp/DTOs/CoordinateDTO.php- Geographic coordinate data structure
app/Helpers/GeographicHelper.php- Reusable geographic calculation utilities for distance calculations and filtering
app/Http/Resources/AffiliateResource.php- JSON API resource for formatting affiliate data responses
resources/views/affiliates/index.blade.php- Main HTML view with table display
storage/app/private/affiliates.txt- Affiliate data file (JSON format, one per line)
config/services.php- Application configuration including Dublin coordinates and cache settings
The application provides a JSON API endpoint that demonstrates service layer reuse between the web interface and API:
Returns a JSON response containing all affiliates within 100km of the Dublin office, sorted by affiliate ID.
Example Response:
{
"data": [
{
"affiliate_id": 1,
"name": "John Doe",
"latitude": 53.35,
"longitude": -6.25,
"distance": 25.5
},
{
"affiliate_id": 2,
"name": "Jane Smith",
"latitude": 53.4,
"longitude": -6.3,
"distance": 45.2
}
]
}Error Response (404):
{
"data": []
}The API endpoint demonstrates clean architecture by reusing the same AffiliateService that powers the web interface. This approach ensures:
- Consistency: Both web and API interfaces use identical business logic
- Maintainability: Updates to affiliate processing logic automatically apply to both interfaces
- Testability: Service layer can be tested independently of presentation layer
- Scalability: Easy to add to for (mobile app, CLI, etc.) using the same core service
Run the test suite using Laravel's built-in testing commands:
# Run all tests
php artisan test
# Run tests with coverage
php artisan test --coverage
# Run specific test types
php artisan test tests/Feature
php artisan test tests/Unit
# Code style check (optional)
./vendor/bin/pint --test
# Check any larastan issues (optional)
./vendor/bin/phpstan analyse --memory-limit=512MThe project includes:
- Feature Tests: End-to-end testing of both web and API controllers
- Unit Tests: Testing of individual components (DTOs, Services, Helpers)
The application uses the great-circle distance formula from Wikipedia to calculate distances between coordinates.
Dublin Office Coordinates: 53.3340285, -6.2535495
A reusable helper class (app/Helpers/GeographicHelper.php) provides geographic calculation functionality that can be used throughout the system:
calculateDistance()- Calculates great-circle distance between two coordinatesfilterByDistance()- Filters collections of objects by distance from a reference point and sorts results
This helper was created for potential reuse in other parts of the system that may require similar geographic calculations.
- Reads affiliate data from
storage/app/private/affiliates.txt - Calculates distance from Dublin office for each affiliate
- Filters affiliates within 100km radius
- Returns results sorted by Affiliate ID (ascending)
Each line in affiliates.txt contains a JSON object:
{
"latitude": "53.123456",
"affiliate_id": 12,
"name": "John Doe",
"longitude": "-6.654321"
}- File-based Data: No database required - reads from text file
- Dual Interface: Both web UI and JSON API access the same business logic
- Caching: Configurable caching to avoid repeated file reads
- Error Handling: Graceful error handling with optional email notifications
- Clean Architecture: Separation of concerns using Services and DTOs
- Configuration-driven: All settings configurable via environment variables
For production deployment:
# Optimize for production
php artisan optimize
composer install --optimize-autoloader --no-dev
# Set proper permissions
chmod -R 755 storage bootstrap/cache
chown -R www-data:www-data storage bootstrap/cache
# Update environment
APP_ENV=production
APP_DEBUG=false-
Affiliate data file not found
- Ensure
storage/app/private/affiliates.txtexists - Check file permissions:
chmod 644 storage/app/private/affiliates.txt
- Ensure
-
Permission errors
- Fix storage permissions:
chmod -R 755 storage bootstrap/cache
- Fix storage permissions:
-
Cache issues
- Clear Laravel cache:
php artisan cache:clear
- Clear Laravel cache:
This project is open-sourced software licensed under the MIT license.