Code Redundancy Analysis Report

📄 General
← Back to Documentation
# Code Redundancy Analysis Report ## Executive Summary This document identifies duplicated functionality across the Zapazime codebase and provides recommendations for refactoring to improve maintainability and reduce code duplication. --- ## 1. Venue Data Formatting Duplication ### Severity: HIGH ### Impact: Multiple controllers with identical venue response formatting ### Affected Controllers: - `VenueApiController` (5 methods) - `CompanyAdminApiController` (6 methods) - `LocationServicesController` (2 methods) - `UserController` (3 methods) - `AIAssistantController` (2 methods) - `WebController` (2 methods) ### Duplication Pattern: All controllers repeatedly map venue data with similar structures: ```php // Repeated across 20+ locations $data = $venues->map(function ($venue) { return [ 'id' => $venue->id, 'name' => $venue->name, 'description' => $venue->description, 'address' => $venue->address, 'city' => $venue->city, 'country' => $venue->country, 'latitude' => $venue->latitude, 'longitude' => $venue->longitude, 'phone' => $venue->phone, 'email' => $venue->email, 'capacity' => $venue->capacity, 'booking_type' => $venue->booking_type, 'type' => $venue->type, 'image_url' => $venue->image_url, 'gallery_images' => $venue->gallery_images, 'lowest_price' => $venue->getLowestPrice(), 'average_rating' => $venue->reviews()->avg('rating') ?? 0, 'total_reviews' => $venue->reviews()->count(), // ... additional fields ]; }); ``` ### Recommendation: Create a `VenueResource` class using Laravel's API Resources: ```php // app/Http/Resources/VenueResource.php class VenueResource extends JsonResource { public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'description' => $this->description, 'address' => $this->address, 'city' => $this->city, 'country' => $this->country, 'latitude' => $this->latitude, 'longitude' => $this->longitude, 'phone' => $this->phone, 'email' => $this->email, 'capacity' => $this->capacity, 'booking_type' => $this->booking_type, 'type' => $this->type, 'image_url' => $this->image_url, 'gallery_images' => $this->gallery_images, 'lowest_price' => $this->getLowestPrice(), 'average_rating' => $this->reviews()->avg('rating') ?? 0, 'total_reviews' => $this->reviews()->count(), 'location' => LocationResource::make($this->whenLoaded('location')), 'place' => PlaceResource::make($this->whenLoaded('place')), ]; } } // Create specialized variants class VenueSimpleResource extends JsonResource { public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'city' => $this->city, 'country' => $this->country, 'image_url' => $this->image_url, 'lowest_price' => $this->getLowestPrice(), 'average_rating' => $this->reviews()->avg('rating') ?? 0, ]; } } ``` ### Benefits: - **Eliminate ~500+ lines of duplicated code** - **Single source of truth** for venue data formatting - **Consistent responses** across all endpoints - **Easier maintenance** - change in one place affects all - **Better testing** - test resources independently --- ## 2. Image URL Construction Inconsistency ### Severity: MEDIUM ### Impact: Inconsistent image URL handling across controllers ### Current Approaches: 1. **Using accessor** (Preferred): `$venue->image_url` 2. **Manual construction**: `asset('storage/' . $venue->image)` 3. **Hardcoded fallbacks**: `'/images/venue-placeholder.jpg'` 4. **Gallery fallback**: Complex nested checks ### Affected Controllers: - `AIAssistantController` - Uses manual construction - `WebController` - Uses hardcoded fallbacks and gallery fallback - `LocationServicesController` - Uses both manual and accessor - `VenueApiController` - Uses accessor (correct) - `CompanyAdminApiController` - Uses accessor (correct) ### Recommendation: Standardize all image URL construction to use the model accessor: ```php // In all controllers, replace: $imageUrl = $venue->image ? asset('storage/' . $venue->image) : null; // With: $imageUrl = $venue->image_url; ``` The `Venue::getImageUrlAttribute()` accessor already handles: - Direct image field - Gallery fallback - Null handling ### Benefits: - **Consistent behavior** across all endpoints - **Centralized logic** in the model - **Easier to modify** image storage strategy in future - **Reduces code complexity** --- ## 3. Booking Type Filtering Duplication ### Severity: MEDIUM ### Impact: Similar filtering logic in multiple locations ### Current Implementation: - `WebController::applyFlexibleBookingTypeFilter()` - 60+ lines - Similar logic repeated in `VenueApiController::popularDestinations()` - Similar logic repeated in `VenueApiController::recommendedVenues()` - Similar logic in `Location::getVenueCountByType()` - 50+ lines ### Duplication Pattern: ```php // Repeated in 4+ locations switch ($bookingType) { case 'spots': $query->where(function($q) { $q->where('booking_type', 'spots') ->orWhereNull('booking_type'); }); break; case 'rentals': $query->where(function($q) { $q->where('booking_type', 'rentals') ->orWhereNull('booking_type'); }); break; // ... repeated for services } ``` ### Recommendation: Create a trait or service for booking type filtering: ```php // app/Traits/BookingTypeFilter.php trait BookingTypeFilter { protected function applyBookingTypeFilter($query, string $bookingType) { $hasActiveCategories = \App\Models\Category::where('booking_type', $bookingType) ->where('is_active', true) ->exists(); if (!$hasActiveCategories) { return $query; } return $query->where(function($q) use ($bookingType) { $q->where('booking_type', $bookingType) ->orWhereNull('booking_type'); }); } } // Or use a scope in Venue model // app/Models/Venue.php public function scopeWithBookingType($query, string $bookingType) { $hasActiveCategories = Category::where('booking_type', $bookingType) ->where('is_active', true) ->exists(); if (!$hasActiveCategories) { return $query; } return $query->where(function($q) use ($bookingType) { $q->where('booking_type', $bookingType) ->orWhereNull('booking_type'); }); } ``` ### Benefits: - **Single implementation** of filtering logic - **Easier to test** in isolation - **Consistent behavior** across application - **Reduced code by ~150 lines** --- ## 4. Venue-Related Data Mapping Duplication ### Severity: MEDIUM ### Impact: Similar mapping logic for venue objects, spots, services ### Affected Controllers: - `VenueApiController` - venue objects, spots, services mapping - `BookingManagementController` - similar mapping for booking data - `CompanyAdminApiController` - venue objects mapping ### Duplication Pattern: ```php // Repeated venue object mapping 'venue_objects' => $venue->venueObjects->map(function ($object) { return [ 'id' => $object->id, 'name' => $object->name, 'description' => $object->description, 'capacity' => $object->capacity, 'price' => $object->price, 'currency' => $object->currency, 'images' => $object->images ?? [], ]; }), ``` ### Recommendation: Create API Resources for related models: ```php // app/Http/Resources/VenueObjectResource.php class VenueObjectResource extends JsonResource { public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'description' => $this->description, 'capacity' => $this->capacity, 'price' => $this->price, 'currency' => $this->currency, 'booking_time_unit' => $this->booking_time_unit, 'images' => $this->images ?? [], 'venue' => VenueSimpleResource::make($this->whenLoaded('venue')), ]; } } // app/Http/Resources/VenueSpotResource.php class VenueSpotResource extends JsonResource { public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'capacity' => $this->capacity, 'price' => $this->price, 'currency' => $this->currency, 'venue' => VenueSimpleResource::make($this->whenLoaded('venue')), ]; } } ``` ### Benefits: - **Consistent formatting** across all endpoints - **Reduced duplication** by ~100 lines - **Easier to extend** with new fields - **Better maintainability** --- ## 5. Location Data Formatting Duplication ### Severity: LOW ### Impact: Similar location mapping in multiple places ### Affected Controllers: - `VenueApiController` - location mapping in venue responses - `LocationServicesController` - location mapping - `Location model` - similar logic in methods ### Recommendation: Create a `LocationResource`: ```php // app/Http/Resources/LocationResource.php class LocationResource extends JsonResource { public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'description' => $this->description, 'city' => $this->city?->name, 'country' => $this->country?->name, 'latitude' => $this->latitude, 'longitude' => $this->longitude, 'image_url' => $this->image_url, ]; } } ``` --- ## 6. Category Filtering Duplication ### Severity: MEDIUM ### Impact: Category filtering logic repeated in Location model and WebController ### Affected Files: - `Location.php` - `applySpotCategoryFilter`, `applyRentalCategoryFilter`, `applyServiceCategoryFilter` (100+ lines) - `WebController.php` - Similar category filtering methods (150+ lines) ### Recommendation: Move category filtering to a dedicated service or use model scopes: ```php // app/Services/CategoryFilterService.php class CategoryFilterService { public function applySpotFilter($query, string $category) { $filters = [ 'beach' => ['%beach%', '%umbrella%', '%sunbed%'], 'parking' => ['%parking%', '%car%'], 'camping' => ['%camping%', '%tent%'], // ... ]; $patterns = $filters[$category] ?? ["%{$category}%"]; return $query->where(function($q) use ($patterns) { foreach ($patterns as $pattern) { $q->orWhere('category', 'like', $pattern) ->orWhere('description', 'like', $pattern); } }); } } ``` ### Benefits: - **Single implementation** of category filtering - **Easier to add new categories** - **Reduced code by ~250 lines** - **Better testability** --- ## Priority Recommendations ### Immediate (High Priority): 1. **Create VenueResource classes** - Eliminates the most duplication 2. **Standardize image URL usage** - Quick win, high impact 3. **Create BookingTypeFilter trait/scope** - Medium effort, good ROI ### Short-term (Medium Priority): 4. **Create VenueObjectResource and VenueSpotResource** - Consistency improvement 5. **Move category filtering to service** - Reduces complexity ### Long-term (Low Priority): 6. **Create LocationResource** - Minor improvement 7. **Review and consolidate similar methods** - Ongoing maintenance --- ## Estimated Impact ### Code Reduction: - **Venue formatting**: ~500 lines eliminated - **Image handling**: ~50 lines eliminated - **Booking type filtering**: ~150 lines eliminated - **Category filtering**: ~250 lines eliminated - **Related model formatting**: ~100 lines eliminated - **Total**: ~1,050+ lines of duplicated code eliminated ### Maintainability Improvement: - **Single source of truth** for data formatting - **Easier to add new fields** - change in one place - **Consistent API responses** across all endpoints - **Better testability** with isolated resources - **Reduced bug surface** - fewer places to make mistakes --- ## Implementation Plan ### Phase 1: Core Resources (Week 1) 1. Create `VenueResource`, `VenueSimpleResource` 2. Create `LocationResource` 3. Update VenueApiController to use resources 4. Update CompanyAdminApiController to use resources ### Phase 2: Related Resources (Week 2) 5. Create `VenueObjectResource`, `VenueSpotResource` 6. Create `VenueServiceResource`, `VenuePackageResource` 7. Update all controllers to use resources ### Phase 3: Filtering Logic (Week 3) 8. Create `BookingTypeFilter` trait/scope 9. Create `CategoryFilterService` 10. Update all controllers to use centralized filtering ### Phase 4: Cleanup (Week 4) 11. Standardize image URL usage 12. Remove duplicated methods 13. Update tests 14. Update documentation --- ## Conclusion The codebase contains significant duplication, particularly in venue data formatting. By implementing Laravel API Resources and centralizing filtering logic, we can eliminate over 1,000 lines of duplicated code while improving maintainability, consistency, and testability. The proposed refactoring follows Laravel best practices and will make the codebase more professional and easier to maintain in the long term.