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

Core Laravel Package

jtc-solutions/core

A foundational Laravel package that bundles shared service providers, configuration defaults, helpers, and reusable building blocks for JTC Solutions applications, keeping common logic consistent and cutting boilerplate across projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check before you install. jtc-solutions/core is a zero-star, zero-dependent package whose repository is named core-bundle. Since v1.0 the naming suspicion has been confirmed by the changelog: v1.1.1 fixes an ExceptionListener, forwards translation parameters to a translator, and "upgrades notifications". Those are Symfony concepts — kernel.exception listeners, the Translation component's %param% placeholder convention, and the Notifier component. There is no Laravel equivalent for any of the three. Treat the first 30 minutes as a compatibility audit, not an integration:

composer require jtc-solutions/core

Then, before writing a single line of application code:

  1. Read vendor/jtc-solutions/core/composer.json — expect symfony/* in require and "type": "symfony-bundle". Confirm whether illuminate/* appears at all; if it doesn't, nothing in this package was written with Laravel in mind.
  2. Read the bundle class — Symfony\Component\HttpKernel\Bundle\Bundle is now the overwhelmingly likely base class. Laravel has no Bundle, no Resources/config/services.yaml loader, and no compiler passes. If it's a Bundle, plan for manual wiring.
  3. Inspect the three subsystems the release touches — the ExceptionListener (does it need kernel.exception to fire?), the translator adapter (where do %param% keys come from?), the notifications (Notifier channels need transports configured). Each is dead code in Laravel unless you bridge it.
  4. Check the published config — php artisan vendor:publish --provider="JTC\Core\..." (confirm the FQCN from source; do not guess). A Symfony bundle ships DependencyInjection/Configuration.php, not a Laravel config file, so nothing may publish at all.

First use case. Given v1.1.1 is a patch release that contains a Features section, the most valuable first experiment is not "does it work" but "how loose is the versioning". Run the audit against the package's own tests before touching your container:

vendor/bin/phpunit -c vendor/jtc-solutions/core/phpunit.xml.dist 2>/dev/null \
  || echo "no runnable suite — you are the QA"

If the suite exists and passes, you have a baseline to detect regressions on v1.1.2. If it doesn't, you are validating a single-maintainer Symfony bundle by hand, in a framework it does not target.

Where to look first. PR numbers #8 and #9 mean the entire history is under a dozen pull requests. The vendor source is not just the documentation — it is small enough to read end-to-end in an afternoon. Do that before adopting, not after.

Implementation Patterns

Because the release confirms the package is Symfony-native and pre-1.2, every pattern below is about containment. The wrapper indirection is not a nicety here — the translator and notifier surfaces you'd actually want are the two most framework-divergent parts of Symfony.

Wrap it behind your own interface. Never let JTC\Core\* types leak into controllers, jobs, or Blade:

// app/Contracts/CoreGateway.php
interface CoreGateway
{
    public function translate(string $id, array $params = []): string;
    public function notify(string $channel, string $recipient, string $message): void;
}

// app/Services/JtcCoreGateway.php
final class JtcCoreGateway implements CoreGateway
{
    public function __construct(
        private readonly \JTC\Core\Translation\TranslatorInterface $translator,
        private readonly \JTC\Core\Notification\NotifierInterface $notifier,
    ) {}

    // Symfony uses %name% placeholders; Laravel uses :name. Convert at the seam, once.
    public function translate(string $id, array $params = []): string
    {
        $params = array_combine(
            array_map(fn ($k) => "%{$k}%", array_keys($params)),
            array_values($params)
        );

        return $this->translator->trans($id, $params);
    }

    public function notify(string $channel, string $recipient, string $message): void
    {
        $this->notifier->getChannel($channel)->notify($recipient, $message);
    }
}
// app/Providers/AppServiceProvider.php
public function register(): void
{
    $this->app->singleton(\JTC\Core\Translation\TranslatorInterface::class, fn () =>
        new \JTC\Core\Translation\Translator(config('jtc_core.locale', 'en'), config('jtc_core.fallback', 'en'))
    );

    $this->app->singleton(CoreGateway::class, JtcCoreGateway::class);
}

This indirection turns "replace the package" into a one-file change. With a bundle that expects a Symfony kernel, that is still the most important decision you will make.

Own the translation layer entirely, if you can. The v1.1.1 fixes (forwarding parameters, and auto-wrapping bare keys with %) are the two most obvious bugs in a hand-rolled adapter. If your app already uses __('messages.hello', ['name' => 'Ada']), run Laravel's translator and use the package's translator only if it stores translations you cannot extract. Duplicating translation infrastructure is a classic way to ship a page in two languages at once.

Do not confuse its notifications with Laravel's. Upgraded notifications (#8) almost certainly means Symfony Notifier channels, not Illuminate\Notifications. Do not attempt Notification::send() against it, and do not let a package notifier write to your notifications table. If you need app notifications, use Laravel's built-in system and let the package own only what it already owns.

Constructor injection only. Symfony bundles lean on tagged services and constructor injection; the classes you resolve may be fine, but any static facade or global helper is the first thing to break on a version bump. Inject the underlying instance.

Configuration via config/ plus env, never via package internals. The bundle's DependencyInjection/Configuration.php will not be loaded by Laravel, so its defaults do not apply. Define config/jtc_core.php yourself and pass values explicitly when constructing the package objects in your provider. Do not mutate package properties at runtime from controllers.

Test double at the seam. With your own interface in place, tests never touch the package:

$this->mock(CoreGateway::class, fn ($m) => $m
    ->shouldReceive('translate')->with('greeting', ['name' => 'Ada'])->andReturn('Hello, Ada'));

Pin exactly, not approximately. v1.1.1 is a patch that contains new features and a behaviour change (auto-wrapping parameter keys). That is not semver. Use "jtc-solutions/core": "1.1.1" with no range, commit composer.lock, and treat every bump as a reviewed change with a diff read. ~1.1 is already too permissive for this package's release discipline.

Gotchas and Tips

Pitfalls

  • Symfony baggage, now confirmed. core-bundle plus an ExceptionListener plus a translator plus a notifier means you are pulling Symfony DI and possibly FrameworkBundle. Laravel's container will autowire simple classes, but tagged services, compiler passes, Bundle::boot(), and the kernel.exception event do not exist. ExceptionListener will simply never be invoked unless you register it against Laravel's exception handler yourself.
  • Translation placeholder mismatch. The package uses %key%. Laravel's translator uses :key. Passing Laravel-style params through unchanged yields raw placeholder strings in production, and because these placeholders render as literal text there is no exception to catch. Test both a plain and a parameterised string on first integration.
  • The %-auto-wrap fix is a silent behaviour change in a patch release. If you were already passing pre-wrapped %name% params, v1.1.1 may double-wrap them. Re-test any caller that built placeholders itself.
  • No documented Laravel support. Auto-discovery (extra.laravel.providers) is almost certainly absent from a Symfony bundle. If php artisan package:discover doesn't list it, register manually.
  • Notification transports. The #8 notification upgrade implies transports (mailer, chat, SMS) that need DSNs. An unconfigured Symfony Notifier channel typically throws only when first used, so a smoke test on boot will not catch a broken prod config.
  • Empty issue tracker = no known bugs, not no bugs. With under ten PRs total, your team is the QA function. Write characterization tests against real behaviour before building on it.
  • Facade/alias collisions. Core packages register aggressively generic aliases. Check config/app.php aliases for "class not found" or silent wrong resolution.
  • PHP version drift. Verify the php constraint against your deployment image, especially if prod lags CI.

Debugging

  • php artisan about shows discovered packages and the Laravel version the provider booted against — a quick way to confirm the provider is even loaded.
  • dump(app()->getLoadedProviders()) when something silently does nothing; check the provider isn't deferred.
  • For container resolution failures, app()->make() with a stack trace beats the package's own error handling.
  • Because ExceptionListener will not fire under Laravel, exception-path behaviour is untested in your app by default. Deliberately throw from a wired call once and confirm the output is what you expect.
  • Watch storage/logs/laravel.log during first invocation — the translator/notifier path often logs at debug.

Config quirks

  • Published config is merged shallowly; nested arrays are replaced, not deep-merged. Copy the full published array and edit within it.
  • php artisan config:cache surfaces any env() calls made outside config/ as null. The single most common "works locally, broken in prod" failure for third-party cores, and more likely here because the package never targeted Laravel's config cache in the first place.

Extension points to look for

  • The translator and notifier interfaces the bundle binds — swap the container binding rather than subclassing.
  • The ExceptionListener itself: if you want its behaviour, register an equivalent against Laravel's exception handling ($exceptions->render(...) in bootstrap/app.php) rather than bridging Symfony's dispatcher for this.
  • Any *Manager or *Factory class — usually the correct place to substitute your own concrete implementation in the container.

On v1.1.1 specifically. This release does not change the adoption calculation. It does confirm the framework mismatch (Symfony listener, Symfony translator, Symfony notifier) and reveals loose versioning (features inside a patch, two bug fixes in the same PR, a duplicated changelog link suggesting the release process is manual). If you are pinned to an earlier 1.1.x, read the #9 diff before upgrading: the delimiter auto-wrap can alter output for existing callers. Nothing here adds a Laravel path, a config publish, or service-provider discovery.

The honest recommendation. Unchanged from the prior assessment, and now better evidenced: adopt only if (a) it is an internal or vendor-mandated dependency, or (b) you have read the source — which is under a dozen PRs of code — and are willing to fork it. The v1.1.1 changes are the kind of work you'd rather own: a translator with % delimiters and a notifier shim are each a small app/Support/ module. If you do adopt, the interface-wrapper pattern above is non-negotiable, and pin to an exact version.

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.
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings