Weave Code
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

Fan Courier Bundle Laravel Package

answear/fan-courier-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require answear/fan-courier-bundle
    

    The bundle auto-registers in config/bundles.php.

  2. Configuration: Add credentials to config/packages/answear_fancourier.yaml:

    answear_fan_courier:
        username: "your_api_username"
        password: "your_api_password"
        apiUrl: "https://api.fancourier.ro/api/v2/"  # Verify with API docs
        logger: "app.logger.fancourier"  # Optional (default: null)
    
  3. First Use Case: Fetch pickup points in a service:

    use Answear\FanCourierBundle\Service\PickupPointService;
    
    $pickupPoints = $this->pickupPointService->getAll();
    // Returns array of `PickupPointDTO` objects
    

Key Files to Review

  • Service: Answear\FanCourierBundle\Service\PickupPointService (core functionality)
  • DTOs: Answear\FanCourierBundle\DTO\PickupPointDTO and AddressDTO (data structure)
  • API Docs: FanCourier API v2.0 (for endpoint specifics)

Implementation Patterns

Core Workflows

  1. Fetching Pickup Points:

    // Basic usage
    $points = $pickupPointService->getAll();
    
    // Filter by city (if API supports it)
    $points = $pickupPointService->getFiltered(['city' => 'Bucharest']);
    
  2. Integration with Laravel:

    • Service Container: Bind the service in config/services.php:
      'services' => [
          'fancourier.pickup' => Answear\FanCourierBundle\Service\PickupPointService::class,
      ],
      
    • Dependency Injection:
      public function __construct(
          private PickupPointService $pickupPointService
      ) {}
      
  3. Data Transformation: Convert PickupPointDTO to Eloquent models:

    $pickupPoint = PickupPoint::create([
        'id' => $dto->getId(),
        'name' => $dto->getName(),
        'address' => json_encode($dto->getAddress()->toArray()),
    ]);
    
  4. Caching Responses: Cache API responses for 1 hour (e.g., using Laravel Cache):

    $cacheKey = 'fancourier.pickup_points';
    $points = Cache::remember($cacheKey, now()->addHours(1), function () {
        return $this->pickupPointService->getAll();
    });
    
  5. Error Handling: Wrap API calls in try-catch:

    try {
        $points = $pickupPointService->getAll();
    } catch (\Answear\FanCourierBundle\Exception\ApiException $e) {
        Log::error('FanCourier API Error: ' . $e->getMessage());
        throw new \RuntimeException('Failed to fetch pickup points.', 0, $e);
    }
    

Advanced Patterns

  • Event-Driven Updates: Trigger events when pickup points are fetched/updated:

    event(new PickupPointsFetched($points));
    
  • Queue Background Jobs: Offload API calls to queues:

    dispatch(new FetchPickupPointsJob($pickupPointService));
    
  • Custom API Endpoints: Extend the service to support undocumented endpoints:

    class CustomPickupPointService extends PickupPointService {
        public function getByPostalCode(string $postalCode): array {
            return $this->callApi('custom/endpoint', ['postalCode' => $postalCode]);
        }
    }
    

Gotchas and Tips

Common Pitfalls

  1. API URL Mismatch:

    • Issue: apiUrl in config must match the exact base URL from the API docs (e.g., https://api.fancourier.ro/api/v2/).
    • Fix: Verify with the API documentation.
  2. Authentication Failures:

    • Issue: Invalid username/password throws a silent ApiException.
    • Debug: Enable logging (logger config) and check Symfony logs for 401 Unauthorized errors.
    • Fix: Test credentials via Postman/cURL first:
      curl -u "username:password" "https://api.fancourier.ro/api/v2/pickup-points"
      
  3. DTO Structure Changes:

    • Issue: PickupPointDTO structure changed in v2.0.0 (e.g., address moved to a nested AddressDTO).
    • Fix: Update your code to access nested properties:
      // Old (v1.x)
      $city = $dto->getCity();
      
      // New (v2.x)
      $city = $dto->getAddress()->getCity();
      
  4. Rate Limiting:

    • Issue: FanCourier may throttle requests. Default Guzzle timeout (5s) might be too short.
    • Fix: Increase timeout in config (if supported) or implement retries:
      $this->pickupPointService->setClientConfig(['timeout' => 30]);
      
  5. Logger Configuration:

    • Issue: Custom logger must implement Psr\Log\LoggerInterface.
    • Fix: Use Laravel’s logger:
      logger: "monolog.logger.fancourier"
      
      Or create a dedicated channel in config/logging.php.

Debugging Tips

  • Enable Debug Mode: Set APP_DEBUG=true in .env to see raw API responses in logs.

  • Inspect HTTP Requests: Use Guzzle middleware to log requests:

    $stack = HandlerStack::create();
    $stack->push(Middleware::tap(function (RequestInterface $request) {
        Log::debug('FanCourier Request:', ['url' => (string) $request->getUri()]);
    }));
    $this->pickupPointService->setClient($client->withHandler($stack));
    
  • Validate API Responses: FanCourier may return non-standard JSON. Use json_last_error() to debug:

    $response = $this->pickupPointService->callApi('endpoint');
    $data = json_decode($response, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new \RuntimeException('Invalid JSON: ' . json_last_error_msg());
    }
    

Extension Points

  1. Custom HTTP Client: Replace the default Guzzle client:

    $client = new \GuzzleHttp\Client(['timeout' => 10]);
    $this->pickupPointService->setClient($client);
    
  2. Add New Endpoints: Extend PickupPointService to support undocumented APIs:

    class ExtendedPickupPointService extends PickupPointService {
        public function getByCoordinates(float $lat, float $lng): array {
            return $this->callApi('custom/coordinates', [
                'latitude' => $lat,
                'longitude' => $lng,
            ]);
        }
    }
    
  3. Override DTOs: Create custom DTOs to map API responses to your domain:

    class CustomPickupPointDTO {
        public function __construct(private array $data) {}
    
        public function getFormattedAddress(): string {
            return implode(', ', [
                $this->data['address']['city'],
                $this->data['address']['street'],
            ]);
        }
    }
    
  4. Add Rate Limiting: Implement a decorator to enforce rate limits:

    class RateLimitedPickupPointService {
        public function __construct(private PickupPointService $service) {}
    
        public function getAll(): array {
            if ($this->isRateLimited()) {
                sleep(60); // Wait 1 minute
            }
            return $this->service->getAll();
        }
    }
    

Configuration Quirks

  • apiUrl Trailing Slash: Ensure the URL ends with / (e.g., api/v2/ not api/v2). FanCourier’s API may reject malformed URLs.

  • Logger Priority: The logger must be configured before the bundle initializes. Use kernel.request event to set it dynamically if needed:

    public function onKernelRequest(RequestEvent $event) {
        $this->container->get('answear_fan_courier.service.pickup_point')
            ->
    
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.
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager