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

Outlook Calendar Bundle Laravel Package

fungio/outlook-calendar-bundle

Symfony bundle that connects PHP applications to Microsoft Outlook calendars via the Microsoft Graph API. Manage events, sync schedules, and authenticate users with OAuth 2.0 for clean, reliable access to Office 365 calendar data.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check before you composer require: this is a Symfony 3 bundle, not a Laravel package. It has no service provider, no facade, no publishable config, and its composer.json will pull symfony/framework-bundle:^3.x, symfony/dependency-injection, and symfony/config — none of which coexist cleanly with a modern Laravel install. With 5 stars, 0 dependents, and a 0.235 score, treat it as a reference implementation of the Outlook API surface, not a dependency you install into vendor/.

Where to look first (in the repo):

  1. README.md — for the expected Azure app registration fields (client id, secret, redirect URI) and the advertised service names.
  2. DependencyInjection/Configuration.php and DependencyInjection/*Extension.php — the canonical list of config keys and default service wiring. This is your de facto API documentation.
  3. Resources/config/services.yml — the actual service IDs and class names you'd otherwise resolve from the container.
  4. Any Service/, Api/, or Client/ directory — these are the classes worth extracting.

Minimal path to a first use case:

  1. Register an app in Azure AD (Entra ID) → App registrations → add a Web redirect URI, create a client secret, and grant delegated Calendars.Read (or Calendars.ReadWrite).
  2. In Laravel, install laravel/socialite with a Microsoft/Graph driver (or microsoft/microsoft-graph directly). Do not try to reuse the bundle's Symfony OAuth wiring.
  3. Copy the bundle's HTTP client/response-parsing classes into app/Services/OutlookCalendar/ and replace constructor-injected Symfony services with Laravel contracts.
  4. First use case: read the signed-in user's events for a date window and persist them.
// app/Services/OutlookCalendar/OutlookClient.php (ported)
public function __construct(
    private \Illuminate\Http\Client\Factory $http,
    private string $accessToken,
) {}

public function events(string $startIso, string $endIso): array
{
    return $this->http
        ->withToken($this->accessToken)
        ->get('https://graph.microsoft.com/v1.0/me/calendarView', [
            'startDateTime' => $startIso,
            'endDateTime'   => $endIso,
            '$select'       => 'id,subject,start,end,location,organizer,isAllDay',
            '$top'          => 100,
        ])
        ->throw()
        ->json('value', []);
}
// routes/web.php
Route::get('/outlook/redirect', fn () => Socialite::driver('microsoft')->redirect());
Route::get('/outlook/callback', function () {
    $user = Socialite::driver('microsoft')->user();
    OutlookAccount::updateOrCreate(
        ['user_id' => auth()->id()],
        ['access_token' => encrypt($user->token),
         'refresh_token' => encrypt($user->refreshToken),
         'expires_at' => now()->addSeconds($user->expiresIn)]
    );
    return redirect('/dashboard');
});

Implementation Patterns

Pattern A — Sidecar service (lowest risk, highest ops cost). Stand up a small Symfony 3 app on PHP 7.1/7.4 that actually installs the bundle, expose two or three JSON endpoints (/events, /calendars), and call it from Laravel with Http::baseUrl(...). Only worth it if you need the bundle's exact behavior for parity with an existing system. You inherit Symfony 3's EOL status and a second deployment target.

Pattern B — Extract and adapt (recommended). Pull the API client, DTOs, and response mappers out of the bundle into app/Services/OutlookCalendar/. Replace:

  • Symfony ContainerAware / autowired constructor args → Laravel constructor injection or a ServiceProvider binding.
  • Symfony ParameterBag config → config/outlook-calendar.php + env().
  • Bundle's token storage → an Eloquent model with encrypted columns.

Bind an interface so the rest of the app never sees the port:

// app/Providers/OutlookCalendarServiceProvider.php
$this->app->bind(OutlookCalendar::class, function ($app) {
    return new GraphOutlookCalendar(
        http: $app['Illuminate\Http\Client\Factory'],
        tokens: $app[OutlookTokenStore::class],
    );
});

Token lifecycle as a first-class concern. Store access + refresh tokens per user (encrypted), check expires_at before every call, and refresh in a job rather than inline:

class RefreshOutlookToken implements ShouldQueue
{
    public function handle(OutlookAccount $account): void
    {
        $res = Http::asForm()->post('https://login.microsoftonline.com/common/oauth2/v2.0/token', [
            'grant_type'    => 'refresh_token',
            'client_id'     => config('outlook-calendar.client_id'),
            'client_secret' => config('outlook-calendar.client_secret'),
            'refresh_token' => decrypt($account->refresh_token),
            'scope'         => 'offline_access Calendars.ReadWrite',
        ])->throw()->json();

        $account->update([
            'access_token'  => encrypt($res['access_token']),
            'refresh_token' => encrypt($res['refresh_token'] ?? decrypt($account->refresh_token)),
            'expires_at'    => now()->addSeconds($res['expires_in']),
        ]);
    }
}

Sync pattern. Poll calendarView on a scheduler for a rolling window (e.g. −7 to +60 days) per connected account, upsert into a local calendar_events table keyed on (account_id, outlook_id), and dispatch domain events for downstream features:

Schedule::job(new SyncOutlookCalendars)->everyFifteenMinutes();

Keep a last_synced_at and an outlook_change_token column so you can migrate to Graph delta queries later without a schema change.

Integration tips.

  • Wrap the ported client in a Laravel HTTP middleware for logging, retries (->retry(3, 500)), and metrics.
  • Fake the port in tests ($this->mock(OutlookCalendar::class)) instead of hitting Graph.
  • Normalize responses into your own DTOs immediately; don't leak Graph's start.dateTime / start.timeZone shape into controllers.

Gotchas and Tips

  • Symfony 3 is EOL. Security support ended January 2021. Any code path that runs the bundle as-is is a compliance problem in most orgs. Do not deploy it in production just to save the port.
  • Composer will fight you. The bundle pulls symfony/framework-bundle ^3.x, which conflicts with Laravel's illuminate/* constraints and modern PHP. composer require fungio/outlook-calendar-bundle in a Laravel app is likely to fail or to downgrade unrelated packages. Use composer show --tree on a scratch project to see the damage before trying it in your real app.
  • No config publishing. Symfony Config Tree definitions in DependencyInjection/Configuration.php are not Laravel config files. Any key you find there must be transcribed by hand into config/outlook-calendar.php.
  • Token acquisition is likely delegated. Symfony calendar bundles of this vintage typically expect HWIOAuthBundle (or similar) to supply tokens via a service reference. There is no drop-in equivalent in Laravel — you're rebuilding the OAuth handshake with Socialite or Graph.
  • Endpoint era mismatch. Docs reference "Outlook Calendar REST API"; Microsoft has retired v2 endpoints in favor of Microsoft Graph (graph.microsoft.com/v1.0). If the bundle targets /api/v2.0/me/events, expect deprecation and behavior gaps. Verify the base URL in the client class before assuming the shape.
  • Timezone names. Outlook/Graph can return Windows timezone identifiers ("Romance Standard Time") rather than IANA ("Europe/Paris"). Carbon::parse() will silently misinterpret these. Use the windowsTimezone extension on Graph (Prefer: outlook.timezone="UTC") or map explicitly.
  • Recurring events. Graph returns a series plus exceptions. Naively iterating value will double-count or miss moved occurrences. Use calendarView (which expands recurrence) rather than /events.
  • Pagination. Responses cap at $top and return @odata.nextLink. A loop that ignores it silently truncates busy calendars — a classic "why are half our events missing" bug.
  • Throttling. Graph returns 429 with Retry-After. Respect it; ->retry() without backoff gets you throttled harder.
  • Delta tokens expire with 410 Gone. If you build a delta sync, handle 410 by resetting the token and doing a full resync rather than crashing the scheduler.
  • Permission vs. consent. Calendars.Read delegated permission still needs a user to consent (or tenant admin consent). Local success in a personal tenant frequently fails in an enterprise tenant — test with the customer's actual tenant early.
  • Debugging. Log the raw request URL, headers (redact Authorization), and response body in a dedicated channel. Nine out of ten failures here are redirect-URI mismatch, missing scopes, or an expired refresh token — all invisible without the raw exchange.
  • Extension points. Rather than forking the bundle, decorate: define OutlookCalendar interface → GraphOutlookCalendar adapter → CachingOutlookCalendar decorator. If Microsoft changes something, you patch one class.

Verdict for a Laravel team: use the repository as a specification for the Outlook calendar operations you need, port ~200–400 lines into app/Services/OutlookCalendar/, and build on microsoft/microsoft-graph or Socialite. Do not add it to composer.json.

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.
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
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style