Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ti Ext Local Laravel Package

tastyigniter/ti-ext-local

TastyIgniter Local extension adds location-based features to your application: manage multiple locations, define delivery areas and zones, set opening hours, enable customer reviews, add custom location fields, and let customers search for the nearest location to their address.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require tastyigniter/ti-ext-local
    

    Publish the extension’s assets and configurations:

    php artisan vendor:publish --provider="TastyIgniter\Local\LocalServiceProvider"
    
  2. First Use Case:

    • Find Nearest Location: Use the Location model’s built-in query scopes:
      use TastyIgniter\Local\Models\Location;
      
      $nearestLocation = Location::nearBy($latitude, $longitude, $distanceInKm)
          ->where('status', 'active')
          ->first();
      
    • Delivery Area Check: Validate if a customer’s address falls within a location’s delivery zone:
      $location = Location::find($locationId);
      $isInDeliveryArea = $location->isInDeliveryArea($customerLatitude, $customerLongitude);
      
    • Timeslot Availability (reliable as of v4.3.1):
      $slots = $location->getTimeslots(); // now correct even with weekly closing days
      
  3. Where to Look First:

    • Documentation: TastyIgniter Local Docs for setup and API references.
    • Models: app/Models/TastyIgniter/Local/Location.php for core functionality (e.g., nearBy(), isInDeliveryArea(), timeslot resolution).
    • Migrations: Check database/migrations/ for schema changes (e.g., delivery area boundaries, opening hours, schedule periods).

Implementation Patterns

Usage Patterns

  1. Location-Based Queries:

    • Nearby Locations: Use the nearBy() scope with optional filters:
      Location::nearBy($lat, $lng, 10) // 10km radius
          ->with(['reviews', 'deliveryAreas']) // Eager load relationships
          ->get();
      
    • Delivery Area Validation: Integrate with checkout logic:
      $cart = Cart::with('items')->find($cartId);
      foreach ($cart->items as $item) {
          $location = $item->location;
          if (!$location->isInDeliveryArea($customerLat, $customerLng)) {
              throw new \Exception("Item not available for delivery in this area.");
          }
      }
      
  2. Opening Hours & Schedule Logic:

    • Check if a location is open during a specific time:
      $location = Location::find($id);
      $isOpen = $location->isOpenNow(); // Uses Carbon for time comparison
      
    • Customize business hours per day:
      $location->openingHours()->update([
          'monday_open' => '09:00',
          'monday_close' => '18:00',
          // ... other days
      ]);
      
    • Timeslot resolution (the core of the v4.3.1 fix): the schedule window search now uses a self-contained search budget independent of the future-order day allowance. This means you can pull available slots without needing to tweak the future_order_days setting as a workaround:
      // Prefer this over manual date math — the search budget is now correct
      $slots = $location->getTimeslots(\Illuminate\Support\Carbon::now());
      
  3. Geocoder Integration:

    • Configure geocoding drivers in .env:
      LOCAL_GEOCODE_DRIVER=google // or 'osm'
      GOOGLE_MAPS_API_KEY=your_key_here
      
    • Reverse geocode an address:
      $geocoder = app(\TastyIgniter\Local\Services\Geocoder::class);
      $result = $geocoder->geocode('1600 Amphitheatre Parkway, Mountain View');
      
  4. Custom Location Fields:

    • Extend the Location model with custom attributes:
      // In a service provider or model observer
      Location::created(function ($location) {
          $location->custom_fields = json_encode([
              'has_wifi' => true,
              'parking_available' => false,
          ]);
          $location->save();
      });
      

Workflows

  1. Admin Workflow:

    • Use the SettingsEditor to configure location-specific settings (e.g., delivery fees, opening hours) via the TastyIgniter admin panel.
    • Define delivery areas using the LocationArea model:
      $location->deliveryAreas()->create([
          'name' => 'Downtown Zone',
          'radius' => 5, // km
          'fee' => 2.99,
          'color' => '#FF0000', // For UI visualization
      ]);
      
  2. Frontend Integration:

    • Nearby Locations Map: Use Laravel Blade to render a map with markers:
      @foreach($nearbyLocations as $location)
          <div data-lat="{{ $location->latitude }}" data-lng="{{ $location->longitude }}">
              {{ $location->name }}
          </div>
      @endforeach
      
    • JavaScript: Use Leaflet.js or Google Maps API to visualize locations:
      const locations = @json($nearbyLocations);
      locations.forEach(loc => {
          L.marker([loc.latitude, loc.longitude]).addTo(map)
              .bindPopup(`<b>${loc.name}</b><br>Distance: ${loc.distance} km`);
      });
      
  3. Performance Optimization:

    • Eager Loading: Avoid N+1 queries for related data:
      Location::with(['reviews', 'deliveryAreas'])->nearBy($lat, $lng, 20)->get();
      
    • Database Indexes: Leverage the package’s added indexes (e.g., latitude, longitude) for faster geospatial queries.

Integration Tips

  1. Event Listeners:

    • Listen for location updates to trigger notifications or sync external services:
      Location::updated(function ($location) {
          if ($location->isDirty('opening_hours')) {
              event(new \TastyIgniter\Local\Events\OpeningHoursUpdated($location));
          }
      });
      
  2. API Endpoints:

    • Create a dedicated route for location searches:
      Route::get('/api/locations/nearby', function (Request $request) {
          $lat = $request->query('lat');
          $lng = $request->query('lng');
          $distance = $request->query('distance', 10);
      
          return Location::nearBy($lat, $lng, $distance)->get();
      });
      
  3. Testing:

    • Mock geocoding responses in tests:
      $this->partialMock(\TastyIgniter\Local\Services\Geocoder::class, function ($mock) {
          $mock->shouldReceive('geocode')
              ->once()
              ->andReturn(['lat' => 37.422, 'lng' => -122.084]);
      });
      
    • Add a regression test around the v4.3.1 timeslot scenario (weekly closing day inside the two-day lookback window, future orders disabled):
      $this->travelTo(now()->setTime(23, 59));
      $slots = $location->getTimeslots();
      $this->assertNotEmpty($slots);
      
  4. Caching:

    • Cache frequent geocoding results or nearby location queries:
      $nearby = Cache::remember("nearby_locations_{$lat}_{$lng}", now()->addHours(1), function () use ($lat, $lng) {
          return Location::nearBy($lat, $lng, 10)->get();
      });
      

Gotchas and Tips

Pitfalls

  1. Namespace References:

    • Issue: Since v4.1.3, Location model references use short class names. If your code explicitly uses fully qualified namespaces, it may break.
    • Fix: Update references to use the canonical namespace:
      // Before (may break)
      $location = new \App\Models\Location;
      
      // After (recommended)
      $location = new \TastyIgniter\Local\Models\Location;
      
  2. Timeslot Lookback Regression (fixed in v4.3.1):

    • Issue: Prior to v4.3.1, getTimeslots() could incorrectly return an empty window when a location was actually open — most visibly when future orders were disabled and a weekly closing day fell inside the two-day lookback the schedule period search used. The bug surfaced around midnight and self-healed the next day, making it hard to reproduce.
    • Fix: Upgrade to v4.3.1+. The window search now has its own search budget decoupled from future_order_days. You can delete any padding workarounds you added around closing days or future_order_days.
  3. Type-Safety Changes on Location Methods:

    • Issue: v4.3.1 tightened type-safety on Location methods. Passing loosely-typed values (string carbon timestamps, nulls, ints where a CarbonInterface is expected) can now trigger TypeError where it previously coerced silently.
    • Fix: Cast inputs explicitly before calling:
      $location->getTimeslots(\Illuminate\Support\Carbon::parse($when));
      
      Run your test suite against the new version to surface any hidden coercions.
  4. Geocoder Driver Configuration:

    • Issue: If LOCAL_GEOCODE_DRIVER is not set in .env, the package will throw an exception.
    • Fix: Add to .env:
      LOCAL_GEOCODE_DRIVER=google
      GOOGLE_MAPS_API_KEY=your_api_key_here
      
  5. Delivery Area Validation:

    • Issue: isInDeliveryArea() may return false positives if the geocoder returns imprecise coordinates.
    • Fix: Use a buffer distance or log discrepancies for review:
      $isInArea = $location->isInDeliveryArea($lat, $lng, 0.1); // Add 100m buffer
      
  6. Opening Hours Edge Cases:

    • Issue: isOpenNow() assumes 24-hour time format and may fail if opening_hours is malformed (e.g., missing values for certain days). The v4.3.1 fix addresses lookback correctness, not malformed data — validation is still your responsibility.
    • Fix: Validate opening hours data before use:
      if (!$location->openingHours->isFilled()) {
          throw new \InvalidArgumentException("Opening hours not fully configured.");
      }
      
  7. Custom Fields Serialization:

    • Issue: Custom fields stored as JSON may cause serialization errors if the data structure changes unexpectedly.
    • Fix: Use a dedicated model or cast the attribute:
      protected $casts = [
          'custom_fields' => 'array',
      ];
      

Debugging

  1. Geocoding Failures:

    • Enable debug mode for the geocoder and inspect the raw HTTP response:
      config(['services.google.maps_key' => env('GOOGLE_MAPS_API_KEY')]);
      Log::debug('Geocode response', ['payload' => $geocoder->geocode($address)]);
      
  2. Timeslot Debugging:

    • If slots still look empty after upgrading, log the inputs the schedule window sees:
      $when = now();
      Log::info('slot-check', [
          'when'        => $when->toIso8601String(),
          'is_open'     => $location->isOpenNow(),
          'future_days' => $location->future_order_days ?? null,
          'slots'       => $location->getTimeslots($when),
      ]);
      
    • Reproduce the v4.3.1 scenario explicitly: future orders off + weekly close day inside two-day lookback + now() just before midnight.
  3. Query Debugging:

    • Inspect nearBy() SQL to confirm indexes are used:
      DB::listen(fn ($q) => dump($q->sql, $q->bindings));
      Location::nearBy($lat, $lng, 10)->get();
      
    • Watch for full table scans — if the latitude/longitude indexes aren’t used, check your DB collation and that the migration from the correct package version has run.
  4. Upgrading from pre-v4.3.1:

    • After composer update, run php artisan migrate (no new migrations in v4.3.1, but the type-safety changes may surface through dependent code) and run your test suite. Remove any workarounds that padded future_order_days or disabled weekly closes to get slots to appear — they’re no longer needed and can mask genuine configuration errors.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel