Installation:
composer require ner0tic/foursquare-bundle
Add the bundle to config/bundles.php:
Ner0tic\FoursquareBundle\Ner0ticFoursquareBundle::class => ['all' => true],
Configuration: Publish the default config:
php bin/console ner0tic:foursquare:install
Update config/packages/ner0tic_foursquare.yaml with your Foursquare API credentials (client ID, secret, and OAuth redirect URI).
First Use Case: Fetch a venue by ID in a controller:
use Ner0tic\FoursquareBundle\Service\VenueService;
class VenueController extends AbstractController
{
public function show(VenueService $venueService, string $venueId)
{
$venue = $venueService->getVenue($venueId);
return $this->json($venue);
}
}
OAuth Integration:
ConnectController (auto-generated via ner0tic:foursquare:install) for user authentication.return $this->redirect($this->container->get('ner0tic_foursquare.oauth')->getAuthorizationUrl());
connectCallback action to exchange code for an access token.Service Layer Abstraction:
UserService, VenueService) into controllers or services:
public function __construct(
private UserService $userService,
private CheckinService $checkinService
) {}
$checkins = $checkinService->getCheckinsForVenue($venueId, $limit = 10);
Entity Mapping:
User, Venue). Extend or override these in your project:
# config/packages/ner0tic_foursquare.yaml
ner0tic_foursquare:
entities:
user: App\Entity\CustomUser
venue: App\Entity\CustomVenue
Pagination:
getPaginatedResults() methods (e.g., getVenues()) to handle large datasets:
$venues = $venueService->getVenues(['near' => 'San Francisco'], 20);
Event Handling:
foursquare.user.connected) in your EventSubscriber:
public static function getSubscribedEvents()
{
return [
'foursquare.user.connected' => 'onUserConnected',
];
}
Caching:
config/packages/ner0tic_foursquare.yaml:
ner0tic_foursquare:
cache_enabled: true
cache_lifetime: 3600 # 1 hour
Error Handling:
FoursquareApiException:
try {
$venue = $venueService->getVenue($venueId);
} catch (FoursquareApiException $e) {
$this->addFlash('error', $e->getMessage());
return $this->redirectToRoute('home');
}
Testing:
FoursquareClientMock for unit tests:
$mockClient = $this->createMock(FoursquareClient::class);
$mockClient->method('get')->willReturn(['response' => 'data']);
$this->container->set('ner0tic_foursquare.client', $mockClient);
Custom Endpoints:
FoursquareClient to add custom API calls:
class CustomFoursquareClient extends FoursquareClient
{
public function getCustomData($params)
{
return $this->get('/custom/endpoint', $params);
}
}
Register it as a service:
services:
App\Service\CustomFoursquareClient:
decorates: ner0tic_foursquare.client
arguments: ['@App\Service\CustomFoursquareClient.inner']
Deprecated Bundle:
ddnet/foursquare-bundle is deprecated. Use ner0tic/foursquare-bundle (linked in the README). Ensure you’re not mixing dependencies.OAuth Redirect URI:
http://localhost:8000/connect/callback and update for production.Rate Limiting:
try {
$response = $client->get('/venues/search', $params);
} catch (RateLimitExceededException $e) {
sleep($e->getRetryAfter());
retry();
}
Entity Overrides:
CustomUser), ensure all required fields from Foursquare’s response are mapped. Use Serializer annotations or Hydrator for complex cases.Token Expiry:
ConnectController or use a library like league/oauth2-client for advanced handling.API Logs:
config/packages/ner0tic_foursquare.yaml:
ner0tic_foursquare:
debug: true
var/log/dev.log.Common Errors:
Invalid OAuth token: Token expired or revoked. Redirect users to re-authenticate.Endpoint not found: Verify the endpoint exists in Foursquare’s API docs.Missing required parameter: Check $params for required fields (e.g., v=20230601 for versioning).Symfony Profiler:
Profiler > HTTP > Foursquare.Custom Services:
class VenueDashboardService
{
public function __construct(
private VenueService $venueService,
private CheckinService $checkinService
) {}
public function getDashboardData($venueId)
{
return [
'venue' => $this->venueService->getVenue($venueId),
'checkins' => $this->checkinService->getRecentCheckins($venueId),
];
}
}
Webhook Integration:
WebhookController:
public function handleWebhook(Request $request)
{
$payload = json_decode($request->getContent(), true);
$this->dispatchEvent('foursquare.webhook.received', $payload);
}
Geocoding:
GeocoderBundle to convert addresses to Foursquare venues:
$geocoder = $this->container->get('geocoder');
$coordinates = $geocoder->geocode('123 Main St, San Francisco');
$venues = $venueService->getVenues(['near' => $coordinates->getLatitude().','.$coordinates->getLongitude()]);
Background Jobs:
$this->messageBus->dispatch(new SyncUserCheckinsMessage($userId));
How can I help you explore Laravel packages today?