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

Php Foursquare Laravel Package

hownowstephen/php-foursquare

A lightweight PHP client for the Foursquare API, offering simple methods for authentication and accessing endpoints such as venues, users, checkins, and photos. Easily integrate Foursquare data into Laravel or plain PHP applications.

Deep Wiki
Context7

Getting Started

composer require hownowstephen/php-foursquare

If Packagist resolution fails (the project predates modern PSR conventions and its metadata has drifted), add it as a VCS repository and use "autoload": { "classmap": ["vendor/hownowstephen/php-foursquare"] } in composer.json, then composer dump-autoload.

First places to look

  1. FoursquareAPI.php (or the single class file in the repo root) — the entire API surface is there: SetRedirectUrl, GetAuthCode, GetAccessToken, SetAccessToken, Get, Post. Read it once; it's small.
  2. The cURL block inside the request method — that's where timeouts, SSL options and error behavior are (not) handled.
  3. The Foursquare developer console — you need a Client ID, Client Secret, and an exact-match Redirect URI before anything works.

Configuration

Add credentials to config/services.php so they are cacheable and not read from env() at runtime:

// config/services.php
'foursquare' => [
    'client_id'     => env('FOURSQUARE_CLIENT_ID'),
    'client_secret' => env('FOURSQUARE_CLIENT_SECRET'),
    'redirect'      => env('FOURSQUARE_REDIRECT_URI'), // must match console exactly
],

First use case: OAuth handshake → venue search

// app/Services/Foursquare.php
namespace App\Services;

class Foursquare
{
    protected \FoursquareAPI $api;

    public function __construct()
    {
        $this->api = new \FoursquareAPI(
            config('services.foursquare.client_id'),
            config('services.foursquare.client_secret')
        );
        $this->api->SetRedirectUrl(config('services.foursquare.redirect'));
    }

    public function authUrl(): string
    {
        return $this->api->GetAuthCode();
    }

    public function exchange(string $code): string
    {
        return $this->api->GetAccessToken($code); // access token string
    }

    public function searchVenues(string $token, string $near, string $query): array
    {
        $this->api->SetAccessToken($token);

        $raw = $this->api->Get('venues/search', [
            'near'  => $near,
            'query' => $query,
            'limit' => 10,
        ]);

        return json_decode($raw, true)['response']['venues'] ?? [];
    }
}

Bind it as a singleton in a service provider ($this->app->singleton(Foursquare::class)) so you instantiate the cURL-backed client once per request, not per call.

Implementation Patterns

OAuth flow in Laravel

// routes/web.php
Route::get('/connect/foursquare', fn () => redirect(app(Foursquare::class)->authUrl()));

Route::get('/callback/foursquare', function (Request $request, Foursquare $fs) {
    abort_unless($request->filled('code'), 400);

    $token = $fs->exchange($request->query('code'));

    $request->user()->forceFill([
        'foursquare_token' => encrypt($token), // tokens are bearer credentials
    ])->save();

    return redirect('/dashboard');
});

Store the token encrypted in a social_accounts table with a provider column if you support multiple integrations; the token is long-lived and does not need a refresh flow.

Keep the raw client behind your own adapter. The library is a concrete class with PascalCase setters and a mutable token on the instance. In tests you cannot Http::fake() it, and you cannot mock it cleanly. Wrap the five or six endpoints you actually use in App\Services\Foursquare behind an interface, bind a fake in TestCase, and let the third-party class stay at the edge.

Endpoint strings are positional, parameters are associative

$fs->api->Get('users/self/checkins', ['limit' => 20, 'beforeTimestamp' => $ts]);
$fs->api->Post('checkins/add', ['venueId' => $id, 'shout' => 'First!']);

Anything not in the core set (venues/search, venues/VENUE_ID, users/self, checkins/add, checkins/recent) is still reachable through Get/Post — you rarely need the helper methods, and the library adds little beyond URL assembly plus the oauth_token parameter.

Cache aggressively. Venue metadata and category trees change slowly and the API is rate limited per token:

$venues = Cache::remember("fs:venue:{$id}", now()->addHours(12), fn () =>
    $fs->get('venues/'.$id, ['v' => config('services.foursquare.version', '20240101')])
);

Route writes through the queue. Check-in posting and venue likes are non-critical; dispatch a job so a Foursquare timeout never blocks a user request. Include the token in the job's payload or reload the user in handle().

Handle the response envelope yourself. Every v2 response is {"meta":{"code":200,...},"response":{...}}. Decode once in your adapter and translate meta.code !== 200 into a typed exception (FoursquareException) so controllers never see raw JSON.

Pagination is limit/offset (or beforeTimestamp for check-in feeds). Do not rely on the library for this; loop in your adapter and cap at a sane page count.

Gotchas and Tips

  • PHP 8 compatibility is the headline risk. This library targets PHP 5.3-era idioms. Dynamic properties, implicit nullables, create_function, and curly-brace string offsets will emit deprecations or hard errors on 8.1+. Laravel 10/11 requires 8.1+, so budget time for a fork or a shim, or plan the migration below.
  • No exceptions, no retries, no timeouts. The cURL call returns false or an empty body on transport failure, and non-2xx responses still return a body. Check $raw === false || $raw === '' before json_decode, and set CURLOPT_TIMEOUT/CURLOPT_CONNECTTIMEOUT yourself if you fork — otherwise a hung Foursquare endpoint hangs a queue worker.
  • Token state is mutable. SetAccessToken mutates the instance, so a singleton shared across a multi-tenant request will leak one user's token into another's call. Either never share the instance or clone it before setting the token.
  • Redirect URI must be byte-for-byte identical to the console value, including trailing slash and scheme. This is the single most common OAuth failure.
  • Version header. Foursquare v2 expects a v query parameter (date-versioned). The library does not inject one; add it to every call or your responses can change shape without warning.
  • Rate limits are reported in X-RateLimit-Remaining / X-Ratelimit-Reset headers, which this library exposes only if you dig into the raw response. If you need them, subclass the request method and stash headers.
  • API v2 is legacy. Foursquare's current product is the Places API; v2 endpoints still respond for many paths but are effectively frozen. Treat this package as glue for an existing integration, not a foundation for new features. For new work, a ~100-line Laravel HTTP client service with Http::withToken() covers the same surface with retries, fakes, and timeouts for free.
  • Testing. Because the class is concrete and cURL-based, the practical pattern is: your interface in App\Contracts, the real adapter bound in AppServiceProvider, and an in-memory fake bound in tests. Never let a feature test hit the network.
  • Never log the token. Error handlers that dump the request URL will print oauth_token=... in plaintext; scrub oauth_token and client_secret from any Log::debug of request parameters.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin