Install the Package
composer require answear/boxnow-bundle
Note: This package is Symfony-specific. For Laravel, you’ll need to manually adapt the logic (see Implementation Patterns).
Configure BoxNow Credentials
Create a Laravel-compatible config file at config/boxnow.php:
return [
'client_id' => env('BOXNOW_CLIENT_ID'),
'client_secret' => env('BOXNOW_CLIENT_SECRET'),
'api_url' => env('BOXNOW_API_URL', 'https://locationapi-stage.boxnow.gr'),
'logger' => env('BOXNOW_LOGGER', null), // Optional: e.g., 'single', 'monolog'
];
Set Up Environment Variables
Add to .env:
BOXNOW_CLIENT_ID=your_client_id
BOXNOW_CLIENT_SECRET=your_client_secret
Create a Service Provider
Register the BoxNow services in app/Providers/BoxNowServiceProvider.php:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Answear\BoxNowBundle\Service\AuthorizationService;
use Answear\BoxNowBundle\Service\PickupPointService;
class BoxNowServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(AuthorizationService::class, function ($app) {
return new AuthorizationService(
config('boxnow.client_id'),
config('boxnow.client_secret'),
config('boxnow.api_url'),
$app->make('logger') ?? null
);
});
$this->app->singleton(PickupPointService::class, function ($app) {
return new PickupPointService(
$app->make('http.client'),
config('boxnow.api_url')
);
});
}
}
Register the provider in config/app.php under providers.
First Use Case: Fetch Pickup Points by Region
use Answear\BoxNowBundle\Enum\RegionEnum;
use Answear\BoxNowBundle\Service\PickupPointService;
public function getCyprusPickupPoints(PickupPointService $pickupPoints)
{
$points = $pickupPoints->getAllByRegion(RegionEnum::Cyprus);
return response()->json($points);
}
Note: RegionEnum must be adapted to Laravel’s enum or constants.
AuthorizationService with auto-injected dependencies.public function authorize(AuthorizationService $authService)
{
$auth = $authService->authorize();
$token = $auth->getAccessToken();
// Store token for future requests (e.g., in cache or session)
cache()->put('boxnow_token', $token, now()->addSeconds($auth->getExpiresIn()));
return $token;
}
public function getPickupPointsByToken(PickupPointService $service)
{
$token = cache()->get('boxnow_token');
$points = $service->getAll($token);
return $points;
}
public function getPickupPointsByRegion(PickupPointService $service)
{
$points = $service->getAllByRegion(RegionEnum::Cyprus);
return $points;
}
try-catch blocks to handle BoxNowApiException (adapted from Symfony’s ProblemDetails):
try {
$points = $service->getAll($token);
} catch (\Answear\BoxNowBundle\Exception\BoxNowApiException $e) {
Log::error('BoxNow API Error: ' . $e->getMessage());
event(new BoxNowApiFailed($e));
return response()->json(['error' => 'Failed to fetch pickup points'], 500);
}
public function getCachedPickupPoints(PickupPointService $service, RegionEnum $region)
{
$cacheKey = "boxnow_pickup_points_{$region->value}";
return cache()->remember($cacheKey, now()->addHours(1), function () use ($service, $region) {
return $service->getAllByRegion($region);
});
}
HTTP Client Configuration
Configure Laravel’s HttpClient to match the bundle’s Guzzle settings (e.g., timeouts):
$client = Http::withOptions([
'timeout' => 30, // seconds
'connect_timeout' => 10,
]);
Region Enum Adaptation
Replace Symfony’s RegionEnum with Laravel’s enum:
namespace App\Enums;
enum Region: string
{
case Greece = 'el-GR';
case Cyprus = 'cy-CY';
case Croatia = 'hr-HR';
case Bulgaria = 'bg-BG';
}
Logging
Use Laravel’s Log facade to replace Symfony’s Psr\Log\LoggerInterface:
$logger = Log::channel('single'); // or 'monolog'
Testing
Mock the PickupPointService and AuthorizationService in Laravel tests:
$mockService = Mockery::mock(PickupPointService::class);
$mockService->shouldReceive('getAllByRegion')
->with(Region::Cyprus)
->andReturn([new PickupPointDTO()]);
$this->app->instance(PickupPointService::class, $mockService);
Event-Driven Extensions Dispatch events for critical actions (e.g., token refresh, API failures):
class BoxNowTokenRefreshed implements ShouldBroadcast
{
public function __construct(public string $newToken) {}
}
// In AuthorizationService:
event(new BoxNowTokenRefreshed($newToken));
Symfony-Specific Assumptions
Serializer and PropertyInfo for DTO handling.collect() or json_decode():
// Symfony (original):
$serializer = $this->serializer->serialize($data, 'json');
// Laravel adaptation:
$data = json_decode($response->body(), true);
Region Enum Mismatch
RegionEnum uses Symfony’s Enum trait, which isn’t native to Laravel.enum or a simple class:
class Region
{
const GREECE = 'el-GR';
const CYPRUS = 'cy-CY';
}
Authentication Token Management
Auth session driver:
$token = cache()->remember('boxnow_token', now()->addMinutes(50), function () {
return $authService->authorize()->getAccessToken();
});
Guzzle vs. Laravel HttpClient
HttpClient.HttpClient into services:
public function __construct(private HttpClient $http) {}
Logger Dependency
Psr\Log\LoggerInterface, but Laravel’s Log facade isn’t a direct drop-in.class LaravelLogger implements LoggerInterface
{
public function __construct(private \Illuminate\Log\Logger $logger) {}
public function error(string $message, array $context = []): void
{
$this->logger->error($message, $context);
}
// Implement other Psr\Log methods...
}
Enable API Logging Add debug logging to track API calls:
$this->logger->debug('BoxNow API Request', [
'url' => $url,
'data' => $data,
'headers' => $headers,
]);
Validate API Responses
Use Laravel’s Http facade to inspect raw responses:
$response = Http::withHeaders(['Authorization' => '
How can I help you explore Laravel packages today?