graham-campbell/parse
Laravel integration for the Parse PHP SDK, letting you use the Parse Platform backend (parse-server) in your Laravel apps. Includes a service provider, facade alias, and publishable config for quickly setting up your Parse application credentials and client.
Architecture fit. The honest framing for planning purposes: this package is not an integration layer, it is a bootstrapper. Its entire surface area is a service provider that calls ParseClient::initialize() once at boot, an optional facade, and a publishable config file. It provides no repository abstraction, no query builder, no error mapping, no schema management, and no multi-connection model. Everything the product actually does — objects, queries, users, files, cloud functions — is the raw parse/php-sdk underneath. That means architectural fit is a function of two things: whether we already operate a self-hosted Parse Server, and whether we accept that the durable integration layer is ours to build and own rather than something we've bought.
Integration feasibility. Low-effort on the happy path. composer require, publish config, wire five .env keys, run a single CRUD smoke test from tinker. This is a days-not-weeks integration for a contained use case, and it is legitimately useful for a time-boxed spike against an existing Parse backend. It is not feasible as platform foundation.
Technical risk.
ParseClient::initialize() runs once at boot with no per-tenant or per-connection model. Runtime config(['parse.*' => ...]) after boot is silently inert. Multi-tenancy is not viable without separate Parse apps or explicit re-initialisation — neither is acceptable for anything user-facing..env, so it can leak into logs, responses, and job payloads. Blast radius is total data access.Parse::user() has no relationship to Auth::user(). Running two identity systems without an explicit decision is a predictable source of defects and support tickets.skip/limit with a server cap around 100, so naive paging over a mutating collection drops and duplicates records.composer update can drag in incompatible Guzzle or parse/php-sdk versions. A Laravel upgrade is a project, not a maintenance chore.Key questions for engineering before we commit.
Stack fit. Check vendor/graham-campbell/parse/composer.json constraints first, before anything else. If the product runs Laravel 10/11 and modern PHP, this bridge likely will not install cleanly, and forking a dead package to gain three files of setup is a bad trade. Given the bridge's tiny surface area, the default recommendation is to skip the bridge and write the equivalent internally — a service provider, a config file, and a repository interface is roughly a day of work and gives us the SDK without the dead dependency.
Migration path. Where we do adopt it, adopt it behind an internal seam on day one. Define a ParseRepository interface, bind it in a service provider, and inject it into controllers and jobs. Never call the facade from a controller. The interface is the exit ramp: it lets us swap the bridge for direct REST calls, a fork, or a different backend without touching product code. Model relationships as native Parse pointers rather than foreign-key strings, and use includeKey to avoid N+1. Keep class names in constants — implicit schema creation punishes typos silently.
Compatibility. Pin both graham-campbell/parse and parse/php-sdk explicitly, and verify Guzzle resolution in CI. Confirm auto-discovery is present in extra.laravel.providers and fall back to manual registration on older stacks. config:cache is safe because the provider reads config at boot; document that runtime overrides are not.
Sequencing.
MockHandler.retry() with backoff on the queue.Maintenance. Effectively ours, permanently. Upstream will not deliver fixes, so we must be prepared to vendor or fork, and a routine dependency bump is a maintenance event rather than a non-event. Practically this needs a named owner, a quarterly review of the pinned versions, and a small standing allocation for patch work. On the positive side, the code we would be maintaining is small: the adapter is a few hundred lines, and the fork burden, if it ever arises, is bounded.
Support. No vendor support and no SLA. Any incident is our on-call, and the runbook needs to state the first diagnostic step explicitly: a ParseConnectionException means the server URL or mount path is wrong before it is ever an API-key problem. The team should expect to debug against parse-community/parse-php-sdk documentation rather than anything this package ships.
Scaling. Every Parse call is an outbound HTTP request, so the integration scales on HTTP volume, not on Laravel's own capacity. Concretely: batch writes at the server's chunk limit (~50 objects), page queries at the server's row cap (~100) ordered by createdAt or objectId for stability, push multi-object and cloud-function work onto a dedicated queue, and use atomic operators — increment, addUnique, add, remove — instead of read-modify-write so concurrent workers do not lose updates. We are also inheriting Parse Server's scaling profile, which is a separate capacity conversation and a separate owner.
Failure modes to design against.
ServiceUnavailableException, and a circuit breaker.objectId.composer update breaking the build — mitigate with pinned versions and lockfile discipline.connect_timeout/timeout and job-level retry().Ramp-up. Superficially fast and therefore deceptive. A developer can get a facade call working in an afternoon and will conclude the integration is trivial, then spend a week discovering that the bridge contributes nothing to the hard parts — ACLs, pointers, batching, pagination, identity, and error semantics. Budget one to two weeks for an engineer to be genuinely productive, and expect most of that time to be spent on Parse Server semantics and the raw SDK rather than on this package. If we are on a modern Laravel stack, add the version-compatibility spike to that estimate up front rather than discovering it mid-sprint.
How can I help you explore Laravel packages today?