graham-campbell/core
Core functionality for Laravel and PHP packages by Graham Campbell. Provides reusable base service providers, helpers, and bootstrapping utilities that other packages build on, keeping setup consistent, minimal, and lightweight across the ecosystem.
Architecture fit. graham-campbell/core is not an application dependency — it is an abstract ServiceProvider plus a handful of convention helpers (config merge/publish, view/translation namespacing, migration and route loading, command registration, bindings, aliases) that predate Laravel 5.5 auto-discovery. Every hook it standardizes is now native (mergeConfigFrom, loadViewsFrom, loadTranslationsFrom, loadMigrationsFrom, loadRoutesFrom, publishes, commands). Its architecture is therefore a reference pattern, not a layer to adopt: it fits legacy Laravel 5.0–5.4 codebases and fits nothing current. A TPM's first move is framing it correctly — it is a risk line item and a modernization sequencing input, never a deliverable on a roadmap.
Integration feasibility. There is no adoption path; feasibility is entirely about removal. Establish the relationship first (composer why graham-campbell/core, composer show graham-campbell/core) and triage into three outcomes: absent (reference only), transitive (a real package such as Flysystem/Security/Messenger pulls it in — you remove it by upgrading or replacing that dependent), or direct (grep GrahamCampbell\\Core to find the wiring). Removal feasibility is high: the port is mechanical, and a timeboxed spike on one concrete subclass typically converts a vague "legacy risk" into an hours-not-days estimate.
Technical risk. The hard blocker is the PHP floor (5.5–7.x) and Laravel 5.0–5.8 pin — Composer refuses at install on modern PHP, so every install carrying it is effectively frozen on an unsupported runtime with no CVE process. Secondary risks: the storage-link helper has a demonstrated regression history (v5.3.2 exists because v5.3.x's fix didn't fix it); the mergeConfigFrom-must-run-in-register() ordering footgun regresses frequently in hand-rolled replacements (symptom: "config missing in a service constructor" at startup); publish-tag collisions where the package name was used as the tag; and boot failures that surface inside the abstract class with no frame pointing at the caller's package. Zero stars, zero dependents, archived under GrahamDeprecated, no support channel — when it breaks, you own it.
Key questions. Is the dependency transitive or direct (different reviewers, tests, and rollback plans). Which concrete providers say extends AbstractServiceProvider, and do any override register()/boot() (that is the behavior that must be reproduced, not just the property values). What Laravel/PHP version is the host app on, and is a framework upgrade already in flight. Who owns the dependent packages, and does a concrete subclassing need actually survive audit.
Stack fit. Poor for anything modern by construction; relevant only to a legacy Laravel 5.0–5.4 app that still boots on PHP 5.5–7.x. The correct treatment is delete or vendor, never "keep it alive" — a fork is strictly worse than both, inheriting maintenance and CVE triage in exchange for saving a few hundred lines.
Migration path. Port each abstract hook to its native call: mergeConfigFrom in register() (config must exist before dependents boot); views, translations, migrations, routes, commands in boot(); bindings/singletons/aliases via plain $this->app->bind/singleton/alias() in register(). Replace the manual config/app.php provider ritual with composer.json extra.laravel.providers auto-discovery — do not write a registrar that reproduces the retired list. Move the storage-link helper out of boot() and into the deploy script (php artisan storage:link). If an internal package fleet needs the convention layer, vendor a ~30-line BootsPackage trait under your own namespace rather than copying the base class.
Compatibility. The "framework-version agnostic" claim is marketing against Illuminate constraints — it is PHP/Laravel-version-bound in practice, and pinning illuminate/* to a 5.x branch will not help if CI runs PHP 8.x. Reproduce legacy environments in a container (php:7.1-cli) rather than fighting the local toolchain.
Sequencing. Fold removal into a framework upgrade that is already being scoped — removal folded into an upgrade you were already paying for is nearly free; a standalone removal ticket incurs a review cycle, regression window, and rollback plan for a package that ships no user-visible behavior. Sequence: composer why → read the concrete subclass → translation table → boot check (route:list, queue:work --stop-when-empty, schedule:list) → roll across remaining subclasses. Snapshot composer.lock before touching any constraint so a transitive float that fails hard can be bisected.
Maintenance. Effectively zero upstream — archived, deprecated, zero stars, zero dependents. The code is small enough to read in vendor/graham-campbell/core/src/, but small is not the same as supported: any code path depending on it is "we own it now," which favors inlining over depending. The correct endpoints are delete or vendor thirty lines, not maintain.
Support. No issue tracker history for your stack trace, no maintainer to ping, no peer troubleshooting, no CVE process. Plan for self-service: read the source, reproduce in a scratch Laravel 5.x app, and write findings to /docs/legacy/. Do not budget "waiting on upstream" — it is not coming.
Scaling. Irrelevant to runtime scaling, but a genuine drag on delivery velocity and upgrade scope at portfolio scale: it recalibrates forecasts for upgrade effort, security review, and maintenance cost on every codebase that carries it. Tag collisions compound at fleet scale — audit publishes() tags and namespace replacements (x-config, x-migrations).
Failure modes. (1) Composer resolution failure on PHP 8 — hard stop at install. (2) Storage-link regression on clean environments — verify symlink creation before and after any bump. (3) Config-missing-in-constructor ordering regressions when mergeConfigFrom lands in boot(). (4) Silent boot failures inside the abstract class — temporarily final the concrete provider and wrap parent::boot() in try/catch to name the failure. (5) Transitive float failures that only surface after a lock bump — bisect against the snapshot.
Ramp-up. Low — the codebase is a few hundred lines and reads quickly. The ramp is not learning the package; it is learning that you must not reintroduce it. Use it as a reference anti-pattern in code review and internal package standards: native Illuminate\Support\ServiceProvider methods plus extra.laravel.providers are the house standard, and this package demonstrates exactly the convention layer new internal packages must not recreate.
How can I help you explore Laravel packages today?